[
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2017-2018\n  Andreia Correia <andreia.veiga@unine.ch>\n  Pedro Ramalhete <pramalhe@gmail.com>\n  Pascal Felber <pascal.felber@unine.ch>\n  Nachshon Cohen <nachshonc@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "\n# OneFile PTM / STM\n\nOneFile is a Software Transactional Memory (STM) meant to make it easy to implement lock-free and wait-free data structures.\nIt is based on the paper \"[OneFile: A Wait-free Persistent Transactional Memory](https://github.com/pramalhe/OneFile/blob/master/OneFile-2019.pdf)\" by Ramalhete, Correia, Felber and Cohen\nhttps://github.com/pramalhe/OneFile/blob/master/OneFile-2019.pdf\n\nIt provides multi-word atomic updates on *tmtype<T>* objects, where T must be word-size, typically a pointer or integer.\nDuring a transaction, each store on an *tmtpye<T>* is transformed into a double-word-compare-and-swap DCAS() and one more regular CAS() is done to complete the transaction. It does this with a store-log (write-set) which other writers can help apply. \nThis is a \"redo-log\" based technique, which means that both store and loads need to be interposed. Stores will be interposed to save them in the log and loads will be interposed to lookup on the log the most recent value.\nIf there is a transaction currently ongoing, the readers will have to check on each *tmtype::pload()* if the variable we're tying to read is part of the current transaction. If a value is read whose 'seq' is higher than the transaction we initially read, the whole read-only operation will be restarted, by throwing an exception in the *tmtype::pload()* interposing method and catching this exception by the TM. All of this logic is handled internally by OF without any explicit user interaction.\n\nBecause of operator overloading, the assignment and reading of *tmtype<T>* types is done transparently to the user, with a pure library implementation, without any need for compiler instrumentation. This means that the user can write the code as if it was a sequential implementation of the data structure, apart from the change of types (type annotation). In this sense, OneFile is a \"quasi-universal construction\" with lock-free progress.\n\nOur design goal with OneFile was to provide a non-blocking STM so that non-experts could implement their own lock-free and wait-free data structures.\nOneFile is not designed to transform regular everyday code into lock-free applications. Such use-cases require a lot more of engineering work and likely a completely different approach from what we took with OneFile (CX is a much better option for that purpose).\n\nWe've made two implementations in the form of Persistent Transactional Memory (PTM) which are STMs meant for Persistent Memory, like Intel's Optane DC Persistent Memory.\n\nWe've implemented four diferent variants of this design:\n- OneFile-LF: The simplest of the four, has lock-free progress and lock-free memory reclamation using Hazard Eras;\n- OneFile-WF: Uses aggregation (like flat-combining) and a new wait-free consensus to provide wait-free bounded progress. Has wait-free bounded memory reclamation;\n- POneFile-LF: A PTM with durable transactions (ACID) and lock-free progress. Memory reclamation is lock-free using an optimistic technique. Allocation and de-allocation of user objects is lock-free;\n- POnefile-WF: A PTM with durable transactions (ACID) and wait-free progress. Memory reclamation for user objects is wait-free using an optimistic technique, while memory reclamation of the transactional objects is done using Hazard Eras, also wait-free. Allocation and de-allocation of user-objects is wait-free;\n\nSee the respective .hpp files for implementation details.\n\nEach implementation is a single header file. Yes, it's that small  :)\n\n\n## Quickstart ##\n\nIf you just want to use OneFile in your own application or benchmarks then follow these steps:\n- Choose one of the four OneFile implementations, depending on whether you want and STM, a PTM, lock-free or wait-free progress:  \n  [stms/OneFileLF.hpp](https://github.com/pramalhe/OneFile/blob/master/stms/OneFileLF.hpp)      STM with lock-free transactions  \n  [stms/OneFileWF.hpp](https://github.com/pramalhe/OneFile/blob/master/stms/OneFileWF.hpp)      STM with wait-free transactions  \n  [ptms/POneFileLF.hpp](https://github.com/pramalhe/OneFile/blob/master/ptms/OneFilePTMLF.hpp)     PTM with lock-free transactions  \n  [ptms/POneFileWF.hpp](https://github.com/pramalhe/OneFile/blob/master/ptms/OneFilePTMWF.hpp)     PTM with wait-free transactions  \n- Copy the header to your development folder\n- Include the header from a single .cpp. If you include from multiple compilation units (.cpp files) then move the last block in the .hpp to one of the .cpp files.\n- If you want a data structure that is already made then take a look at what's on these folders:\n\n\tdatastructures/         Data structures for volatile memory (needs one of the STMs)\n\tpdatastructures/        Data structures for persistent memory (needs one of the PTMs)\n\n\n### Design ###\n\nIn OneFile STM a transaction goes through three phases. \nThe first phase is to convert the operation (lambda) into a store-log (write-set). There is no need to save the loads (read-set) because unlike other approaches, a transaction does not need to re-check for changes at commit time: it does a check in-flight on each load of whether or not the value has changed since the beginning of the transaction, by looking at a sequence number associated with every read value, a technique similar to TL2 or TinySTM but without the need for keeping a read-set because all write transactions are executed one at a time, effectively serialized.\nThe second phase is to commit the transaction by advancing the current transaction (curTx).\nThe third phase is to apply the store-log using DCAS.\n\nThe first phase is implicitly serializable. Even if each thread publishes its operation, there is no way to parallelize this work among threads. The best that could be done would be that each thread to transform its own operation into its own store-log which it then appends to a global store-log. Unfortunately this is possible only for disjoint-access parallel transactions, and these are not easy to detect, therefore, our implementation of OneFile does not do this.\nInstead, we attempt to parallelize the second stage, where the store-log is applied. This task is easier to split among multiple threads, thus parallelizing it.\nAdding Flat-Combining or other similar aggregation techniques to the first stage, means that each thread will produce a store-log containing the operations of all other threads. This can be a bottleneck if the operations involves heavy computations and small store-logs. For data structures, this is not the case, and OneFile is designed to implement and work with data structures or other scenarios where the transactions are short in time, therefore, we found it acceptable to go with such an approach.\n\nThe parallelization of the third phase can be done with at least two different approaches: blocking and non-blocking.\nIn the blocking approach, the store-log can be divided into chunks (for example, one chunk per thread), each chunk having a lock, and the thread that takes the lock is responsible for applying that chunk.\nIn the non-blocking approach (OF-LF and OF-WF), each thread tries to apply an entry of the store-log at a time. To avoid ABA issues, a double-word compare-and-swap (DCAS) must be used.\n\nIn summary, OneFile does *not* do disjoint-access parallel transactions. If you absolutely need that functionality, then go and take a look at TinySTM. \n\n\n\n## Requirements ##\n\n- OneFile needs a double-word CAS, which limits it to x86. The algorithm can be modified to use LL/SC or even single-word CAS at the cost of losing its generic capability because bits would have to be stolen from a 64 bit wordl\n- The user must \"instrument\" the code where the atomic updates take place by wrapping the types with *tmtype<T>*. Even then, the operator overloading will not cover all the cases and there will be situations where the user has to annotate the code with .pload() or .pstore() respectively;\n- The *T* type must be the size of a word, i.e. 64 bits. Anything bigger and it needs to be splitted into multiple *tmtype<T>* objects;\n- If memory reclamation is needed, then the objects need to derive from the *tmbase* base class, need to be allocated with *tmNew()* or *tmMalloc()* and deallocated with *tmDelete()* or *tmFree()*;\n\n\n\n## Memory Reclamation ##\n\nWe're using a customized implementation of Hazard Eras, lock-free/wait-free memory reclamation:  \n[https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf](https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf)  \n[https://dl.acm.org/citation.cfm?id=3087588](https://dl.acm.org/citation.cfm?id=3087588)  \nSee the HazardErasOF class in each implementation for more details.  \n\nAs far as we know, there is only one wait-free data structure that has integrated wait-free memory reclamation:  \n[https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/crturnqueue-2016.pdf]([https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/crturnqueue-2016.pdf)  \nOneFile and CX are the first time that someone has made a generic mechanism for wait-free memory reclamation.\n\n\n\n## How to use this ##\n\n1. Annotate all the objects that are shared among threads, namely, everything that is *std::atomic<T>* should be changed to *tmtype<T>*;\n2. Use only *pstore()* and *pload()* (or just use '='). Do *not* call compare_exchange_strong(), exchange() or fetch_add();\n3. Replace calls to \"obj = new T(args)\" with \"obj = tmNew<T>(args)\";\n4. Replace calls to \"delete obj\" with \"tmDelete<T>(obj)\";\n5. The T types must derive from the base class *tmbase*;\n6. Place your methods in a lambda, capturing whatever you need, and pass the lambda to *updateTx()*;\nThat's it, you've now got your own lock-free data structure!\nFor an example of a simple linked-list set, take a look datastructures/linkedlists/OFLFLinkedListSet.hpp\n\n\n## Disadvantages ##\n\n- All mutative operations are serialized;\n- Types must be broken down to 64 bit sizes;\n- Requires Double-word-compare-and-swap (DCAS);\n\n\n## Advantages ##\n\n- Lock-free programming was never so easy, all the user code has to do is loads and stores on *tmtypes<T>* types and those get transformed into a DCAS() based transaction that provides correct linearizable lock-free progress, without ABA issues;\n- Memory reclamation is also handled by OF using Hazard Eras, a lock-free/wait-free memory reclamation technique;\n- Compared to hand-written lock-free data structures, on the uncontended case, we are replacing each CAS with a DCAS and adding one extra (regular) CAS on the currTrans, which is a small price to pay for the atomicity;\n- This technique provides full linearizability for generic code, even mutative iterators, something which is nearly impossible to do with hand-written lock-free data structures;\n- Multiple helping threads can help apply starting on different places. A good heuristic is to start from the (tid % numStores);\n- OneFile-WF is the first STM with wait-free bounded progress and it's the first to have wait-free bounded progress with wait-free bounded memory reclamation.\n- Read-only transactions are lightweight and they can run concurrently with write transactions as long as they're disjoint;\n\nThe biggest advantage of all is that it's way easier to use OneFile than it is to implement a hand-made lock-free or wait-free data structure.\n\n\n\n## Examples ##\n\nThere are some working examples in the \"datastructures/\" folder:\nOFLFBoundedQueue.hpp:     An array based queue (memory-bounded) \nOFLFLinkedListQueue.hpp:  A linked list based queue (memory unbounded) \nOFLFLinkedListSet.hpp:    A linked list based set \nOFLFRedBlackBST.hpp:      A Red-Black (balanced) tree map  \n\n\n\n## Benchmarks ##\nTo build the benchmarks you need to build ESTM and TinySTM, and then you need to pull PMDK (PMEM/NVML) and build it:\n\n    cd ~/onefile/stms/\n    cd estm-0.3.0\n    make clean ; make\n    cd ..\n    cd tinystm\n    make clean ; make\n    cd ..\n    cd ~\n    git clone https://github.com/pmem/pmdk.git\n    cd pmdk\n    make -j12\n    sudo make install\n    export PMEM_IS_PMEM_FORCE=1\n    cd ~/onefile/graphs\n    make -j12\n    \n\n## Tests ##\nThe four implementations of OneFile were executed during thousands of cpu hours and heavily stress tested with invariant checking and using tools like address sanitizer and valgrind. This is a lot more than what other STMs on github provide, but it doesn't mean there are no bugs in it  ;)\nIf you see a crash or invariant failure, run the same code under a global rw-lock to make sure the bug is not in your code. If you really believe it's in OneFile, then please open a bug on github and add as much information as you can, namely, stack trace and files needed to reproduce. \nWe'll do our best to address it.\n\n \n"
  },
  {
    "path": "common/HazardEras.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2016-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_ERAS_H_\r\n#define _HAZARD_ERAS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <vector>\r\n#include <algorithm>\r\n\r\n/*\r\n * <h1> Hazard Eras </h1>\r\n * This a light-weight implementation of hazard eras, where each thread has a\r\n * thread-local list of retired objects.\r\n *\r\n * This is based on the paper \"Hazard Eras - Non-Blocking Memory Reclamation\"\r\n * by Pedro Ramalhete and Andreia Correia:\r\n * github...\r\n *\r\n * The type T is for the objects/nodes and it's expected to have the following members:\r\n * newEra, delEra, delNext.\r\n *\r\n * R is zero.\r\n *\r\n * <p>\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass HazardEras {\r\n\r\nprivate:\r\n    static const uint64_t NONE = 0;\r\n    static const int      HE_MAX_THREADS = 128;\r\n    static const int      MAX_HES = 5;        // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HE_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n\r\n    const int             maxHEs;\r\n    const int             maxThreads;\r\n\r\n    alignas(128) std::atomic<uint64_t>  eraClock {1};\r\n    alignas(128) std::atomic<uint64_t>* he[HE_MAX_THREADS];\r\n    alignas(128) std::vector<T*>        retiredList[HE_MAX_THREADS*CLPAD];  // It's not nice that we have a lot of empty vectors\r\n\r\npublic:\r\n    HazardEras(int maxHEs=MAX_HES, int maxThreads=HE_MAX_THREADS) : maxHEs{maxHEs}, maxThreads{maxThreads} {\r\n        for (int it = 0; it < HE_MAX_THREADS; it++) {\r\n            he[it] = new std::atomic<uint64_t>[CLPAD*2]; // We allocate four cache lines to allow for many hps and without false sharing\r\n            retiredList[it*CLPAD].reserve(maxThreads*maxHEs);\r\n            for (int ihe = 0; ihe < MAX_HES; ihe++) {\r\n                he[it][ihe].store(NONE, std::memory_order_relaxed);\r\n            }\r\n        }\r\n        static_assert(std::is_same<decltype(T::newEra), uint64_t>::value, \"T::newEra must be uint64_t\");\r\n        static_assert(std::is_same<decltype(T::delEra), uint64_t>::value, \"T::delEra must be uint64_t\");\r\n    }\r\n\r\n    ~HazardEras() {\r\n        for (int it = 0; it < HE_MAX_THREADS; it++) {\r\n            delete[] he[it];\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[it*CLPAD].size(); iret++) {\r\n                delete retiredList[it*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    inline uint64_t getEra() {\r\n        return eraClock.load();\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHEs)\r\n     */\r\n    inline void clear(const int tid) {\r\n        for (int ihe = 0; ihe < maxHEs; ihe++) {\r\n            he[tid][ihe].store(NONE, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    inline T* get_protected(int index, const std::atomic<T*>& atom, const int tid) {\r\n        auto prevEra = he[tid][index].load(std::memory_order_relaxed);\r\n\t\twhile (true) {\r\n\t\t    T* ptr = atom.load();\r\n\t\t    auto era = eraClock.load(std::memory_order_acquire);\r\n\t\t    if (era == prevEra) return ptr;\r\n            he[tid][index].store(era);\r\n            prevEra = era;\r\n\t\t}\r\n    }\r\n\r\n    inline void protectEraRelease(int index, int other, const int tid) {\r\n        auto era = he[tid][other].load(std::memory_order_relaxed);\r\n        if (he[tid][index].load(std::memory_order_relaxed) == era) return;\r\n        he[tid][index].store(era, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /*\r\n     * Does a single iteration. Must be integrated into the algorithm that's using HE.\r\n     * In other words, we must re-check if era has changed\r\n     *\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    inline T* protectPtr(int index, const std::atomic<T*>& atom, uint64_t& prevEra, const int tid) {\r\n        T* ptr = atom.load(std::memory_order_acquire);\r\n        auto era = eraClock.load();\r\n        if (prevEra != era) {\r\n            prevEra = era;\r\n            he[tid][index].store(era, std::memory_order_relaxed);\r\n            std::atomic_thread_fence(std::memory_order_seq_cst);\r\n        }\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * Retire an object (node)\r\n     * Progress Condition: wait-free bounded\r\n     */\r\n    void retire(T* ptr, const int mytid) {\r\n        auto currEra = eraClock.load();\r\n        ptr->delEra = currEra;\r\n        auto& rlist = retiredList[mytid*CLPAD];\r\n        rlist.push_back(ptr);\r\n        if (eraClock == currEra) eraClock.fetch_add(1);\r\n        for (unsigned iret = 0; iret < rlist.size();) {\r\n            auto obj = rlist[iret];\r\n            if (canDelete(obj, mytid)) {\r\n                rlist.erase(rlist.begin() + iret);\r\n                delete obj;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n\r\nprivate:\r\n    bool canDelete(T* obj, const int mytid) {\r\n        for (int tid = 0; tid < maxThreads; tid++) {\r\n            for (int ihe = 0; ihe < maxHEs; ihe++) {\r\n                const auto era = he[tid][ihe].load(std::memory_order_acquire);\r\n                if (era == NONE || era < obj->newEra || era > obj->delEra) continue;\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n};\r\n\r\n#endif /* _HAZARD_ERAS_H_ */\r\n"
  },
  {
    "path": "common/HazardPointers.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_POINTERS_H_\r\n#define _HAZARD_POINTERS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n\r\n\r\n\r\n/**\r\n * This is a customized version of Hazard Pointers to be used with CXMutation\r\n */\r\n// TODO: use std::vector instead of arrays for the retired objects (keep the padding)\r\ntemplate<typename T>\r\nclass HazardPointers {\r\n\r\nprivate:\r\n    static const int      MAX_THREADS = 128;\r\n    static const int      MAX_HPS = 5;\r\n    static const int      MAX_RETIRED = MAX_THREADS*MAX_HPS;\r\n    static const int      HP_THRESHOLD_R = 0;  // This is named 'R' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    const int             maxHPs;\r\n    const int             maxThreads;\r\n    alignas(128) std::atomic<T*>*      hp[MAX_THREADS*CLPAD];\r\n    alignas(128) T**                   retiredObjects[MAX_THREADS*CLPAD];  // List of retired nodes that need to be 'deleted' for the current thread\r\n    alignas(128) long                  numRetiredObjects[MAX_THREADS*CLPAD];       // Number of nodes in the retired list\r\n    // Used specifically for CXMutation\r\n    alignas(128) std::atomic<T*>       heads[2*MAX_THREADS*CLPAD];\r\n\r\npublic:\r\n    HazardPointers(int maxHPs=MAX_HPS, int maxThreads=MAX_THREADS) : maxHPs{maxHPs}, maxThreads{maxThreads} {\r\n        for (int ih = 0; ih < 2*MAX_THREADS; ih++) {\r\n            heads[ih*CLPAD].store(nullptr, std::memory_order_relaxed);\r\n        }\r\n        for (int ithread = 0; ithread < MAX_THREADS; ithread++) {\r\n        \tnumRetiredObjects[ithread*CLPAD] = 0;\r\n            hp[ithread*CLPAD] = new std::atomic<T*>[MAX_HPS];\r\n            for (int ihp = 0; ihp < MAX_HPS; ihp++) {\r\n                hp[ithread*CLPAD][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n            retiredObjects[ithread*CLPAD] = new T*[MAX_RETIRED];\r\n            for (int iret = 0; iret < MAX_RETIRED; iret++) {\r\n                retiredObjects[ithread*CLPAD][iret] = nullptr;\r\n            }\r\n        }\r\n    }\r\n\r\n    ~HazardPointers() {\r\n        for (int ithread = 0; ithread < MAX_THREADS; ithread++) {\r\n            // Clear the current retired nodes\r\n            for (int iret = 0; iret < numRetiredObjects[ithread*CLPAD]; iret++) {\r\n                delete (T*)retiredObjects[ithread*CLPAD][iret];\r\n            }\r\n            delete[] hp[ithread*CLPAD];\r\n            delete[] retiredObjects[ithread*CLPAD];\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHPs)\r\n     *\r\n     * It's ok to use relaxed loads here because:\r\n     * - For progress: we know that the store will eventually become visible,\r\n     *   or another publish() will take its place;\r\n     * - For correctness: it can be re-ordered below, but at most it will protect\r\n     *   an object for longer than required, i.e. until the next publish overwrites it.\r\n     *   Or it gets re-ordered above, but only up to a seq-cst store on the same\r\n     *   variable in publish(), which _must_ be it, even if the store in the publish\r\n     *   is a release store (which is the case for publishRelease()).\r\n     */\r\n    void clear(const int tid) {\r\n        for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n            hp[tid*CLPAD][ihp].store(nullptr, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    void clearOne(int ihp, const int tid) {\r\n        hp[tid*CLPAD][ihp].store(nullptr,std::memory_order_relaxed);\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* protect(int index, const std::atomic<T*>& atom, const int tid) {\r\n        T* n = nullptr;\r\n        T* ret;\r\n\t\twhile ((ret = atom.load()) != n) {\r\n\t\t\thp[tid*CLPAD][index].store(ret);\r\n\t\t\tn = ret;\r\n\t\t}\r\n\t\treturn ret;\r\n    }\r\n\r\n    inline T* get_protected(int index, const std::atomic<T*>& atom, const int tid) {\r\n        return protect(index, atom, tid);\r\n    }\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtr(int index, T* ptr, const int tid) {\r\n        hp[tid*CLPAD][index].store(ptr);\r\n        return ptr;\r\n    }\r\n\r\n    /**\r\n     * This assumes that the ptr lhead is already protected by a \"regular\" hazard pointers\r\n     */\r\n    void protectHead(int combinedIndex, T* lhead) {\r\n        heads[combinedIndex*CLPAD].store(lhead, std::memory_order_release);\r\n    }\r\n\r\n    std::atomic<T*>* getHeads() {\r\n        return heads;\r\n    }\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectRelease(int index, T* ptr, const int tid) {\r\n        hp[tid*CLPAD][index].store(ptr, std::memory_order_release);\r\n        return ptr;\r\n    }\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free bounded (by the number of threads squared)\r\n     */\r\n    void retire(T* ptr, const int tid) {\r\n        if (numRetiredObjects[tid*CLPAD] >= HP_THRESHOLD_R) scanAndDelete(tid);\r\n        retiredObjects[tid*CLPAD][numRetiredObjects[tid*CLPAD]++] = ptr;\r\n    }\r\n\r\n\r\n    void copyPtr(int index, int other, const int tid) {\r\n        auto ptr = hp[tid*CLPAD][other].load(std::memory_order_relaxed);\r\n        hp[tid*CLPAD][index].store(ptr, std::memory_order_release);\r\n    }\r\n\r\n\r\nprivate:\r\n    void scanAndDelete(const int tid) {\r\n        for (int iret = 0; iret < numRetiredObjects[tid*CLPAD]; ) {\r\n            bool ptrInUse = false;\r\n            auto ptr = (T*)retiredObjects[tid*CLPAD][iret];\r\n            for (int it = 0; it < maxThreads; it++) {\r\n                for (int ihp = maxHPs-1; ihp >= 0; ihp--) {\r\n                    if (ptr == hp[it*CLPAD][ihp].load()) ptrInUse = true;\r\n                }\r\n            }\r\n            if (ptrInUse) { iret++; continue; }\r\n            // Scan the array of heads before deleting the pointer\r\n            for (int icomb = 0; icomb < 2*MAX_THREADS; icomb++) {\r\n                if (ptr == heads[icomb*CLPAD].load()) ptrInUse = true;\r\n            }\r\n            if (ptrInUse) { iret++; continue;  }\r\n            for (int i = iret; i < numRetiredObjects[tid*CLPAD]-1; i++) retiredObjects[tid*CLPAD][i] = retiredObjects[tid*CLPAD][i+1];\r\n            numRetiredObjects[tid*CLPAD]--;\r\n            delete ptr;\r\n\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _HAZARD_POINTERS_H_ */\r\n"
  },
  {
    "path": "common/HazardPointersSimQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_POINTERS_SIM_QUEUE_H_\r\n#define _HAZARD_POINTERS_SIM_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <functional>\r\n#include <vector>\r\n\r\n\r\n/*\r\n * The main difference from this implementation to regular Hazard Pointers is\r\n * that the constructor takes a function pointer to function 'find' which\r\n * acts as a callback, returning true if the pointer is still stored somewhere\r\n * in the data structure. This is used by SimQueue to indicate if there is a\r\n * pointer to the object we're trying to de-allocate in the array of enqReused.\r\n */\r\ntemplate<typename T>\r\nclass HazardPointersSimQueue {\r\n\r\nprivate:\r\n    static const int      HP_MAX_THREADS = 128;\r\n    static const int      HP_MAX_HPS = 11;     // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HP_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    static const int      MAX_RETIRED = HP_MAX_THREADS*HP_MAX_HPS; // Maximum number of retired objects per thread\r\n\r\n    const int             maxHPs;\r\n    const int             maxThreads;\r\n\r\n    std::atomic<T*>       hp[HP_MAX_THREADS*CLPAD][HP_MAX_HPS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    std::vector<T*>       retiredList[HP_MAX_THREADS*CLPAD];\r\n\r\n    std::function<bool(T*)> findPtr;\r\n\r\npublic:\r\n    HazardPointersSimQueue(std::function<bool(T*)>& find, int maxHPs=HP_MAX_HPS, int maxThreads=HP_MAX_THREADS) : maxHPs{maxHPs}, maxThreads{maxThreads} {\r\n        findPtr = find;\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[ithread*CLPAD][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    ~HazardPointersSimQueue() {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[ithread*CLPAD].size(); iret++) {\r\n                delete retiredList[ithread*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHPs)\r\n     */\r\n    void clear(const int tid) {\r\n        for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n            hp[tid*CLPAD][ihp].store(nullptr, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    void clearOne(int ihp, const int tid) {\r\n        hp[tid*CLPAD][ihp].store(nullptr, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* protect(int index, const std::atomic<T*>& atom, const int tid) {\r\n        T* n = nullptr;\r\n        T* ret;\r\n\t\twhile ((ret = atom.load()) != n) {\r\n\t\t\thp[tid*CLPAD][index].store(ret);\r\n\t\t\tn = ret;\r\n\t\t}\r\n\t\treturn ret;\r\n    }\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtr(int index, T* ptr, const int tid) {\r\n        hp[tid*CLPAD][index].store(ptr);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectRelease(int index, T* ptr, const int tid) {\r\n        hp[tid*CLPAD][index].store(ptr, std::memory_order_release);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free bounded (by the number of threads squared)\r\n     */\r\n    void retire(T* ptr, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(ptr);\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            auto obj = retiredList[tid*CLPAD][iret];\r\n            if (findPtr(obj)) {\r\n                iret++;\r\n                continue;\r\n            }\r\n            bool canDelete = true;\r\n            for (int tid = 0; tid < maxThreads && canDelete; tid++) {\r\n                for (int ihp = maxHPs-1; ihp >= 0; ihp--) {\r\n                    if (hp[tid*CLPAD][ihp].load() == obj) {\r\n                        canDelete = false;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            if (canDelete) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                delete obj;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _HAZARD_POINTERS_H_ */\r\n"
  },
  {
    "path": "common/README.md",
    "content": "Here are some files that are needed by other libraries and data structures:\r\n\r\n    HazardEras.hpp              Used by some of the lock-free data structures for memory reclamation\r\n    HazardPointers.hpp          Used by some of the lock-free data structures for memory reclamation\r\n    HazardPointersSimQueue.hpp  Used by SimQueue for memory reclamation. Notice that the original SimQueue implementation in C does not ha memory reclamation. This implementation in C++ with this modified version of Hazard Pointers was done by Correia and Ramalhete\r\n    pfences.h                   Used by Romulus\r\n    RIStaticPerThread.hpp       Used by Romulus\r\n    ThreadRegistry.cpp          Used by Romulus\r\n    ThreadRegistry.hpp          Used by Romulus"
  },
  {
    "path": "common/RIStaticPerThread.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _RISTATIC_H_\r\n#define _RISTATIC_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <cstdint>\r\n\r\n\r\n// TODO: change all calls that need the tid to use a function argument\r\n// TODO: use std::vector instead of arrays for the retired objects (keep the padding)\r\nclass RIStaticPerThread {\r\n\r\nprivate:\r\n    const int maxThreads;\r\n    alignas(128) std::atomic<uint64_t>* states;\r\n\r\n    static const uint64_t NOT_READING = 0;\r\n    static const uint64_t READING = 1;\r\n    static const int CLPAD = 128/sizeof(uint64_t);\r\n\r\npublic:\r\n    RIStaticPerThread(int maxThreads) : maxThreads{maxThreads} {\r\n        states = new std::atomic<uint64_t>[maxThreads*CLPAD];\r\n        for (int tid = 0; tid < maxThreads; tid++) {\r\n            states[tid*CLPAD].store(NOT_READING, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    ~RIStaticPerThread() {\r\n        delete[] states;\r\n    }\r\n\r\n    // Will attempt to pass all current READING states to\r\n    inline void abortRollback() noexcept {\r\n        for (int tid = 0; tid < maxThreads; tid++) {\r\n            if (states[tid*CLPAD].load() != READING) continue;\r\n            uint64_t read = READING;\r\n            states[tid*CLPAD].compare_exchange_strong(read, READING+1);\r\n        }\r\n    }\r\n\r\n    // Returns true if the arrival was successfully rollbacked.\r\n    // If there was a writer changing the state to READING+1 then it will\r\n    // return false, meaning that the arrive() is still valid and visible.\r\n    inline bool rollbackArrive(const int tid) noexcept {\r\n        return (states[tid*CLPAD].fetch_add(-1) == READING);\r\n    }\r\n\r\n    inline void arrive(const int tid) noexcept {\r\n        states[tid*CLPAD].store(READING);\r\n    }\r\n\r\n    inline void depart(const int tid) noexcept {\r\n        states[tid*CLPAD].store(NOT_READING); // Making this \"memory_order_release\" will cause overflows!\r\n    }\r\n\r\n    inline bool isEmpty() noexcept {\r\n        for (int tid = 0; tid < maxThreads; tid++) {\r\n            if (states[tid*CLPAD].load() != NOT_READING) return false;\r\n        }\r\n        return true;\r\n    }\r\n};\r\n\r\n#endif /* RISTATIC_H */\r\n"
  },
  {
    "path": "common/ThreadRegistry.cpp",
    "content": "/*\r\n * Contains all global variables.\r\n */\r\n#include \"common/ThreadRegistry.hpp\"\r\n\r\n// Global/singleton to hold all the thread registry functionality\r\nThreadRegistry gThreadRegistry {};\r\n\r\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\r\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\r\nthread_local ThreadCheckInCheckOut tl_tcico {};\r\n\r\nvoid thread_registry_deregister_thread(const int tid) {\r\n    gThreadRegistry.deregister_thread(tid);\r\n}\r\n"
  },
  {
    "path": "common/ThreadRegistry.hpp",
    "content": "#ifndef _THREAD_REGISTRY_H_\r\n#define _THREAD_REGISTRY_H_\r\n\r\n#include <atomic>\r\n#include <thread>\r\n#include <iostream>\r\n#include <cassert>\r\n\r\n// Increase this if 128 threads is not enough\r\nstatic const int REGISTRY_MAX_THREADS = 128;\r\n\r\n\r\nextern void thread_registry_deregister_thread(const int tid);\r\n\r\n\r\n// An helper class to do the checkin and checkout of the thread registry\r\nstruct ThreadCheckInCheckOut {\r\n    static const int NOT_ASSIGNED = -1;\r\n    int tid { NOT_ASSIGNED };\r\n    ~ThreadCheckInCheckOut() {\r\n        if (tid == NOT_ASSIGNED) return;\r\n        thread_registry_deregister_thread(tid);\r\n    }\r\n};\r\n\r\n\r\nextern thread_local ThreadCheckInCheckOut tl_tcico;\r\n\r\n\r\n// Forward declaration of global/singleton instance\r\nclass ThreadRegistry;\r\nextern ThreadRegistry gThreadRegistry;\r\n\r\n\r\n/*\r\n * <h1> Registry for threads </h1>\r\n *\r\n * This is singleton type class that allows assignement of a unique id to each thread.\r\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\r\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\r\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\r\n * corresponding slot to be used by a later thread.\r\n * RomulusLR relies on this to work properly.\r\n */\r\nclass ThreadRegistry {\r\nprivate:\r\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\r\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\r\n\r\npublic:\r\n    ThreadRegistry() {\r\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            usedTID[it].store(false, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    /*\r\n     * Progress Condition: wait-free bounded (by the number of threads)\r\n     */\r\n    int register_thread_new(void) {\r\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\r\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\r\n            bool unused = false;\r\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\r\n            // Increase the current maximum to cover our thread id\r\n            int curMax = maxTid.load();\r\n            while (curMax <= tid) {\r\n                maxTid.compare_exchange_strong(curMax, tid+1);\r\n                curMax = maxTid.load();\r\n            }\r\n            tl_tcico.tid = tid;\r\n            return tid;\r\n        }\r\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\r\n        assert(false);\r\n    }\r\n\r\n    /*\r\n     * Progress condition: wait-free population oblivious\r\n     */\r\n    inline void deregister_thread(const int tid) {\r\n        usedTID[tid].store(false, std::memory_order_release);\r\n    }\r\n\r\n    /*\r\n     * Progress condition: wait-free population oblivious\r\n     */\r\n    static inline uint64_t getMaxThreads(void) {\r\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\r\n    }\r\n\r\n    /*\r\n     * Progress condition: wait-free bounded (by the number of threads)\r\n     */\r\n    static inline int getTID(void) {\r\n        int tid = tl_tcico.tid;\r\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\r\n        return gThreadRegistry.register_thread_new();\r\n    }\r\n};\r\n\r\n#endif /* _THREAD_REGISTRY_H_ */\r\n"
  },
  {
    "path": "common/pfences.h",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_FENCES_\r\n#define _PERSISTENT_FENCES_\r\n\r\n/*\r\n * The naming for these macros and respective operations were taken from the excellent\r\n * \"Preserving Happens-before in Persistent Memory\" by Izraelevitz, Mendes, and Scott\r\n * https://www.cs.rochester.edu/u/jhi1/papers/2016-spaa-transform\r\n *\r\n * We have five different definitions of pwb/pfence/psync:\r\n * - Emulated: We introduce a delay on stores, like Mnemosyne does\r\n * - Nothing: only works with process restart persistency, i.e. process failures, but not system failure\r\n * - Define pwb as clflush (Broadwell cpus)\r\n * - Define pwb as clflushopt (most x86 cpus)\r\n * - Define pwb as clwb (only very recent cpus have this instruction)\r\n */\r\n\r\n/*\r\n * We copied the methods from Menmosyne:\r\n * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.221.5462&rep=rep1&type=pdf\r\n */\r\nstatic inline unsigned long long asm_rdtsc(void)\r\n{\r\n    unsigned hi, lo;\r\n    __asm__ __volatile__ (\"rdtsc\" : \"=a\"(lo), \"=d\"(hi));\r\n    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );\r\n}\r\n\r\n// Change this depending on the clock cycle of your cpu. For Cervino it's 2100, for my laptop it's 2712.\r\n#define EMULATED_CPUFREQ  2100\r\n\r\n#define NS2CYCLE(__ns) ((__ns) * EMULATED_CPUFREQ / 1000)\r\n\r\nstatic inline void emulate_latency_ns(int ns) {\r\n    uint64_t stop;\r\n    uint64_t start = asm_rdtsc();\r\n    uint64_t cycles = NS2CYCLE(ns);\r\n    do {\r\n        /* RDTSC doesn't necessarily wait for previous instructions to complete\r\n         * so a serializing instruction is usually used to ensure previous\r\n         * instructions have completed. However, in our case this is a desirable\r\n         * property since we want to overlap the latency we emulate with the\r\n         * actual latency of the emulated instruction.\r\n         */\r\n        stop = asm_rdtsc();\r\n    } while (stop - start < cycles);\r\n}\r\n\r\n\r\n/*\r\n * We use the settings on the delays for emulation from the NVMOVE paper:\r\n * http://www.cs.utexas.edu/~vijay/papers/inflow16-nvmove.pdf\r\n */\r\n#ifdef PWB_IS_STT\r\n  /* Delays for emulating STT in DRAM */\r\n  #define PWB(addr)              emulate_latency_ns(140)\r\n  #define PFENCE()               emulate_latency_ns(200)\r\n  #define PSYNC()                emulate_latency_ns(200)\r\n#elif PWB_IS_PCM\r\n  /* Delays for emulating PCM in DRAM */\r\n  #define PWB(addr)              emulate_latency_ns(340)\r\n  #define PFENCE()               emulate_latency_ns(500)\r\n  #define PSYNC()                emulate_latency_ns(500)\r\n#elif PWB_IS_CLFLUSH\r\n  /*\r\n   * More info at http://elixir.free-electrons.com/linux/latest/source/arch/x86/include/asm/special_insns.h#L213\r\n   * Intel programming manual at https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf\r\n   * Use these for Broadwell CPUs (cervino server)\r\n   */\r\n  #define PWB(addr)              __asm__ volatile(\"clflush (%0)\" :: \"r\" (addr) : \"memory\")                      // Broadwell only works with this.\r\n  #define PFENCE()               {}                                                                             // No ordering fences needed for CLFLUSH (section 7.4.6 of Intel manual)\r\n  #define PSYNC()                {}                                                                             // For durability it's not obvious, but CLFLUSH seems to be enough, and PMDK uses the same approach\r\n#elif PWB_IS_CLWB\r\n  /* Use this for CPUs that support clwb, such as the SkyLake SP series (c5 compute intensive instances in AWS are an example of it) */\r\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; xsaveopt %0\" : \"+m\" (*(volatile char *)(addr)))  // clwb() only for Ice Lake onwards\r\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\r\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\r\n#elif PWB_IS_NOP\r\n  /* pwbs are not needed for shared memory persistency (i.e. persistency across process failure) */\r\n  #define PWB(addr)              {}\r\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\r\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\r\n#elif PWB_IS_CLFLUSHOPT\r\n  /* Use this for CPUs that support clflushopt, which is most recent x86 */\r\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; clflush %0\" : \"+m\" (*(volatile char *)(addr)))    // clflushopt (Kaby Lake)\r\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\r\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\r\n#else\r\n#error \"You must define what PWB is. Choose PWB_IS_CLFLUSHOPT if you don't know what your CPU is capable of\"\r\n#endif\r\n\r\n// Flush each cache line in a range\r\n// TODO: fix cache alignment\r\ninline static void flushFromTo(void* from, void* to) noexcept {\r\n    const int cache_line_size = 64;\r\n    uint8_t* ptr = (uint8_t*)from;\r\n    for (; ptr < (uint8_t*)to; ptr += cache_line_size) PWB(ptr);\r\n}\r\n\r\n// TODO: Implement fences for ARM\r\n\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/generic/TMHashMap.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _TM_NON_RESIZABLE_HASH_MAP_H_\r\n#define _TM_NON_RESIZABLE_HASH_MAP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include <mutex>\r\n\r\n#include \"../../stms/tm.h\"               // This header defines the macros for the STM being compiled\r\n\r\n\r\n/**\r\n * <h1> A Non-Resizable Hash Map for usage with STMs </h1>\r\n *\r\n * Each node contains 4 entries (key/value) so as to provide better cache locality\r\n *\r\n *\r\n * TODO\r\n\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename K, typename V>\r\nclass TMHashMap : public TM_BASE_TYPE {\r\n\r\nprivate:\r\n    // One KeyVal is 16+16 bytes, therefore, 4 KeyVals are 2 cache lines in x86 (128 bytes)\r\n    static const int KV_NUM = 4;\r\n    static const unsigned int MAX_THREADS = 128;\r\n    const unsigned int maxThreads;\r\n    const unsigned int capacity;\r\n\r\n    struct KeyVal {\r\n        //uint64_t          h;     // Full hash of the key, for faster comparison. TODO: add code to handle h\r\n        TM_TYPE<K*> key {nullptr};\r\n        TM_TYPE<V*> val {nullptr};\r\n        KeyVal() {}\r\n        KeyVal(K* key, V* value) : key{key}, val{value} { }\r\n    };\r\n\r\n    struct Node : TM_BASE_TYPE {\r\n        KeyVal            kv[KV_NUM];\r\n        TM_TYPE<Node*>    next {nullptr};\r\n        Node() {}\r\n        Node(K* key, V* value) {\r\n            kv[0].key = key;\r\n            kv[0].val = value;\r\n        }\r\n        bool isEmpty() {\r\n            for (int i = 0; i < KV_NUM; i++) {\r\n                if (kv[i].key != nullptr) return false;\r\n            }\r\n            return true;\r\n        }\r\n    };\r\n\r\n    alignas(128) Node* buckets;      // An array of Nodes\r\n\r\n\r\n    int myhash(K* key) { return 0; }  // Used only for tests\r\n\r\npublic:\r\n    TMHashMap(unsigned int maxThreads=MAX_THREADS, unsigned int capacity=2*1024*1024) : maxThreads{maxThreads}, capacity{capacity} {\r\n        buckets = new Node[capacity];\r\n    }\r\n\r\n\r\n    ~TMHashMap() {\r\n        delete[] buckets;\r\n    }\r\n\r\n\r\n    std::string className() { return TM_NAME() + \"-HashMap\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\r\n     * Returns the previous value (nullptr by default).\r\n     */\r\n    V* put(K* key, V* value, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        if (value == nullptr) throw std::invalid_argument(\"value can not be nullptr\");\r\n        V* oldVal = nullptr;\r\n        KeyVal *firstFree = nullptr;\r\n        auto h = std::hash<K>{}(*key);\r\n        Node* node = &buckets[h];\r\n        while (true) {\r\n            for (int i = 0; i < KV_NUM; i++) {\r\n                KeyVal& kv = node->kv[i];\r\n                if (kv.key == nullptr) {\r\n                    // Save the first available entry, in case we need to insert somewhere\r\n                    if (firstFree == nullptr) firstFree = &kv;\r\n                    continue;\r\n                }\r\n                if (*kv.key != *key) continue;\r\n                // Found a matching key, replace the old value with the new\r\n                oldVal = kv.val;\r\n                kv.val = value;\r\n                return oldVal;\r\n            }\r\n            Node* lnext = node->next;\r\n            if (lnext == nullptr) break;\r\n            node = lnext;\r\n        }\r\n        // We got here without a replacement, so insert in the first available\r\n        if (firstFree == nullptr) {\r\n            // No available entry, allocate a node and insert it there\r\n            Node* newNode = TM_ALLOC<Node>(key,value);\r\n            node->next = newNode;\r\n        } else {\r\n            firstFree->key = key;\r\n            firstFree->val = value;\r\n        }\r\n        return oldVal;\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Removes a key, returning the value associated with it.\r\n     * Returns nullptr if there is no matching key.\r\n     */\r\n    V* removeKey(K* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        auto h = std::hash<K>{}(*key);\r\n        Node* node = &buckets[h];\r\n        Node* prev = node;\r\n        while (true) {\r\n            for (int i = 0; i < KV_NUM; i++) {\r\n                KeyVal& kv = node->kv[i];\r\n                if (kv.key == nullptr || *kv.key != *key) continue;\r\n                // Found a matching key, replace the old value with nullptr\r\n                V* oldVal = kv.val;\r\n                kv.val = nullptr;\r\n                kv.key = nullptr;\r\n                // Check if it's the first node and if it is empty, then unlink it and free it\r\n                if (prev != node && node->isEmpty()) {\r\n                    prev->next = node->next;\r\n                    TM_FREE(node);\r\n                }\r\n                return oldVal;\r\n            }\r\n            prev = node;\r\n            node = node->next;\r\n            // We got to the end without a matching key, return nullptr\r\n            if (node == nullptr) return nullptr;\r\n        }\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Returns the value of associated with the key, nullptr if there is no mapping\r\n     */\r\n    V* get(K* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        auto h = std::hash<K>{}(*key);\r\n        Node* node = &buckets[h];\r\n        while (true) {\r\n            for (int i = 0; i < KV_NUM; i++) {\r\n                KeyVal& kv = node->kv[i];\r\n                if (kv.key == nullptr || *kv.key != *key) continue;\r\n                return kv.val;\r\n            }\r\n            Node* lnext = node->next;\r\n            if (lnext == nullptr) return nullptr;\r\n            node = lnext;\r\n        }\r\n    }\r\n\r\n\r\n\r\n    //\r\n    // Set methods for running the usual tests and benchmarks\r\n    //\r\n\r\n    bool add(K* key, const int tid) {\r\n        return TM_WRITE_TRANSACTION<bool>([&] () -> bool {\r\n            return put(key,key, tid) == nullptr;\r\n        });\r\n    }\r\n\r\n    bool remove(K* key, const int tid) {\r\n        return TM_WRITE_TRANSACTION<bool>([this,key,tid] () -> bool {\r\n            return removeKey(key, tid) != nullptr;\r\n        });\r\n    }\r\n\r\n    bool contains(K* key, const int tid) {\r\n        return TM_READ_TRANSACTION<bool>([this,key,tid] () -> bool {\r\n            return get(key, tid) != nullptr;\r\n        });\r\n    }\r\n\r\n    // Used only for benchmarks. It's single-threaded\r\n    bool addAll(K** keys, const int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(keys[i], tid);\r\n    }\r\n\r\n};\r\n\r\n#endif /* _TM_NON_RESIZABLE_HASH_MAP_H_ */\r\n"
  },
  {
    "path": "datastructures/generic/TMLinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _TM_LINKED_LIST_QUEUE_H_\r\n#define _TM_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"../../stms/CRWWPSTM.hpp\"\r\n#include \"../../stms/LeftRightTM.hpp\"\r\n#include \"../../stms/tm.h\"               // This header defines the macros for the STM being compiled\r\n#include \"MWCLF.hpp\"\r\n#include \"MWCWF.hpp\"\r\n#include \"CXTM.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using STM </h1>\r\n *\r\n *\r\n * TODO\r\n *\r\n *\r\n * enqueue algorithm: sequential implementation + MWC\r\n * dequeue algorithm: sequential implementation + MWC\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into MWC)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass TMLinkedListQueue {\r\n\r\nprivate:\r\n    static const unsigned int MAX_THREADS = 128;\r\n    const unsigned int maxThreads;\r\n\r\n    struct Node : TM_BASE_TYPE {\r\n        T* item;\r\n        TM_TYPE<Node*> next;\r\n        Node(T* userItem) : item{userItem}, next{nullptr} { }\r\n    };\r\n\r\n    alignas(128) TM_TYPE<Node*>  head {nullptr};\r\n    alignas(128) TM_TYPE<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    TMLinkedListQueue(unsigned int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        Node* sentinelNode = TM_ALLOC<Node>(nullptr);\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    ~TMLinkedListQueue() {\r\n        // TODO: replace this 0 with the actual tid otherwise we could have issues\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        delete lhead;\r\n    }\r\n\r\n\r\n    static std::string className() { return TM_NAME() + \"-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     *\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return TM_WRITE_TRANSACTION<bool>([this,item] () -> bool {\r\n                Node* newNode = TM_ALLOC<Node>(item);\r\n                tail->next = newNode;\r\n                tail = newNode;\r\n                return true;\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     *\r\n     */\r\n    T* dequeue(const int tid) {\r\n        return TM_WRITE_TRANSACTION<T*>([this] () -> T* {\r\n                Node* lhead = head;\r\n                if (lhead == tail) return nullptr;\r\n                head = lhead->next;\r\n                TM_FREE(lhead);\r\n                return head->item;\r\n            });\r\n    }\r\n};\r\n\r\n#endif /* _MWC_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/generic/TMLinkedListSet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _TM_LINKED_LIST_SET_H_\r\n#define _TM_LINKED_LIST_SET_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"../../stms/tm.h\"               // This header defines the macros for the STM being compiled\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for usage with STMs </h1>\r\n *\r\n * TODO\r\n *\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass TMLinkedListSet : public TM_BASE_TYPE {\r\n\r\nprivate:\r\n    static const unsigned int MAX_THREADS = 128;\r\n    const unsigned int maxThreads;\r\n\r\n    struct Node : public TM_BASE_TYPE {\r\n        T* key;\r\n        TM_TYPE<Node*> next;\r\n        Node(T* key) : key{key}, next{nullptr} { }\r\n    };\r\n\r\n    alignas(128) TM_TYPE<Node*>  head {nullptr};\r\n    alignas(128) TM_TYPE<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    TMLinkedListSet(unsigned int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        Node* lhead = new Node(nullptr);\r\n        Node* ltail = new Node(nullptr);\r\n        head = lhead;\r\n        head->next = ltail;\r\n        tail = ltail;\r\n    }\r\n\r\n\r\n    ~TMLinkedListSet() {\r\n        // Delete all the nodes in the list\r\n        Node* prev = head;\r\n        Node* node = prev->next;\r\n        while (node != tail) {\r\n            delete prev;\r\n            prev = node;\r\n            node = node->next;\r\n        }\r\n        delete prev;\r\n        delete tail;\r\n    }\r\n\r\n\r\n    static std::string className() { return TM_NAME() + \"-LinkedListSet\"; }\r\n\r\n#ifdef TINY_STM\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        bool retval = false;\r\n        WRITE_TX_BEGIN\r\n        Node* newNode = TM_ALLOC<Node>(key);\r\n        Node* prev = head;\r\n        Node* node = prev->next;\r\n        while (true) {\r\n            if (node == tail) {\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                retval = true;\r\n                break;\r\n            }\r\n            if (*key == *node->key) {\r\n                TM_FREE(newNode); // If the key was already in the set, free the node that was never used\r\n                break;\r\n            }\r\n            if (*(node->key) < *key) {\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                retval = true;\r\n                break;\r\n            }\r\n            prev = node;\r\n            node = node->next;\r\n        }\r\n        WRITE_TX_END\r\n        return retval;\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        bool retval = false;\r\n        WRITE_TX_BEGIN\r\n        Node* prev = head;\r\n        Node* node = prev->next;\r\n        while (true) {\r\n            if (node == tail) break;\r\n            if (*key == *node->key) {\r\n                prev->next = node->next;\r\n                TM_FREE(node);\r\n                retval = true;\r\n                break;\r\n            }\r\n            if (*(node->key) < *key) break;\r\n            prev = node;\r\n            node = node->next;\r\n        }\r\n        WRITE_TX_END\r\n        return retval;\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        bool retval = false;\r\n        READ_TX_BEGIN\r\n        Node* node = head->next;\r\n        while (true) {\r\n            if (node == tail) break;\r\n            if (*key == *node->key) {retval = true; break; }\r\n            if (*(node->key) < *key) break;\r\n            node = node->next;\r\n        }\r\n        READ_TX_END\r\n        return retval;\r\n    }\r\n\r\n#else\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        return TM_WRITE_TRANSACTION<bool>([this,key] () -> bool {\r\n                Node* newNode = TM_ALLOC<Node>(key);\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) break;\r\n                    if (*key == *node->key) {\r\n                        TM_FREE(newNode); // If the key was already in the set, free the node that was never used\r\n                        return false;\r\n                    }\r\n                    if (*(node->key) < *key) break;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                return true;\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        return TM_WRITE_TRANSACTION<bool>([this,key] () -> bool {\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (*key == *node->key) {\r\n                        prev->next = node->next;\r\n                        TM_FREE(node);\r\n                        return true;\r\n                    }\r\n                    if (*(node->key) < *key) return false;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T* key, const int tid) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        return TM_READ_TRANSACTION<bool>([this,key] () -> bool {\r\n                Node* node = head->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (*key == *node->key) return true;\r\n                    if (*(node->key) < *key) return false;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n#endif\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(keys[i], tid);\r\n    }\r\n};\r\n\r\n#endif /* _TM_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/generic/TMRedBlackBST.hpp",
    "content": "#ifndef _TM_RED_BLACK_BST_H_\r\n#define _TM_RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n#include \"../../stms/tm.h\"               // This header defines the macros for the STM being compiled\r\n\r\nstatic const int64_t RED   = 0;\r\nstatic const int64_t BLACK = 1;\r\n\r\n//http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V>\r\nclass TMRedBlackBST : public TM_BASE_TYPE {\r\n\r\n    struct Node : TM_BASE_TYPE {\r\n        TM_TYPE<K*>      key;\r\n        TM_TYPE<V*>      val;\r\n        TM_TYPE<Node*>   left {nullptr};\r\n        TM_TYPE<Node*>   right {nullptr};\r\n        TM_TYPE<int64_t> color;    // color of parent link\r\n        TM_TYPE<int64_t> size;     // subtree count\r\n        Node(K* key, V* val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\r\n    };\r\n\r\n    TM_TYPE<Node*> root {nullptr};   // root of the BST\r\n\r\n    const unsigned int maxThreads;\r\n\r\n    inline void assignAndFreeIfNull(TM_TYPE<Node*>& z, Node* w) {\r\n        Node* tofree = z;\r\n        z = w;\r\n        if (w == nullptr) TM_FREE(tofree);\r\n    }\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    TMRedBlackBST(unsigned int maxThreads=128) : maxThreads{maxThreads} { }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    V* get(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return get(root, key);\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    V* get(Node* x, K* key) {\r\n        while (x != nullptr) {\r\n            if      (*key < *x->key) x = x->left;\r\n            else if (*x->key < *key) x = x->right;\r\n            else              return x->val;\r\n        }\r\n        return nullptr;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool contains(K* key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    void put(K* key, V* val) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (val == nullptr) {\r\n            deleteKey(key);\r\n            return;\r\n        }\r\n        root = put(root, key, val);\r\n        root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, K* key, V* val) {\r\n        if (h == nullptr) return TM_ALLOC<Node>(key, val, RED, 1);\r\n        if      (*key < *h->key) h->left  = put(h->left,  key, val);\r\n        else if (*h->key < *key) h->right = put(h->right, key, val);\r\n        else              h->val   = val;\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = RED;\r\n        assignAndFreeIfNull(root, deleteMin(root));\r\n        if (!isEmpty()) root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    void deleteKey(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (!contains(key)) return;\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = RED;\r\n        assignAndFreeIfNull(root, deleteKey(root, key));\r\n        if (!isEmpty()) root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, K* key) {\r\n        // assert get(h, key) != null;\r\n        if (*key < *h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left)) {\r\n                h = moveRedLeft(h);\r\n            }\r\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\r\n        } else {\r\n            if (isRed(h->left)) {\r\n                h = rotateRight(h);\r\n            }\r\n            if (*key == *h->key && (h->right == nullptr)) {\r\n                return nullptr;\r\n            }\r\n            if (!isRed(h->right) && !isRed(h->right->left)) {\r\n                h = moveRedRight(h);\r\n            }\r\n            if (*key == *h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\r\n            } else {\r\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\r\n            }\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                        h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, K* key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (*key == *x->key) return x;\r\n        if (*key < *x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, K* key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (*key == *x->key) return x;\r\n        if (*x->key < *key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            throw std::invalid_argument(\"item can not be nullptr\");\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(K* key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (*key < *x->key) return rank(key, x->left);\r\n        else if (*x->key < *key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(K* lo, K* hi) {\r\n        if (lo == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (hi == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n\r\n        if (*hi < *lo) return 0;\r\n        if (contains(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        // TODO: port these two lines\r\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Set methods\r\n    bool add(K* key, const int tid) {\r\n        return TM_WRITE_TRANSACTION<bool>([this,key] () -> bool {\r\n            if (contains(key)) return false;\r\n            put(key,key);\r\n            return true;\r\n        });\r\n    }\r\n\r\n    bool remove(K* key, const int tid) {\r\n        return TM_WRITE_TRANSACTION<bool>([this,key] () -> bool {\r\n            if (!contains(key)) return false;\r\n            deleteKey(key);\r\n            return true;\r\n        });\r\n    }\r\n\r\n    inline bool contains(K* key, const int tid) {\r\n        return TM_READ_TRANSACTION<bool>([this,key] () -> bool {\r\n            return contains(key);\r\n        });\r\n    }\r\n\r\n    // This is not fully transactionally but it's ok because we use it only on initialization.\r\n    // We could make it fully transactionally, but we would have to increase the size of allocation/store logs.\r\n    bool addAll(K** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(keys[i], tid);\r\n    }\r\n\r\n    std::string className() { return TM_NAME() + \"-RedBlackBST\"; }\r\n\r\n};\r\n\r\n#endif   // _TM_RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "datastructures/hashmaps/CRWWPSTMResizableHashSet.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _CRWWP_STM_RESIZABLE_HASH_MAP_H_\n#define _CRWWP_STM_RESIZABLE_HASH_MAP_H_\n\n#include <string>\n\n#include \"stms/CRWWPSTM.hpp\"\n\n/**\n * <h1> A Resizable Hash Map for usage with STMs </h1>\n * TODO\n *\n */\ntemplate<typename K>\nclass CRWWPSTMResizableHashSet {\n\nprivate:\n    struct Node : public crwwpstm::tmbase {\n        crwwpstm::tmtype<K>     key;\n        crwwpstm::tmtype<Node*> next {nullptr};\n        Node(const K& k) : key{k} { } // Copy constructor for k\n    };\n\n    crwwpstm::tmtype<long>                         capacity;\n    crwwpstm::tmtype<long>                         sizeHM = 0;\n    static constexpr double                        loadFactor = 0.75;\n    crwwpstm::tmtype<crwwpstm::tmtype<Node*>*>     buckets;      // An array of pointers to Nodes\n\n\npublic:\n    CRWWPSTMResizableHashSet(int maxThreads=0, int capacity=4) : capacity{capacity} {\n        crwwpstm::updateTx([&] () {\n            buckets = (crwwpstm::tmtype<Node*>*)crwwpstm::tmMalloc(capacity*sizeof(crwwpstm::tmtype<Node*>));\n            for (int i = 0; i < capacity; i++) buckets[i] = nullptr;\n        });\n    }\n\n\n    ~CRWWPSTMResizableHashSet() {\n        crwwpstm::updateTx([&] () {\n            for(int i = 0; i < capacity; i++){\n                Node* node = buckets[i];\n                while (node != nullptr) {\n                    Node* next = node->next;\n                    crwwpstm::tmDelete(node);\n                    node = next;\n                }\n            }\n            crwwpstm::tmFree(buckets.load());\n        });\n    }\n\n\n    static std::string className() { return crwwpstm::CRWWPSTM::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        int newcapacity = 2*capacity;\n        crwwpstm::tmtype<Node*>* newbuckets = (crwwpstm::tmtype<Node*>*)crwwpstm::tmMalloc(newcapacity*sizeof(crwwpstm::tmtype<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while(node!=nullptr){\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        crwwpstm::tmFree(buckets.load());\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key) {\n        if (sizeHM > capacity*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = crwwpstm::tmNew<Node>(key);\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM++;\n                return true;  // New insertion\n            }\n            if (key == node->key) return false;\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM--;\n                crwwpstm::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) return true;\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(K key, const int tid=0) {\n        return crwwpstm::updateTx<bool>([&] () {\n            return innerPut(key);\n        });\n    }\n\n    // Returns true only if the key was present\n    bool remove(K key, const int tid=0) {\n        return crwwpstm::updateTx<bool>([&] () {\n            return innerRemove(key);\n        });\n    }\n\n    bool contains(K key, const int tid=0) {\n        return crwwpstm::readTx<bool>([&] () {\n            return innerGet(key);\n        });\n    }\n\n    // Used only for benchmarks\n    void addAll(K** keys, const int size, const int tid=0) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n    }\n};\n\n#endif /* _CRWWP_STM_RESIZABLE_HASH_MAP_H_ */\n"
  },
  {
    "path": "datastructures/hashmaps/ESTMResizableHashSet.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _ESTM_RESIZABLE_HASH_MAP_H_\n#define _ESTM_RESIZABLE_HASH_MAP_H_\n\n#include <string>\n\n#include \"stms/ESTM.hpp\"\n\n/**\n * <h1> A Resizable Hash Map for usage with STMs </h1>\n * TODO\n *\n */\ntemplate<typename K>\nclass ESTMResizableHashSet {\n\nprivate:\n    struct Node : public estm::tmbase {\n        estm::tmtype<K>     key;\n        estm::tmtype<Node*> next {nullptr};\n        Node(const K& k) : key{k} { } // Copy constructor for k\n    };\n\n    estm::tmtype<uint64_t>                     capacity;\n    estm::tmtype<uint64_t>                     sizeHM = 0;\n    static constexpr double                    loadFactor = 0.75;\n    estm::tmtype<estm::tmtype<Node*>*>         buckets;      // An array of pointers to Nodes\n\n\npublic:\n    ESTMResizableHashSet(int maxThreads=0, uint64_t capacity=4) : capacity{capacity} {\n        estm::updateTx([&] () {\n            buckets = (estm::tmtype<Node*>*)estm::tmMalloc(capacity*sizeof(estm::tmtype<Node*>));\n            for (int i = 0; i < capacity; i++) buckets[i] = nullptr;\n        });\n    }\n\n\n    ~ESTMResizableHashSet() {\n        estm::updateTx([&] () {\n            for(int i = 0; i < capacity; i++){\n                Node* node = buckets[i];\n                while (node != nullptr) {\n                    Node* next = node->next;\n                    estm::tmDelete(node);\n                    node = next;\n                }\n            }\n            estm::tmFree(buckets.load());\n        });\n    }\n\n\n    static std::string className() { return estm::ESTM::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        uint64_t newcapacity = 2*capacity;\n        estm::tmtype<Node*>* newbuckets = (estm::tmtype<Node*>*)estm::tmMalloc(newcapacity*sizeof(estm::tmtype<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while (node!=nullptr) {\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        estm::tmFree(buckets);\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key) {\n        if (sizeHM.load() > capacity.load()*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = estm::tmNew<Node>(key);\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM++;\n                return true;  // New insertion\n            }\n            if (key == node->key) return false;\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM--;\n                estm::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) return true;\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(K key, const int tid=0) {\n        return estm::updateTx<bool>([&] () {\n            return innerPut(key);\n        });\n    }\n\n    // Returns true only if the key was present\n    bool remove(K key, const int tid=0) {\n        return estm::updateTx<bool>([&] () {\n            return innerRemove(key);\n        });\n    }\n\n    bool contains(K key, const int tid=0) {\n        return estm::readTx<bool>([&] () {\n            return innerGet(key);\n        });\n    }\n\n    // Used only for benchmarks\n    void addAll(K** keys, const int size, const int tid=0) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n    }\n};\n\n#endif /* _ESTM_RESIZABLE_HASH_MAP_H_ */\n"
  },
  {
    "path": "datastructures/hashmaps/OFLFResizableHashSet.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _OF_LF_RESIZABLE_HASH_MAP_H_\n#define _OF_LF_RESIZABLE_HASH_MAP_H_\n\n#include <string>\n\n#include \"stms/OneFileLF.hpp\"\n\n/**\n * <h1> A Resizable Hash Map for usage with STMs </h1>\n * TODO\n *\n */\ntemplate<typename K>\nclass OFLFResizableHashSet {\n\nprivate:\n    struct Node : public oflf::tmbase {\n        oflf::tmtype<K>     key;\n        oflf::tmtype<Node*> next {nullptr};\n        Node(const K& k) : key{k} { } // Copy constructor for k\n    };\n\n    oflf::tmtype<uint64_t>                     capacity;\n    oflf::tmtype<uint64_t>                     sizeHM = 0;\n    static constexpr double                         loadFactor = 0.75;\n    oflf::tmtype<oflf::tmtype<Node*>*>    buckets;      // An array of pointers to Nodes\n\n\npublic:\n    OFLFResizableHashSet(int maxThreads=0, uint64_t capacity=4) : capacity{capacity} {\n        oflf::updateTx([&] () {\n            buckets = (oflf::tmtype<Node*>*)oflf::tmMalloc(capacity*sizeof(oflf::tmtype<Node*>));\n            for (int i = 0; i < capacity; i++) buckets[i] = nullptr;\n        });\n    }\n\n\n    ~OFLFResizableHashSet() {\n        oflf::updateTx([&] () {\n            for (int i = 0; i < capacity; i++){\n                Node* node = buckets[i];\n                while (node != nullptr) {\n                    Node* next = node->next;\n                    oflf::tmDelete(node);\n                    node = next;\n                }\n            }\n            oflf::tmFree(buckets.pload());\n        });\n    }\n\n\n    static std::string className() { return oflf::OneFileLF::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        uint64_t newcapacity = 2*capacity;\n        oflf::tmtype<Node*>* newbuckets = (oflf::tmtype<Node*>*)oflf::tmMalloc(newcapacity*sizeof(oflf::tmtype<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while (node!=nullptr) {\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        oflf::tmFree(buckets.pload());\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key) {\n        if (sizeHM.pload() > capacity.pload()*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = oflf::tmNew<Node>(key);\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM++;\n                return true;  // New insertion\n            }\n            if (key == node->key) return false;\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM--;\n                oflf::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) return true;\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(K key, const int tid=0) {\n        return oflf::updateTx<bool>([&] () {\n            return innerPut(key);\n        });\n    }\n\n    // Returns true only if the key was present\n    bool remove(K key, const int tid=0) {\n        return oflf::updateTx<bool>([&] () {\n            return innerRemove(key);\n        });\n    }\n\n    bool contains(K key, const int tid=0) {\n        return oflf::readTx<bool>([&] () {\n            return innerGet(key);\n        });\n    }\n\n    // Used only for benchmarks\n    void addAll(K** keys, const int size, const int tid=0) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n    }\n};\n\n#endif /* _OF_LF_RESIZABLE_HASH_MAP_H_ */\n"
  },
  {
    "path": "datastructures/hashmaps/OFWFResizableHashSet.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _OF_WF_RESIZABLE_HASH_MAP_H_\n#define _OF_WF_RESIZABLE_HASH_MAP_H_\n\n#include <string>\n\n#include \"stms/OneFileWF.hpp\"\n\n/**\n * <h1> A Resizable Hash Map for usage with STMs </h1>\n * TODO\n *\n */\ntemplate<typename K>\nclass OFWFResizableHashSet {\n\nprivate:\n    struct Node : public ofwf::tmbase {\n        ofwf::tmtype<K>     key;\n        ofwf::tmtype<Node*> next {nullptr};\n        Node(const K& k) : key{k} { } // Copy constructor for k\n    };\n\n    ofwf::tmtype<uint64_t>                     capacity;\n    ofwf::tmtype<uint64_t>                     sizeHM = 0;\n    static constexpr double                         loadFactor = 0.75;\n    ofwf::tmtype<ofwf::tmtype<Node*>*>    buckets;      // An array of pointers to Nodes\n\n\npublic:\n    OFWFResizableHashSet(int maxThreads=0, uint64_t capacity=4) : capacity{capacity} {\n        ofwf::updateTx([&] () {\n            buckets = (ofwf::tmtype<Node*>*)ofwf::tmMalloc(capacity*sizeof(ofwf::tmtype<Node*>));\n            for (int i = 0; i < capacity; i++) buckets[i] = nullptr;\n        });\n    }\n\n\n    ~OFWFResizableHashSet() {\n        ofwf::updateTx([=] () {\n            for (int i = 0; i < capacity; i++){\n                Node* node = buckets[i];\n                while (node != nullptr) {\n                    Node* next = node->next;\n                    ofwf::tmDelete(node);\n                    node = next;\n                }\n            }\n            ofwf::tmFree(buckets.pload());\n        });\n    }\n\n\n    static std::string className() { return ofwf::OneFileWF::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        uint64_t newcapacity = 2*capacity;\n        ofwf::tmtype<Node*>* newbuckets = (ofwf::tmtype<Node*>*)ofwf::tmMalloc(newcapacity*sizeof(ofwf::tmtype<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while (node!=nullptr) {\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        ofwf::tmFree(buckets.pload());\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key) {\n        if (sizeHM.pload() > capacity.pload()*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = ofwf::tmNew<Node>(key);\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM++;\n                return true;  // New insertion\n            }\n            if (key == node->key) return false;\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM--;\n                ofwf::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) return true;\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(K key, const int tid=0) {\n        return ofwf::updateTx<bool>([=] () {\n            return innerPut(key);\n        });\n    }\n\n    // Returns true only if the key was present\n    bool remove(K key, const int tid=0) {\n        return ofwf::updateTx<bool>([=] () {\n            return innerRemove(key);\n        });\n    }\n\n    bool contains(K key, const int tid=0) {\n        return ofwf::readTx<bool>([=] () {\n            return innerGet(key);\n        });\n    }\n\n    // Used only for benchmarks\n    void addAll(K** keys, const int size, const int tid=0) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n    }\n};\n\n#endif /* _OF_WF_RESIZABLE_HASH_MAP_H_ */\n"
  },
  {
    "path": "datastructures/hashmaps/TinySTMResizableHashSet.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _TINY_STM_RESIZABLE_HASH_MAP_H_\n#define _TINY_STM_RESIZABLE_HASH_MAP_H_\n\n#include <string>\n\n#include \"stms/TinySTM.hpp\"\n\n/**\n * <h1> A Resizable Hash Map for usage with STMs </h1>\n * TODO\n *\n */\ntemplate<typename K>\nclass TinySTMResizableHashSet {\n\nprivate:\n    struct Node : public tinystm::tmbase {\n        tinystm::tmtype<K>     key;\n        tinystm::tmtype<Node*> next {nullptr};\n        Node(const K& k) : key{k} { } // Copy constructor for k\n    };\n\n    tinystm::tmtype<uint64_t>                     capacity;\n    tinystm::tmtype<uint64_t>                     sizeHM = 0;\n    static constexpr double                       loadFactor = 0.75;\n    tinystm::tmtype<tinystm::tmtype<Node*>*>      buckets;      // An array of pointers to Nodes\n\n\npublic:\n    TinySTMResizableHashSet(int maxThreads=0, uint64_t capacity=4) : capacity{capacity} {\n        tinystm::updateTx<bool>([&] () {\n            buckets = (tinystm::tmtype<Node*>*)tinystm::tmMalloc(capacity*sizeof(tinystm::tmtype<Node*>));\n            for (int i = 0; i < capacity; i++) buckets[i] = nullptr;\n            return true;\n        });\n    }\n\n\n    ~TinySTMResizableHashSet() {\n        tinystm::updateTx<bool>([&] () {\n            for(int i = 0; i < capacity; i++){\n                Node* node = buckets[i];\n                while (node != nullptr) {\n                    Node* next = node->next;\n                    tinystm::tmDelete(node);\n                    node = next;\n                }\n            }\n            tinystm::tmFree(buckets.load());\n            return true;\n        });\n    }\n\n\n    static std::string className() { return tinystm::TinySTM::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        uint64_t newcapacity = 2*capacity;\n        tinystm::tmtype<Node*>* newbuckets = (tinystm::tmtype<Node*>*)tinystm::tmMalloc(newcapacity*sizeof(tinystm::tmtype<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while (node!=nullptr) {\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        tinystm::tmFree(buckets);\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key) {\n        if (sizeHM > capacity*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = tinystm::tmNew<Node>(key);\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM++;\n                return true;  // New insertion\n            }\n            if (key == node->key) return false;\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM--;\n                tinystm::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) return true;\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(K key, const int tid=0) {\n        return tinystm::updateTx<bool>([&] () {\n            return innerPut(key);\n        });\n    }\n\n    // Returns true only if the key was present\n    bool remove(K key, const int tid=0) {\n        return tinystm::updateTx<bool>([&] () {\n            return innerRemove(key);\n        });\n    }\n\n    bool contains(K key, const int tid=0) {\n        return tinystm::readTx<bool>([&] () {\n            return innerGet(key);\n        });\n    }\n\n    // Used only for benchmarks\n    void addAll(K** keys, const int size, const int tid=0) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n    }\n};\n\n#endif /* _TINY_STM_RESIZABLE_HASH_MAP_H_ */\n"
  },
  {
    "path": "datastructures/linkedlists/CRWWPLinkedListSet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _CRWWP_STM_LINKED_LIST_SET_H_\r\n#define _CRWWP_STM_LINKED_LIST_SET_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"stms/CRWWPSTM.hpp\"\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for CRWWP STM (blocking) </h1>\r\n *\r\n * TODO\r\n *\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass CRWWPLinkedListSet : public crwwpstm::tmbase {\r\n\r\nprivate:\r\n    struct Node : public crwwpstm::tmbase {\r\n        T key;\r\n        crwwpstm::tmtype<Node*> next {nullptr};\r\n        Node() {}\r\n        Node(T key) : key{key} { }\r\n    };\r\n\r\n    alignas(128) crwwpstm::tmtype<Node*>  head {nullptr};\r\n    alignas(128) crwwpstm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    CRWWPLinkedListSet(unsigned int maxThreads=0) {\r\n        Node* lhead = new Node();\r\n        Node* ltail = new Node();\r\n        head = lhead;\r\n        head->next = ltail;\r\n        tail = ltail;\r\n    }\r\n\r\n\r\n    ~CRWWPLinkedListSet() {\r\n        // Delete all the nodes in the list\r\n        Node* prev = head;\r\n        Node* node = prev->next;\r\n        while (node != tail) {\r\n            delete prev;\r\n            prev = node;\r\n            node = node->next;\r\n        }\r\n        delete prev;\r\n        delete tail;\r\n    }\r\n\r\n\r\n    static std::string className() { return crwwpstm::CRWWPSTM::className() + \"-LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T key, const int tid=0) {\r\n        return crwwpstm::updateTx<bool>([&] () -> bool {\r\n                Node* newNode = crwwpstm::tmNew<Node>(key);\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) break;\r\n                    if (key == node->key) {\r\n                        crwwpstm::tmDelete(newNode); // If the key was already in the set, free the node that was never used\r\n                        return false;\r\n                    }\r\n                    if (node->key < key) break;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                return true;\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T key, const int tid=0) {\r\n        return crwwpstm::updateTx<bool>([&] () -> bool {\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (key == node->key) {\r\n                        prev->next = node->next;\r\n                        crwwpstm::tmDelete(node);\r\n                        return true;\r\n                    }\r\n                    if (node->key < key) return false;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T key, const int tid=0) {\r\n        return crwwpstm::readTx<bool>([&] () -> bool {\r\n                Node* node = head->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (key == node->key) return true;\r\n                    if (node->key < key) return false;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n};\r\n\r\n#endif /* _C_RW_WP_STM_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/ESTMLinkedListSet.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _ESTM_LINKED_LIST_SET_H_\r\n#define _ESTM_LINKED_LIST_SET_H_\r\n\r\n\r\n#include \"../../stms/ESTM.hpp\"               // This header defines the macros for the STM being compiled\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for Elastic STM </h1>\r\n * When we make the 'ltail' optimization here, it causes a crash on ESTM, therefore we don't do it.\r\n */\r\ntemplate<typename T>\r\nclass ESTMLinkedListSet : public estm::tmbase {\r\n\r\nprivate:\r\n    struct Node : public estm::tmbase {\r\n        T key {};\r\n        estm::tmtype<Node*> next {nullptr};\r\n        Node() {}\r\n        Node(T key) : key{key} { }\r\n    };\r\n\r\n    alignas(128) estm::tmtype<Node*>  head {nullptr};\r\n    alignas(128) estm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    ESTMLinkedListSet(unsigned int maxThreads=0) {\r\n        estm::updateTx([&] () {\r\n            Node* lhead = estm::tmNew<Node>();\r\n            Node* ltail = estm::tmNew<Node>();\r\n            head = lhead;\r\n            head->next = ltail;\r\n            tail = ltail;\r\n        });\r\n    }\r\n\r\n\r\n    ~ESTMLinkedListSet() {\r\n        estm::updateTx([&] () {\r\n            // Delete all the nodes in the list\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            while (node != tail) {\r\n                estm::tmDelete(prev);\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n            estm::tmDelete(prev);\r\n            estm::tmDelete(tail.load());\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return estm::ESTM::className() + \"-LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T key, const int tid=0) {\r\n        return estm::updateTx<bool>([this,key] () {\r\n                Node* newNode = estm::tmNew<Node>(key);\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) break;\r\n                    if (key == node->key) {\r\n                        estm::tmDelete(newNode); // If the key was already in the set, free the node that was never used\r\n                        return false;\r\n                    }\r\n                    if (node->key < key) break;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                return true;\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T key, const int tid=0) {\r\n        return estm::updateTx<bool>([this,key] () {\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (key == node->key) {\r\n                        prev->next = node->next;\r\n                        estm::tmDelete(node);\r\n                        return true;\r\n                    }\r\n                    if (node->key < key) return false;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T key, const int tid=0) {\r\n        return estm::readTx<bool>([this,key] () {\r\n            Node* node = head->next;\r\n            while (true) {\r\n                if (node == tail) return false;\r\n                if (key == node->key) return true;\r\n                if (node->key < key) return false;\r\n                node = node->next;\r\n            }\r\n        });\r\n    }\r\n\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n        return true;\r\n    }\r\n};\r\n\r\n#endif /* _ESTM_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/HazardEras.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2016-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_ERAS_H_\r\n#define _HAZARD_ERAS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <vector>\r\n#include <algorithm>\r\n\r\n/*\r\n * <h1> Hazard Eras </h1>\r\n * This a light-weight implementation of hazard eras, where each thread has a\r\n * thread-local list of retired objects.\r\n *\r\n * This is based on the paper \"Hazard Eras - Non-Blocking Memory Reclamation\"\r\n * by Pedro Ramalhete and Andreia Correia:\r\n * https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf\r\n *\r\n * The type T is for the objects/nodes and it's it must have the members newEra, delEra\r\n *\r\n * R is zero.\r\n *\r\n * <p>\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass HazardEras {\r\n\r\nprivate:\r\n    static const uint64_t NONE = 0;\r\n    static const int      HE_MAX_THREADS = 128;\r\n    static const int      MAX_HES = 5;        // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HE_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n\r\n    const int             maxHEs;\r\n    const int             maxThreads;\r\n\r\n    alignas(128) std::atomic<uint64_t>  eraClock {1};\r\n    alignas(128) std::atomic<uint64_t>* he[HE_MAX_THREADS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<T*>        retiredList[HE_MAX_THREADS*CLPAD];\r\n\r\npublic:\r\n    HazardEras(int maxHEs=MAX_HES, int maxThreads=HE_MAX_THREADS) : maxHEs{maxHEs}, maxThreads{maxThreads} {\r\n        for (int it = 0; it < HE_MAX_THREADS; it++) {\r\n            he[it] = new std::atomic<uint64_t>[CLPAD*2]; // We allocate four cache lines to allow for many hps and without false sharing\r\n            retiredList[it*CLPAD].reserve(maxThreads*maxHEs);\r\n            for (int ihe = 0; ihe < MAX_HES; ihe++) {\r\n                he[it][ihe].store(NONE, std::memory_order_relaxed);\r\n            }\r\n        }\r\n        static_assert(std::is_same<decltype(T::newEra), uint64_t>::value, \"T::newEra must be uint64_t\");\r\n        static_assert(std::is_same<decltype(T::delEra), uint64_t>::value, \"T::delEra must be uint64_t\");\r\n    }\r\n\r\n    ~HazardEras() {\r\n        for (int it = 0; it < HE_MAX_THREADS; it++) {\r\n            delete[] he[it];\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[it*CLPAD].size(); iret++) {\r\n                delete retiredList[it*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    inline uint64_t getEra() {\r\n        return eraClock.load();\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHEs)\r\n     */\r\n    inline void clear(const int tid) {\r\n        for (int ihe = 0; ihe < maxHEs; ihe++) {\r\n            he[tid][ihe].store(NONE, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    inline T* get_protected(int index, const std::atomic<T*>& atom, const int tid) {\r\n        auto prevEra = he[tid][index].load(std::memory_order_relaxed);\r\n\t\twhile (true) {\r\n\t\t    T* ptr = atom.load();\r\n\t\t    auto era = eraClock.load(std::memory_order_acquire);\r\n\t\t    if (era == prevEra) return ptr;\r\n            he[tid][index].store(era);\r\n            prevEra = era;\r\n\t\t}\r\n    }\r\n\r\n    inline void protectEraRelease(int index, int other, const int tid) {\r\n        auto era = he[tid][other].load(std::memory_order_relaxed);\r\n        if (he[tid][index].load(std::memory_order_relaxed) == era) return;\r\n        he[tid][index].store(era, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /*\r\n     * Does a single iteration. Must be integrated into the algorithm that's using HE.\r\n     * In other words, we must re-check if era has changed\r\n     *\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    inline T* protectPtr(int index, const std::atomic<T*>& atom, uint64_t& prevEra, const int tid) {\r\n        T* ptr = atom.load(std::memory_order_acquire);\r\n        auto era = eraClock.load();\r\n        if (prevEra != era) {\r\n            prevEra = era;\r\n            he[tid][index].store(era, std::memory_order_relaxed);\r\n            std::atomic_thread_fence(std::memory_order_seq_cst);\r\n        }\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * Retire an object (node)\r\n     * Progress Condition: wait-free bounded\r\n     *\r\n     * Doing rlist.erase() is not the most efficient way to remove entries from a std::vector, but ok...\r\n     */\r\n    void retire(T* ptr, const int mytid) {\r\n        auto currEra = eraClock.load();\r\n        ptr->delEra = currEra;\r\n        auto& rlist = retiredList[mytid*CLPAD];\r\n        rlist.push_back(ptr);\r\n        if (eraClock == currEra) eraClock.fetch_add(1);\r\n        for (unsigned iret = 0; iret < rlist.size();) {\r\n            auto obj = rlist[iret];\r\n            if (canDelete(obj, mytid)) {\r\n                rlist.erase(rlist.begin() + iret);\r\n                delete obj;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n\r\nprivate:\r\n    bool canDelete(T* obj, const int mytid) {\r\n        for (int tid = 0; tid < maxThreads; tid++) {\r\n            for (int ihe = 0; ihe < maxHEs; ihe++) {\r\n                const auto era = he[tid][ihe].load(std::memory_order_acquire);\r\n                if (era == NONE || era < obj->newEra || era > obj->delEra) continue;\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n};\r\n\r\n#endif /* _HAZARD_ERAS_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/HazardPointers.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_POINTERS_H_\r\n#define _HAZARD_POINTERS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <vector>\r\n\r\n\r\ntemplate<typename T>\r\nclass HazardPointers {\r\n\r\nprivate:\r\n    static const int      HP_MAX_THREADS = 128;\r\n    static const int      HP_MAX_HPS = 5;     // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HP_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    static const int      MAX_RETIRED = HP_MAX_THREADS*HP_MAX_HPS; // Maximum number of retired objects per thread\r\n\r\n    const int             maxHPs;\r\n    const int             maxThreads;\r\n\r\n    alignas(128) std::atomic<T*>*      hp[HP_MAX_THREADS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<T*>       retiredList[HP_MAX_THREADS*CLPAD];\r\n\r\npublic:\r\n    HazardPointers(int maxHPs=HP_MAX_HPS, int maxThreads=HP_MAX_THREADS) : maxHPs{maxHPs}, maxThreads{maxThreads} {\r\n        for (int it = 0; it < HP_MAX_THREADS; it++) {\r\n            hp[it] = new std::atomic<T*>[CLPAD*2]; // We allocate four cache lines to allow for many hps and without false sharing\r\n            retiredList[it*CLPAD].reserve(MAX_RETIRED);\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[it][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    ~HazardPointers() {\r\n        for (int it = 0; it < HP_MAX_THREADS; it++) {\r\n            delete[] hp[it];\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[it*CLPAD].size(); iret++) {\r\n                delete retiredList[it*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHPs)\r\n     */\r\n    inline void clear(const int tid) {\r\n        for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n            hp[tid][ihp].store(nullptr, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    inline void clearOne(int ihp, const int tid) {\r\n        hp[tid][ihp].store(nullptr, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    inline T* protect(int index, const std::atomic<T*>& atom, const int tid) {\r\n        T* n = nullptr;\r\n        T* ret;\r\n\t\twhile ((ret = atom.load()) != n) {\r\n\t\t\thp[tid][index].store(ret);\r\n\t\t\tn = ret;\r\n\t\t}\r\n\t\treturn ret;\r\n    }\r\n\r\n\t\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    inline T* protectPtr(int index, T* ptr, const int tid) {\r\n        hp[tid][index].store(ptr);\r\n        /*\r\n        // For x86-only implementations, use this instead (it's 2x faster than mfence on x86):\r\n        hp[tid][index].store(ptr, std::memory_order_release);\r\n        __asm__ __volatile__ (\"lock;addl $0,(%%rsp);\" ::: \"cc\",\"memory\") ;\r\n        */\r\n        return ptr;\r\n    }\r\n\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    inline T* protectPtrRelease(int index, T* ptr, const int tid) {\r\n        hp[tid][index].store(ptr, std::memory_order_release);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by the number of threads squared)\r\n     */\r\n    void retire(T* ptr, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(ptr);\r\n        if (retiredList[tid*CLPAD].size() < HP_THRESHOLD_R) return;\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            auto obj = retiredList[tid*CLPAD][iret];\r\n            bool canDelete = true;\r\n            for (int tid = 0; tid < maxThreads && canDelete; tid++) {\r\n                for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n                    if (hp[tid][ihp].load() == obj) {\r\n                        canDelete = false;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            if (canDelete) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                delete obj;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _HAZARD_POINTERS_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/MagedHarrisLinkedListSetHE.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _MAGED_M_MICHAEL_LINKED_LIST_HE_H_\r\n#define _MAGED_M_MICHAEL_LINKED_LIST_HE_H_\r\n\r\n#include <atomic>\r\n#include <thread>\r\n#include <forward_list>\r\n#include <set>\r\n#include <iostream>\r\n#include <string>\r\n#include \"common/HazardEras.hpp\"\r\n\r\n\r\n\r\n/**\r\n * This is the linked list by Maged M. Michael that uses Hazard Eras.\r\n * Lock-Free Linked List as described in Maged M. Michael paper (Figure 7):\r\n * http://www.cs.tau.ac.il/~afek/p73-Lock-Free-HashTbls-michael.pdf\r\n *\r\n * <p>\r\n * This set has three operations:\r\n * <ul>\r\n * <li>add(x)      - Lock-Free\r\n * <li>remove(x)   - Lock-Free\r\n * <li>contains(x) - Lock-Free\r\n * </ul><p>\r\n * <p>\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass MagedHarrisLinkedListSetHE {\r\n\r\nprivate:\r\n    struct Node {\r\n        T key;\r\n        uint64_t newEra;\r\n        uint64_t delEra;\r\n        std::atomic<Node*> next;\r\n\r\n        Node(T key, uint64_t newEra) : key{key}, newEra{newEra}, delEra{0}, next{nullptr}  { }\r\n\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    // Pointers to head and tail sentinel nodes of the list\r\n    std::atomic<Node*> head;\r\n    std::atomic<Node*> tail;\r\n\r\n    const int maxThreads;\r\n\r\n    HazardEras<Node> he {3, maxThreads};\r\n    const int kHp0 = 0; // Protects next\r\n    const int kHp1 = 1; // Protects curr\r\n    const int kHp2 = 2; // Protects prev\r\n\r\npublic:\r\n\r\n    MagedHarrisLinkedListSetHE(const int maxThreads) : maxThreads{maxThreads} {\r\n        head.store(new Node({}, 1));  // Uses K's default constructor\r\n        tail.store(new Node({}, 1));  // Uses K's default constructor\r\n        head.load()->next.store(tail.load());\r\n    }\r\n\r\n\r\n    // We don't expect the destructor to be called if this instance can still be in use\r\n    ~MagedHarrisLinkedListSetHE() {\r\n        Node *prev = head.load();\r\n        Node *node = prev->next.load();\r\n        while (node != nullptr) {\r\n            delete prev;\r\n            prev = node;\r\n            node = prev->next.load();\r\n        }\r\n        delete prev;\r\n    }\r\n\r\n    static std::string className() { return \"MagedHarris-LinkedListSetHE\"; }\r\n\r\n    /*\r\n     * This function is single threaded to be called at the start of the test.\r\n     * It is assumed keys are ordered\r\n     */\r\n    void addAll(T** keys, const int size, const int tid) {\r\n        Node* node = head;\r\n        for(int i=0;i<size;i++){\r\n            T* key = keys[i];\r\n            Node* newNode = new Node(*key, 1);\r\n            node->next.store(newNode, std::memory_order_relaxed);\r\n            node = newNode;\r\n        }\r\n        node->next.store(tail.load(std::memory_order_relaxed), std::memory_order_relaxed);\r\n    }\r\n\r\n    /**\r\n     * This method is named 'Insert()' in the original paper.\r\n     * Taken from Figure 7 of the paper:\r\n     * \"High Performance Dynamic Lock-Free Hash Tables and List-Based Sets\"\r\n     * <p>\r\n     * Progress Condition: Lock-Free\r\n     *\r\n     */\r\n    bool add(T key, const int tid)\r\n    {\r\n        Node *curr, *next;\r\n        std::atomic<Node*> *prev;\r\n        Node* newNode = new Node(key, he.getEra());\r\n        while (true) {\r\n            if (find(&key, &prev, &curr, &next, tid)) {\r\n                delete newNode;              // There is already a matching key\r\n                he.clear(tid);\r\n                return false;\r\n            }\r\n            newNode->next.store(curr, std::memory_order_relaxed);\r\n            Node *tmp = getUnmarked(curr);\r\n            if (prev->compare_exchange_strong(tmp, newNode)) { // seq-cst\r\n                he.clear(tid);\r\n                return true;\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * This method is named 'Delete()' in the original paper.\r\n     * Taken from Figure 7 of the paper:\r\n     * \"High Performance Dynamic Lock-Free Hash Tables and List-Based Sets\"\r\n     */\r\n    bool remove(T key, const int tid)\r\n    {\r\n        Node *curr, *next;\r\n        std::atomic<Node*> *prev;\r\n        while (true) {\r\n            /* Try to find the key in the list. */\r\n            if (!find(&key, &prev, &curr, &next, tid)) {\r\n                he.clear(tid);\r\n                return false;\r\n            }\r\n            /* Mark if needed. */\r\n            Node *tmp = getUnmarked(next);\r\n            if (!curr->next.compare_exchange_strong(tmp, getMarked(next))) {\r\n                continue; /* Another thread interfered. */\r\n            }\r\n\r\n            tmp = getUnmarked(curr);\r\n            if (prev->compare_exchange_strong(tmp, getUnmarked(next))) { /* Unlink */\r\n                he.clear(tid);\r\n                he.retire(getUnmarked(curr), tid); /* Reclaim */\r\n            } else {\r\n                he.clear(tid);\r\n            }\r\n            /*\r\n             * If we want to prevent the possibility of there being an\r\n             * unbounded number of unmarked nodes, add \"else _find(head,key).\"\r\n             * This is not necessary for correctness.\r\n             */\r\n            return true;\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * This is named 'Search()' on the original paper\r\n     * Taken from Figure 7 of the paper:\r\n     * \"High Performance Dynamic Lock-Free Hash Tables and List-Based Sets\"\r\n     * <p>\r\n     * Progress Condition: Lock-Free\r\n     */\r\n    bool contains(T key, const int tid)\r\n    {\r\n        Node *curr, *next;\r\n        std::atomic<Node*> *prev;\r\n        bool isContains = find(&key, &prev, &curr, &next, tid);\r\n        he.clear(tid);\r\n        return isContains;\r\n    }\r\n\r\n\r\nprivate:\r\n\r\n    /**\r\n     * <p>\r\n     * Progress Condition: Lock-Free\r\n     */\r\n    bool find (T* key, std::atomic<Node*> **par_prev, Node **par_curr, Node **par_next, const int tid)\r\n    {\r\n        std::atomic<Node*> *prev;\r\n        Node *curr, *next;\r\n\r\n     try_again:\r\n        prev = &head;\r\n        // Protect curr with a hazard era\r\n        curr = he.get_protected(kHp1, *prev, tid);\r\n        while (true) {\r\n            if (getUnmarked(curr) == nullptr) break; // TODO: Will it ever happen?\r\n            // Protect next with a hazard era.\r\n            next = he.get_protected(kHp0, curr->next, tid);\r\n            if (getUnmarked(curr)->next.load() != next) goto try_again;\r\n            if (getUnmarked(next) == tail.load()) break;\r\n            if (prev->load() != getUnmarked(curr)) goto try_again;\r\n            if (getUnmarked(next) == next) { // !cmark in the paper\r\n                if (!(getUnmarked(curr)->key < *key)) { // Check for null to handle head and tail\r\n                    *par_curr = curr;\r\n                    *par_prev = prev;\r\n                    *par_next = next;\r\n                    return (getUnmarked(curr)->key == *key);\r\n                }\r\n                prev = &getUnmarked(curr)->next;\r\n                he.protectEraRelease(kHp2, kHp1, tid);\r\n            } else {\r\n                // Update the link and retire the node.\r\n                Node *tmp = getUnmarked(curr);\r\n                if (!prev->compare_exchange_strong(tmp, getUnmarked(next))) {\r\n                    goto try_again;\r\n                }\r\n                he.retire(getUnmarked(curr), tid);\r\n            }\r\n            curr = next;\r\n            he.protectEraRelease(kHp1, kHp0, tid);\r\n        }\r\n        *par_curr = curr;\r\n        *par_prev = prev;\r\n        *par_next = next;\r\n        return false;\r\n    }\r\n\r\n    bool isMarked(Node * node) {\r\n    \treturn ((size_t) node & 0x1);\r\n    }\r\n\r\n    Node * getMarked(Node * node) {\r\n    \treturn (Node*)((size_t) node | 0x1);\r\n    }\r\n\r\n    Node * getUnmarked(Node * node) {\r\n    \treturn (Node*)((size_t) node & (~0x1));\r\n    }\r\n};\r\n\r\n#endif /* _MAGED_M_MICHAEL_LINKED_LIST_HE_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/MagedHarrisLinkedListSetHP.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _MAGED_MICHAEL_TIM_HARRIS_LINKED_LIST_HP_H_\r\n#define _MAGED_MICHAEL_TIM_HARRIS_LINKED_LIST_HP_H_\r\n\r\n#include <atomic>\r\n#include <thread>\r\n#include <forward_list>\r\n#include <set>\r\n#include <iostream>\r\n#include <string>\r\n#include \"common/HazardPointers.hpp\"\r\n\r\n\r\n\r\n/**\r\n * This is the linked list by Maged M. Michael that uses Hazard Pointers in\r\n * a correct way because Harris original algorithm with HPs doesn't.\r\n * Lock-Free Linked List as described in Maged M. Michael paper (Figure 4):\r\n * http://www.cs.tau.ac.il/~afek/p73-Lock-Free-HashTbls-michael.pdf\r\n *\r\n * \r\n * <p>\r\n * This set has three operations:\r\n * <ul>\r\n * <li>add(x)      - Lock-Free\r\n * <li>remove(x)   - Lock-Free\r\n * <li>contains(x) - Lock-Free\r\n * </ul><p>\r\n * <p>\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T> \r\nclass MagedHarrisLinkedListSetHP {\r\n\r\nprivate:\r\n    struct Node {\r\n        T key;\r\n        std::atomic<Node*> next;\r\n\r\n        Node(T key) : key{key}, next{nullptr} { }\r\n\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    // Pointers to head and tail sentinel nodes of the list\r\n    std::atomic<Node*> head;\r\n    std::atomic<Node*> tail;\r\n\r\n    const int maxThreads;\r\n\r\n    // We need 3 hazard pointers\r\n    HazardPointers<Node> hp {3, maxThreads};\r\n    const int kHp0 = 0; // Protects next\r\n    const int kHp1 = 1; // Protects curr\r\n    const int kHp2 = 2; // Protects prev\r\n\r\npublic:\r\n\r\n    MagedHarrisLinkedListSetHP(const int maxThreads) : maxThreads{maxThreads} {\r\n        head.store(new Node({}));\r\n        tail.store(new Node({}));\r\n        head.load()->next.store(tail.load());\r\n    }\r\n\r\n\r\n    // We don't expect the destructor to be called if this instance can still be in use\r\n    ~MagedHarrisLinkedListSetHP() {\r\n        Node *prev = head.load();\r\n        Node *node = prev->next.load();\r\n        while (node != nullptr) {\r\n            delete prev;\r\n            prev = node;\r\n            node = prev->next.load();\r\n        }\r\n        delete prev;\r\n    }\r\n\r\n    static std::string className() { return \"MagedHarris-LinkedListSetHP\"; }\r\n\r\n    /*\r\n     * This function is single threaded to be called at the start of the test.\r\n     * It is assumed keys are ordered\r\n     */\r\n    void addAll(T** keys, const int size, const int tid) {\r\n        Node* node = head;\r\n        for(int i=0;i<size;i++){\r\n            T* key = keys[i];\r\n            Node* newNode = new Node(*key);\r\n            node->next.store(newNode, std::memory_order_relaxed);\r\n            node = newNode;\r\n        }\r\n        node->next.store(tail.load(std::memory_order_relaxed), std::memory_order_relaxed);\r\n    }\r\n\r\n    /**\r\n     * This method is named 'Insert()' in the original paper.\r\n     * Taken from Figure 7 of the paper:\r\n     * \"High Performance Dynamic Lock-Free Hash Tables and List-Based Sets\"\r\n     * <p>\r\n     * Progress Condition: Lock-Free\r\n     *\r\n     */\r\n    bool add(T key, const int tid)\r\n    {\r\n        Node *curr, *next;\r\n        std::atomic<Node*> *prev;\r\n        Node* newNode = new Node(key);\r\n        while (true) {\r\n            if (find(&key, &prev, &curr, &next, tid)) {\r\n                delete newNode;              // There is already a matching key\r\n                hp.clear(tid);\r\n                return false;\r\n            }\r\n            newNode->next.store(curr, std::memory_order_relaxed);\r\n            Node *tmp = getUnmarked(curr);\r\n            if (prev->compare_exchange_strong(tmp, newNode)) { // seq-cst\r\n                hp.clear(tid);\r\n                return true;\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * This method is named 'Delete()' in the original paper.\r\n     * Taken from Figure 7 of the paper:\r\n     * \"High Performance Dynamic Lock-Free Hash Tables and List-Based Sets\"\r\n     */\r\n    bool remove(T key, const int tid)\r\n    {\r\n        Node *curr, *next;\r\n        std::atomic<Node*> *prev;\r\n        while (true) {\r\n            /* Try to find the key in the list. */\r\n            if (!find(&key, &prev, &curr, &next, tid)) {\r\n                hp.clear(tid);\r\n                return false;\r\n            }\r\n            /* Mark if needed. */\r\n            Node *tmp = getUnmarked(next);\r\n            if (!curr->next.compare_exchange_strong(tmp, getMarked(next))) {\r\n                continue; /* Another thread interfered. */\r\n            }\r\n\r\n            tmp = getUnmarked(curr);\r\n            if (prev->compare_exchange_strong(tmp, getUnmarked(next))) { /* Unlink */\r\n                hp.clear(tid);\r\n                hp.retire(getUnmarked(curr), tid); /* Reclaim */\r\n            } else {\r\n                hp.clear(tid);\r\n            }\r\n            /*\r\n             * If we want to prevent the possibility of there being an\r\n             * unbounded number of unmarked nodes, add \"else _find(head,key).\"\r\n             * This is not necessary for correctness.\r\n             */\r\n            return true;\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * This is named 'Search()' on the original paper\r\n     * Taken from Figure 7 of the paper:\r\n     * \"High Performance Dynamic Lock-Free Hash Tables and List-Based Sets\"\r\n     * <p>\r\n     * Progress Condition: Lock-Free\r\n     */\r\n    bool contains(T key, const int tid)\r\n    {\r\n        Node *curr, *next;\r\n        std::atomic<Node*> *prev;\r\n        bool isContains = find(&key, &prev, &curr, &next, tid);\r\n        hp.clear(tid);\r\n        return isContains;\r\n    }\r\n\r\n\r\nprivate:\r\n\r\n    /**\r\n     * TODO: This needs to be code reviewed... it's not production-ready\r\n     * <p>\r\n     * Progress Condition: Lock-Free\r\n     */\r\n    bool find (T* key, std::atomic<Node*> **par_prev, Node **par_curr, Node **par_next, const int tid)\r\n    {\r\n        std::atomic<Node*> *prev;\r\n        Node *curr, *next;\r\n\r\n     try_again:\r\n        prev = &head;\r\n        curr = prev->load();\r\n        // Protect curr with a hazard pointer.\r\n        hp.protectPtr(kHp1, curr, tid);\r\n        if (prev->load() != getUnmarked(curr)) goto try_again;\r\n        while (true) {\r\n            if (getUnmarked(curr) == nullptr) break;\r\n            // Protect next with a hazard pointer.\r\n            next = curr->next.load();\r\n            hp.protectPtr(kHp0, getUnmarked(next), tid);\r\n            if (getUnmarked(curr)->next.load() != next) goto try_again;\r\n            if (getUnmarked(next) == tail.load()) break;\r\n            if (prev->load() != getUnmarked(curr)) goto try_again;\r\n            if (getUnmarked(next) == next) { // !cmark in the paper\r\n                if (!(getUnmarked(curr)->key < *key)) { // Check for null to handle head and tail\r\n                    *par_curr = curr;\r\n                    *par_prev = prev;\r\n                    *par_next = next;\r\n                    return (getUnmarked(curr)->key == *key);\r\n                }\r\n                prev = &getUnmarked(curr)->next;\r\n                hp.protectRelease(kHp2, getUnmarked(curr), tid);\r\n            } else {\r\n                // Update the link and retire the node.\r\n                Node *tmp = getUnmarked(curr);\r\n                if (!prev->compare_exchange_strong(tmp, getUnmarked(next))) {\r\n                    goto try_again;\r\n                }\r\n                hp.retire(getUnmarked(curr), tid);\r\n            }\r\n            curr = next;\r\n            hp.protectRelease(kHp1, getUnmarked(next), tid);\r\n        }\r\n        *par_curr = curr;\r\n        *par_prev = prev;\r\n        *par_next = next;\r\n        return false;\r\n    }\r\n\r\n    bool isMarked(Node * node) {\r\n    \treturn ((size_t) node & 0x1);\r\n    }\r\n\r\n    Node * getMarked(Node * node) {\r\n    \treturn (Node*)((size_t) node | 0x1);\r\n    }\r\n\r\n    Node * getUnmarked(Node * node) {\r\n    \treturn (Node*)((size_t) node & (~0x1));\r\n    }\r\n};\r\n\r\n#endif /* _MAGED_MICHAEL_TIM_HARRIS_LINKED_LIST_HP_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/OFLFLinkedListSet.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _ONEFILE_LF_LINKED_LIST_SET_H_\r\n#define _ONEFILE_LF_LINKED_LIST_SET_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"stms/OneFileLF.hpp\"\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for One-File STM (Lock-Free) </h1>\r\n */\r\ntemplate<typename T>\r\nclass OFLFLinkedListSet : public oflf::tmbase {\r\n\r\nprivate:\r\n    struct Node : public oflf::tmbase {\r\n        T key {};\r\n        oflf::tmtype<Node*> next {nullptr};\r\n        Node() {}\r\n        Node(T key) : key{key} { }\r\n    };\r\n\r\n    alignas(128) oflf::tmtype<Node*>  head {nullptr};\r\n    alignas(128) oflf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    OFLFLinkedListSet(unsigned int maxThreads=0) {\r\n        oflf::updateTx([this] () {\r\n            Node* lhead = oflf::tmNew<Node>();\r\n            Node* ltail = oflf::tmNew<Node>();\r\n            head = lhead;\r\n            head->next = ltail;\r\n            tail = ltail;\r\n        });\r\n    }\r\n\r\n\r\n    ~OFLFLinkedListSet() {\r\n        oflf::updateTx([this] () {\r\n            // Delete all the nodes in the list\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            while (node != tail) {\r\n                oflf::tmDelete(prev);\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n            oflf::tmDelete(prev);\r\n            oflf::tmDelete(tail.pload());\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return oflf::OneFileLF::className() + \"-LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T key, const int tid=0) {\r\n        return oflf::updateTx<bool>([this,key] () -> bool {\r\n            Node* newNode = oflf::tmNew<Node>(key);\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            Node* ltail = tail;\r\n            while (true) {\r\n                if (node == ltail) break;\r\n                T nkey = node->key;\r\n                if (key == nkey) {\r\n                    oflf::tmDelete(newNode); // If the key was already in the set, free the node that was never used\r\n                    return false;\r\n                }\r\n                if (nkey < key) break;\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n            prev->next = newNode;\r\n            newNode->next = node;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T key, const int tid=0) {\r\n        return oflf::updateTx<bool>([this,key] () -> bool {\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            Node* ltail = tail;\r\n            while (true) {\r\n                if (node == ltail) return false;\r\n                T nkey = node->key;\r\n                if (key == nkey) {\r\n                    prev->next = node->next;\r\n                    oflf::tmDelete(node);\r\n                    return true;\r\n                }\r\n                if (nkey < key) return false;\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T key, const int tid=0) {\r\n        return oflf::readTx<bool>([this,key] () -> bool {\r\n            Node* node = head->next;\r\n            Node* ltail = tail;\r\n            while (true) {\r\n                if (node == ltail) return false;\r\n                T nkey = node->key;\r\n                if (key == nkey) return true;\r\n                if (nkey < key) return false;\r\n                node = node->next;\r\n            }\r\n        });\r\n    }\r\n\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n        return true;\r\n    }\r\n};\r\n\r\n#endif /* _ONE_FILE_LF_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/OFWFLinkedListSet.hpp",
    "content": " /*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _ONEFILE_WF_LINKED_LIST_SET_H_\r\n#define _ONEFILE_WF_LINKED_LIST_SET_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"stms/OneFileWF.hpp\"\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for One-File STM (wait-Free) </h1>\r\n */\r\ntemplate<typename T>\r\nclass OFWFLinkedListSet : public ofwf::tmbase {\r\n\r\nprivate:\r\n    struct Node : public ofwf::tmbase {\r\n        T key {};\r\n        ofwf::tmtype<Node*> next {nullptr};\r\n        Node(T key) : key{key} { }\r\n        Node() {}\r\n    };\r\n\r\n    alignas(128) ofwf::tmtype<Node*>  head {nullptr};\r\n    alignas(128) ofwf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    OFWFLinkedListSet(unsigned int maxThreads=0) {\r\n        ofwf::updateTx([this] () {\r\n            Node* lhead = ofwf::tmNew<Node>();\r\n            Node* ltail = ofwf::tmNew<Node>();\r\n            head = lhead;\r\n            head->next = ltail;\r\n            tail = ltail;\r\n        });\r\n    }\r\n\r\n\r\n    ~OFWFLinkedListSet() {\r\n        ofwf::updateTx([this] () {\r\n            // Delete all the nodes in the list\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            while (node != tail) {\r\n                ofwf::tmDelete(prev);\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n            ofwf::tmDelete(prev);\r\n            ofwf::tmDelete(tail.pload());\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return ofwf::OneFileWF::className() + \"-LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T key, const int tid=0) {\r\n        return ofwf::updateTx<bool>([this,key] () {\r\n            Node* newNode = ofwf::tmNew<Node>(key);\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            Node* ltail = tail;\r\n            while (true) {\r\n                if (node == ltail) break;\r\n                T nkey = node->key;\r\n                if (key == nkey) {\r\n                    ofwf::tmDelete(newNode); // If the key was already in the set, free the node that was never used\r\n                    return false;\r\n                }\r\n                if (nkey < key) break;\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n            prev->next = newNode;\r\n            newNode->next = node;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T key, const int tid=0) {\r\n        return ofwf::updateTx<bool>([this,key] () {\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            Node* ltail = tail;\r\n            while (true) {\r\n                if (node == ltail) return false;\r\n                T nkey = node->key;\r\n                if (key == nkey) {\r\n                    prev->next = node->next;\r\n                    ofwf::tmDelete(node);\r\n                    return true;\r\n                }\r\n                if (nkey < key) return false;\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T key, const int tid=0) {\r\n        return ofwf::readTx<bool>([this,key] () {\r\n            Node* node = head->next;\r\n            Node* ltail = tail;\r\n            while (true) {\r\n                if (node == ltail) return false;\r\n                T nkey = node->key;\r\n                if (key == nkey) return true;\r\n                if (nkey < key) return false;\r\n                node = node->next;\r\n            }\r\n        });\r\n    }\r\n\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n        return true;\r\n    }\r\n};\r\n\r\n#endif /* _ONE_FILE_WF_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/STMLinkedListSet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _STM_LINKED_LIST_SET_H_\r\n#define _STM_LINKED_LIST_SET_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n//#include \"stms/OneFileLF.hpp\"\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for an STM </h1>\r\n *\r\n * TODO\r\n *\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T, typename TM, template<typename> class TMTYPE, template<typename> class TMBASE>\r\nclass STMLinkedListSet : public TMBASE {\r\n\r\nprivate:\r\n    struct Node : public TMBASE {\r\n        T* key;\r\n        TMTYPE<Node*> next;\r\n        Node(T* key) : key{key}, next{nullptr} { }\r\n    };\r\n\r\n    alignas(128) TMTYPE<Node*>  head {nullptr};\r\n    alignas(128) TMTYPE<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    STMLinkedListSet(unsigned int maxThreads=0) {\r\n        Node* lhead = new Node(nullptr);\r\n        Node* ltail = new Node(nullptr);\r\n        head = lhead;\r\n        head->next = ltail;\r\n        tail = ltail;\r\n    }\r\n\r\n\r\n    ~STMLinkedListSet() {\r\n        // Delete all the nodes in the list\r\n        Node* prev = head;\r\n        Node* node = prev->next;\r\n        while (node != tail) {\r\n            delete prev;\r\n            prev = node;\r\n            node = node->next;\r\n        }\r\n        delete prev;\r\n        delete tail;\r\n    }\r\n\r\n\r\n    static std::string className() { return TM::className() + \"-LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T* key, const int tid=0) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        return TM::updateTx<bool>([this,key] () -> bool {\r\n                Node* newNode = TM::tmNew<Node>(key);\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) break;\r\n                    if (*key == *node->key) {\r\n                        TM::tmDelete(newNode); // If the key was already in the set, free the node that was never used\r\n                        return false;\r\n                    }\r\n                    if (*(node->key) < *key) break;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                return true;\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T* key, const int tid=0) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        return TM::updateTx<bool>([this,key] () -> bool {\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (*key == *node->key) {\r\n                        prev->next = node->next;\r\n                        TM::tmDelete(node);\r\n                        return true;\r\n                    }\r\n                    if (*(node->key) < *key) return false;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T* key, const int tid=0) {\r\n        if (key == nullptr) throw std::invalid_argument(\"key can not be nullptr\");\r\n        return TM::readTx<bool>([this,key] () -> bool {\r\n                Node* node = head->next;\r\n                while (true) {\r\n                    if (node == tail) return false;\r\n                    if (*key == *node->key) return true;\r\n                    if (*(node->key) < *key) return false;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(keys[i], tid);\r\n    }\r\n};\r\n\r\n#endif /* _ONE_FILE_LF_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/linkedlists/TinySTMLinkedListSet.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _TINY_STM_LINKED_LIST_SET_H_\r\n#define _TINY_STM_LINKED_LIST_SET_H_\r\n\r\n#include \"stms/TinySTM.hpp\"\r\n\r\n\r\n/**\r\n * <h1> A Linked List Set for usage with TinySTM </h1>\r\n */\r\ntemplate<typename T>\r\nclass TinySTMLinkedListSet : public tinystm::tmbase {\r\n\r\nprivate:\r\n    struct Node : public tinystm::tmbase {\r\n        T key;\r\n        tinystm::tmtype<Node*> next{nullptr};\r\n        Node() {}\r\n        Node(T key) : key{key} { }\r\n    };\r\n\r\n    alignas(128) tinystm::tmtype<Node*>  head {nullptr};\r\n    alignas(128) tinystm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    TinySTMLinkedListSet(unsigned int maxThreads=0) {\r\n        tinystm::updateTx<bool>([this] () {\r\n            Node* lhead = tinystm::tmNew<Node>();\r\n            Node* ltail = tinystm::tmNew<Node>();\r\n            head = lhead;\r\n            head->next = ltail;\r\n            tail = ltail;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    ~TinySTMLinkedListSet() {\r\n        tinystm::updateTx<bool>([this] () {\r\n            // Delete all the nodes in the list\r\n            Node* prev = head;\r\n            Node* node = prev->next;\r\n            while (node != tail) {\r\n                tinystm::tmDelete(prev);\r\n                prev = node;\r\n                node = node->next;\r\n            }\r\n            tinystm::tmDelete(prev);\r\n            tinystm::tmDelete(tail.load());\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"TinySTM-LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(T key, const int tid=0) {\r\n        return tinystm::updateTx<bool>([this,key] () {\r\n                Node* newNode = tinystm::tmNew<Node>(key);\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                Node* ltail = tail;\r\n                while (true) {\r\n                    if (node == ltail) break;\r\n                    T nkey = node->key;\r\n                    if (key == nkey) {\r\n                        tinystm::tmDelete(newNode); // If the key was already in the set, free the node that was never used\r\n                        return false;\r\n                    }\r\n                    if (nkey < key) break;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n                return true;\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(T key, const int tid=0) {\r\n        return tinystm::updateTx<bool>([this,key] () {\r\n                Node* prev = head;\r\n                Node* node = prev->next;\r\n                Node* ltail = tail;\r\n                while (true) {\r\n                    if (node == ltail) return false;\r\n                    T nkey = node->key;\r\n                    if (key == nkey) {\r\n                        prev->next = node->next;\r\n                        tinystm::tmDelete(node);\r\n                        return true;\r\n                    }\r\n                    if (nkey < key) return false;\r\n                    prev = node;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(T key, const int tid=0) {\r\n        return tinystm::readTx<bool>([this,key] () {\r\n                Node* node = head->next;\r\n                Node* ltail = tail;\r\n                while (true) {\r\n                    if (node == ltail) return false;\r\n                    T nkey = node->key;\r\n                    if (key == nkey) return true;\r\n                    if (nkey < key) return false;\r\n                    node = node->next;\r\n                }\r\n            });\r\n    }\r\n\r\n\r\n    bool addAll(T** keys, int size, const int tid) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n};\r\n\r\n#endif /* _TINY_STM_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/CRWWPLinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _CRWWP_LINKED_LIST_QUEUE_H_\r\n#define _CRWWP_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"../../stms/CRWWPSTM.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using C-RW-WP STM </h1>\r\n *\r\n *\r\n * TODO\r\n *\r\n *\r\n * enqueue algorithm: sequential implementation + MWC\r\n * dequeue algorithm: sequential implementation + MWC\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into MWC)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass CRWWPLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node : crwwpstm::tmbase {\r\n        T* item;\r\n        crwwpstm::tmtype<Node*> next;\r\n        Node(T* userItem) : item{userItem}, next{nullptr} { }\r\n    };\r\n\r\n    alignas(128) crwwpstm::tmtype<Node*>  head {nullptr};\r\n    alignas(128) crwwpstm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    CRWWPLinkedListQueue(unsigned int maxThreads=0) {\r\n        Node* sentinelNode = new Node(nullptr);\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    ~CRWWPLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        delete lhead;\r\n    }\r\n\r\n\r\n    static std::string className() { return \"CRWWP-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* newNode = crwwpstm::tmNew<Node>(item); // Let's allocate outside the transaction, less overhead\r\n        return crwwpstm::updateTx<bool>([this,&newNode] () -> bool {\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return crwwpstm::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return nullptr;\r\n            head = lhead->next;\r\n            crwwpstm::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _CRWWP_TM_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/ESTMArrayLinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _ELASTIC_STM_ARRAY_LINKED_LIST_QUEUE_H_\r\n#define _ELASTIC_STM_ARRAY_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/ESTM.hpp\"\r\n\r\n/**\r\n * <h1> An Array Linked List Queue using OneFile STM (Wait-Free) </h1>\r\n *\r\n * TODO\r\n *\r\n *\r\n * enqueue algorithm: sequential implementation + MWC\r\n * dequeue algorithm: sequential implementation + MWC\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into MWC)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass ESTMArrayLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node : estm::tmbase {\r\n        static const int ITEM_NUM = 1024;\r\n        estm::tmtype<uint64_t> headidx {0};\r\n        estm::tmtype<T*>       items[ITEM_NUM];\r\n        estm::tmtype<uint64_t> tailidx {0};\r\n        estm::tmtype<Node*>    next {nullptr};\r\n        Node(T* item) {\r\n            items[0] = item;\r\n            tailidx = 1;\r\n            headidx = 0;\r\n            for (int i = 1; i < ITEM_NUM; i++) items[i] = nullptr;\r\n        }\r\n    };\r\n\r\n    alignas(128) estm::tmtype<Node*>  head {nullptr};\r\n    alignas(128) estm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    ESTMArrayLinkedListQueue(unsigned int maxThreads=0) {\r\n        estm::updateTx<bool>([this] () {\r\n            Node* sentinelNode = estm::tmNew<Node>(nullptr);\r\n            sentinelNode->tailidx = 0;\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    ~ESTMArrayLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        estm::updateTx<bool>([this] () {\r\n            Node* lhead = head;\r\n            estm::tmDelete(lhead);\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"ESTM-ArrayLinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return estm::updateTx<bool>([this,item] () -> bool {\r\n            Node* ltail = tail;\r\n            uint64_t ltailidx = ltail->tailidx;\r\n            if (ltailidx < Node::ITEM_NUM) {\r\n                ltail->items[ltailidx] = item;\r\n                ++ltail->tailidx;\r\n                return true;\r\n            }\r\n            Node* newNode = estm::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return estm::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            uint64_t lheadidx = lhead->headidx;\r\n            // Check if queue is empty\r\n            if (lhead == tail && lheadidx == tail->tailidx) return nullptr;\r\n            if (lheadidx < Node::ITEM_NUM) {\r\n                ++lhead->headidx;\r\n                return lhead->items[lheadidx];\r\n            }\r\n            lhead = lhead->next;\r\n            estm::tmDelete(head.load());\r\n            head = lhead;\r\n            ++lhead->headidx;\r\n            return lhead->items[0];\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _OF_WF_ARRAY_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/ESTMLinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _ELASTIC_STM_LINKED_LIST_QUEUE_H_\r\n#define _ELASTIC_STM_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/ESTM.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using Elastic STM (blocking) </h1>\r\n *\r\n *\r\n * TODO\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass ESTMLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node : estm::tmbase {\r\n        T* item;\r\n        estm::tmtype<Node*> next {nullptr};\r\n        Node(T* userItem) : item{userItem} { }\r\n    };\r\n\r\n    alignas(128) estm::tmtype<Node*>  head {nullptr};\r\n    alignas(128) estm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    ESTMLinkedListQueue(unsigned int maxThreads=0) {\r\n        estm::updateTx<bool>([this] () {\r\n            Node* sentinelNode = estm::tmNew<Node>(nullptr);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    ~ESTMLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        estm::updateTx<bool>([this] () {\r\n            Node* lhead = head;\r\n            estm::tmDelete(lhead);\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"ESTM-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return estm::updateTx<bool>([this,item] () -> bool {\r\n            Node* newNode = estm::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return estm::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return nullptr;\r\n            head = lhead->next;\r\n            estm::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _ESTM_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/FAAArrayQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _FAA_ARRAY_QUEUE_HP_H_\r\n#define _FAA_ARRAY_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"HazardPointers.hpp\"\r\n\r\n\r\n/**\r\n * <h1> Fetch-And-Add Array Queue </h1>\r\n *\r\n * Each node has one array but we don't search for a vacant entry. Instead, we\r\n * use FAA to obtain an index in the array, for enqueueing or dequeuing.\r\n *\r\n * There are some similarities between this queue and the basic queue in YMC:\r\n * http://chaoran.me/assets/pdf/wfq-ppopp16.pdf\r\n * but it's not the same because the queue in listing 1 is obstruction-free, while\r\n * our algorithm is lock-free.\r\n * In FAAArrayQueue eventually a new node will be inserted (using Michael-Scott's\r\n * algorithm) and it will have an item pre-filled in the first position, which means\r\n * that at most, after BUFFER_SIZE steps, one item will be enqueued (and it can then\r\n * be dequeued). This kind of progress is lock-free.\r\n *\r\n * Each entry in the array may contain one of three possible values:\r\n * - A valid item that has been enqueued;\r\n * - nullptr, which means no item has yet been enqueued in that position;\r\n * - taken, a special value that means there was an item but it has been dequeued;\r\n *\r\n * Enqueue algorithm: FAA + CAS(null,item)\r\n * Dequeue algorithm: FAA + CAS(item,taken)\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Pointers (lock-free)\r\n * Uncontended enqueue: 1 FAA + 1 CAS + 1 HP\r\n * Uncontended dequeue: 1 FAA + 1 CAS + 1 HP\r\n *\r\n *\r\n * <p>\r\n * Lock-Free Linked List as described in Maged Michael and Michael Scott's paper:\r\n * {@link http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf}\r\n * <a href=\"http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf\">\r\n * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms</a>\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass FAAArrayQueue {\r\n    static const long BUFFER_SIZE = 1024;  // 1024\r\n\r\nprivate:\r\n    struct Node {\r\n        alignas(128) std::atomic<int>   deqidx;\r\n        alignas(128) std::atomic<T*>    items[BUFFER_SIZE];\r\n        alignas(128) std::atomic<int>   enqidx;\r\n        alignas(128) std::atomic<Node*> next;\r\n\r\n        // Start with the first entry pre-filled and enqidx at 1\r\n        Node(T* item) : deqidx{0}, enqidx{1}, next{nullptr} {\r\n            items[0].store(item, std::memory_order_relaxed);\r\n            for (long i = 1; i < BUFFER_SIZE; i++) {\r\n                items[i].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    bool casTail(Node *cmp, Node *val) {\r\n\t\treturn tail.compare_exchange_strong(cmp, val);\r\n\t}\r\n\r\n    bool casHead(Node *cmp, Node *val) {\r\n        return head.compare_exchange_strong(cmp, val);\r\n    }\r\n\r\n    // Pointers to head and tail of the list\r\n    alignas(128) std::atomic<Node*> head;\r\n    alignas(128) std::atomic<Node*> tail;\r\n\r\n    static const int MAX_THREADS = 128;\r\n    const int maxThreads;\r\n\r\n    T* taken = (T*)new int();  // Muuuahahah !\r\n\r\n    // We need just one hazard pointer\r\n    HazardPointers<Node> hp {1, maxThreads};\r\n    const int kHpTail = 0;\r\n    const int kHpHead = 0;\r\n\r\n\r\npublic:\r\n    FAAArrayQueue(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        Node* sentinelNode = new Node(nullptr);\r\n        sentinelNode->enqidx.store(0, std::memory_order_relaxed);\r\n        head.store(sentinelNode, std::memory_order_relaxed);\r\n        tail.store(sentinelNode, std::memory_order_relaxed);\r\n    }\r\n\r\n\r\n    ~FAAArrayQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        delete head.load();            // Delete the last node\r\n        delete (int*)taken;\r\n    }\r\n\r\n\r\n    static std::string className() { return \"FAAArrayQueue\"; }\r\n\r\n\r\n    void enqueue(T* item, const int tid) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        while (true) {\r\n            Node* ltail = hp.protect(kHpTail, tail, tid);\r\n            const int idx = ltail->enqidx.fetch_add(1);\r\n            if (idx > BUFFER_SIZE-1) { // This node is full\r\n                if (ltail != tail.load()) continue;\r\n                Node* lnext = ltail->next.load();\r\n                if (lnext == nullptr) {\r\n                    Node* newNode = new Node(item);\r\n                    if (ltail->casNext(nullptr, newNode)) {\r\n                        casTail(ltail, newNode);\r\n                        hp.clear(tid);\r\n                        return;\r\n                    }\r\n                    delete newNode;\r\n                } else {\r\n                    casTail(ltail, lnext);\r\n                }\r\n                continue;\r\n            }\r\n            T* itemnull = nullptr;\r\n            if (ltail->items[idx].compare_exchange_strong(itemnull, item)) {\r\n                hp.clear(tid);\r\n                return;\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    T* dequeue(const int tid) {\r\n        while (true) {\r\n            Node* lhead = hp.protect(kHpHead, head, tid);\r\n            if (lhead->deqidx.load() >= lhead->enqidx.load() && lhead->next.load() == nullptr) break;\r\n            const int idx = lhead->deqidx.fetch_add(1);\r\n            if (idx > BUFFER_SIZE-1) { // This node has been drained, check if there is another one\r\n                Node* lnext = lhead->next.load();\r\n                if (lnext == nullptr) break;  // No more nodes in the queue\r\n                if (casHead(lhead, lnext)) hp.retire(lhead, tid);\r\n                continue;\r\n            }\r\n            T* item = lhead->items[idx].load();\r\n            if (item != nullptr) {\r\n                hp.clear(tid);\r\n                return item;\r\n            }\r\n            item = lhead->items[idx].exchange(taken);\r\n            if (item == nullptr) continue;\r\n            hp.clear(tid);\r\n            return item;\r\n        }\r\n        hp.clear(tid);\r\n        return nullptr;\r\n    }\r\n};\r\n\r\n#endif /* _FAA_ARRAY_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/HazardPointers.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_POINTERS_H_\r\n#define _HAZARD_POINTERS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <functional>\r\n#include <vector>\r\n\r\n\r\ntemplate<typename T>\r\nclass HazardPointers {\r\n\r\nprivate:\r\n    static const int      HP_MAX_THREADS = 128;\r\n    static const int      HP_MAX_HPS = 128;     // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HP_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    static const int      MAX_RETIRED = HP_MAX_THREADS*HP_MAX_HPS; // Maximum number of retired objects per thread\r\n\r\n    const int             maxHPs;\r\n    const int             maxThreads;\r\n\r\n    alignas(128) std::atomic<T*>*      hp[HP_MAX_THREADS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<T*>       retiredList[HP_MAX_THREADS*CLPAD];\r\n    std::function<void(T*,int)> defdeleter = [](T* t, int tid){ delete t; };\r\n    std::function<void(T*,int)>& deleter;\r\npublic:\r\n\r\n    HazardPointers(int maxHPs, int maxThreads) : maxHPs{maxHPs}, maxThreads{maxThreads}, deleter{defdeleter} {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            hp[ithread] = new std::atomic<T*>[HP_MAX_HPS];\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[ithread][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    HazardPointers(int maxHPs, int maxThreads, std::function<void(T*,int)>& deleter) : maxHPs{maxHPs}, maxThreads{maxThreads}, deleter{deleter} {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            hp[ithread] = new std::atomic<T*>[HP_MAX_HPS];\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[ithread][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    ~HazardPointers() {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            delete[] hp[ithread];\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[ithread*CLPAD].size(); iret++) {\r\n                delete retiredList[ithread*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHPs)\r\n     */\r\n    void clear(const int tid) {\r\n        for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n            hp[tid][ihp].store(nullptr, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    void clearOne(int ihp, const int tid) {\r\n        hp[tid][ihp].store(nullptr, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* protect(int index, const std::atomic<T*>& atom, const int tid) {\r\n        T* n = nullptr;\r\n        T* ret;\r\n\t\twhile ((ret = atom.load()) != n) {\r\n\t\t\thp[tid][index].store(ret);\r\n\t\t\tn = ret;\r\n\t\t}\r\n\t\treturn ret;\r\n    }\r\n\r\n    T* get(int index, const int tid){\r\n        return hp[tid][index].load();\r\n    }\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtr(int index, T* ptr, const int tid) {\r\n        hp[tid][index].store(ptr);\r\n        return ptr;\r\n    }\r\n\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtrRelease(int index, T* ptr, const int tid) {\r\n        hp[tid][index].store(ptr, std::memory_order_release);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by the number of threads squared)\r\n     */\r\n    void retire(T* ptr, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(ptr);\r\n        if (retiredList[tid*CLPAD].size() < HP_THRESHOLD_R) return;\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            auto obj = retiredList[tid*CLPAD][iret];\r\n            bool canDelete = true;\r\n            for (int tid = 0; tid < maxThreads && canDelete; tid++) {\r\n                for (int ihp = maxHPs-1; ihp >= 0; ihp--) {\r\n                    if (hp[tid][ihp].load() == obj) {\r\n                        canDelete = false;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            if (canDelete) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                deleter(obj,tid);\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _HAZARD_POINTERS_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/HazardPointersSimQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_POINTERS_SIM_QUEUE_H_\r\n#define _HAZARD_POINTERS_SIM_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <functional>\r\n#include <vector>\r\n\r\n\r\n// TODO: use std::vector instead of arrays for the retired objects (keep the padding)\r\ntemplate<typename T>\r\nclass HazardPointersSimQueue {\r\n\r\nprivate:\r\n    static const int      HP_MAX_THREADS = 128;\r\n    static const int      HP_MAX_HPS = 11;     // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HP_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    static const int      MAX_RETIRED = HP_MAX_THREADS*HP_MAX_HPS; // Maximum number of retired objects per thread\r\n\r\n    const int             maxHPs;\r\n    const int             maxThreads;\r\n\r\n    std::atomic<T*>       hp[HP_MAX_THREADS*CLPAD][HP_MAX_HPS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    std::vector<T*>       retiredList[HP_MAX_THREADS*CLPAD];\r\n\r\n    std::function<bool(T*)> findPtr;\r\n\r\npublic:\r\n    HazardPointersSimQueue(std::function<bool(T*)>& find, int maxHPs=HP_MAX_HPS, int maxThreads=HP_MAX_THREADS) : maxHPs{maxHPs}, maxThreads{maxThreads} {\r\n        findPtr = find;\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[ithread*CLPAD][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    ~HazardPointersSimQueue() {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[ithread*CLPAD].size(); iret++) {\r\n                delete retiredList[ithread*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHPs)\r\n     */\r\n    void clear(const int tid) {\r\n        for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n            hp[tid*CLPAD][ihp].store(nullptr, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    void clearOne(int ihp, const int tid) {\r\n        hp[tid*CLPAD][ihp].store(nullptr, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* protect(int index, const std::atomic<T*>& atom, const int tid) {\r\n        T* n = nullptr;\r\n        T* ret;\r\n\t\twhile ((ret = atom.load()) != n) {\r\n\t\t\thp[tid*CLPAD][index].store(ret);\r\n\t\t\tn = ret;\r\n\t\t}\r\n\t\treturn ret;\r\n    }\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtr(int index, T* ptr, const int tid) {\r\n        hp[tid*CLPAD][index].store(ptr);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectRelease(int index, T* ptr, const int tid) {\r\n        hp[tid*CLPAD][index].store(ptr, std::memory_order_release);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free bounded (by the number of threads squared)\r\n     */\r\n    void retire(T* ptr, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(ptr);\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            auto obj = retiredList[tid*CLPAD][iret];\r\n            if (findPtr(obj)) {\r\n                iret++;\r\n                continue;\r\n            }\r\n            bool canDelete = true;\r\n            for (int tid = 0; tid < maxThreads && canDelete; tid++) {\r\n                for (int ihp = maxHPs-1; ihp >= 0; ihp--) {\r\n                    if (hp[tid*CLPAD][ihp].load() == obj) {\r\n                        canDelete = false;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            if (canDelete) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                delete obj;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _HAZARD_POINTERS_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/LCRQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _LCRQ_QUEUE_HP_H_\r\n#define _LCRQ_QUEUE_HP_H_\r\n\r\n\r\n#include <atomic>\r\n#include \"HazardPointers.hpp\"\r\n\r\n// CAS2 macro\r\n\r\n#define __CAS2(ptr, o1, o2, n1, n2)                             \\\r\n({                                                              \\\r\n    char __ret;                                                 \\\r\n    __typeof__(o2) __junk;                                      \\\r\n    __typeof__(*(ptr)) __old1 = (o1);                           \\\r\n    __typeof__(o2) __old2 = (o2);                               \\\r\n    __typeof__(*(ptr)) __new1 = (n1);                           \\\r\n    __typeof__(o2) __new2 = (n2);                               \\\r\n    asm volatile(\"lock cmpxchg16b %2;setz %1\"                   \\\r\n                   : \"=d\"(__junk), \"=a\"(__ret), \"+m\" (*ptr)     \\\r\n                   : \"b\"(__new1), \"c\"(__new2),                  \\\r\n                     \"a\"(__old1), \"d\"(__old2));                 \\\r\n    __ret; })\r\n\r\n#define CAS2(ptr, o1, o2, n1, n2)    __CAS2(ptr, o1, o2, n1, n2)\r\n\r\n\r\n#define BIT_TEST_AND_SET(ptr, b)                                \\\r\n({                                                              \\\r\n    char __ret;                                                 \\\r\n    asm volatile(\"lock btsq $63, %0; setnc %1\" : \"+m\"(*ptr), \"=a\"(__ret) : : \"cc\"); \\\r\n    __ret;                                                      \\\r\n})\r\n\r\n\r\n\r\n\r\n/**\r\n * <h1> LCRQ Queue </h1>\r\n *\r\n * This is LCRQ by Adam Morrison and Yehuda Afek\r\n * http://www.cs.tau.ac.il/~mad/publications/ppopp2013-x86queues.pdf\r\n *\r\n * This implementation does NOT obey the C++ memory model rules AND it is x86 specific.\r\n * No guarantees are given on the correctness or consistency of the results if you use this queue.\r\n *\r\n * Bugs fixed:\r\n * tt was not initialized in dequeue();\r\n *\r\n * <p>\r\n * enqueue algorithm: MS enqueue + LCRQ with re-usage\r\n * dequeue algorithm: MS dequeue + LCRQ with re-usage\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Pointers (lock-free)\r\n *\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass LCRQueue {\r\n\r\nprivate:\r\n    static const int RING_POW = 10;\r\n    static const uint64_t RING_SIZE = 1ull << RING_POW;\r\n\r\n    struct Cell {\r\n        std::atomic<T*>       val;\r\n        std::atomic<uint64_t> idx;\r\n        uint64_t pad[14];\r\n    } __attribute__ ((aligned (128)));\r\n\r\n    struct Node {\r\n        std::atomic<int64_t> head  __attribute__ ((aligned (128)));\r\n        std::atomic<int64_t> tail  __attribute__ ((aligned (128)));\r\n        std::atomic<Node*> next    __attribute__ ((aligned (128)));\r\n        Cell array[RING_SIZE];\r\n\r\n        Node() {\r\n            for (unsigned i = 0; i < RING_SIZE; i++) {\r\n                array[i].val.store(nullptr, std::memory_order_relaxed);\r\n                array[i].idx.store(i, std::memory_order_relaxed);\r\n            }\r\n            head.store(0, std::memory_order_relaxed);\r\n            tail.store(0, std::memory_order_relaxed);\r\n            next.store(nullptr, std::memory_order_relaxed);\r\n        }\r\n    };\r\n\r\n    alignas(128) std::atomic<Node*> head;\r\n    alignas(128) std::atomic<Node*> tail;\r\n\r\n    static const int MAX_THREADS = 128;\r\n    const int maxThreads;\r\n\r\n    HazardPointers<Node> hp {1, maxThreads};\r\n    const int kHpTail = 0;\r\n    const int kHpHead = 0;\r\n\r\n\r\n    /*\r\n     * Private methods\r\n     */\r\n    int is_empty(T* v)  {\r\n        return (v == nullptr);\r\n    }\r\n\r\n    uint64_t node_index(uint64_t i) {\r\n        return (i & ~(1ull << 63));\r\n    }\r\n\r\n    uint64_t set_unsafe(uint64_t i) {\r\n        return (i | (1ull << 63));\r\n    }\r\n\r\n    uint64_t node_unsafe(uint64_t i) {\r\n        return (i & (1ull << 63));\r\n    }\r\n\r\n    inline uint64_t tail_index(uint64_t t) {\r\n        return (t & ~(1ull << 63));\r\n    }\r\n\r\n    int crq_is_closed(uint64_t t) {\r\n        return (t & (1ull << 63)) != 0;\r\n    }\r\n\r\n    void fixState(Node *lhead) {\r\n        while (1) {\r\n            uint64_t t = lhead->tail.fetch_add(0);\r\n            uint64_t h = lhead->head.fetch_add(0);\r\n            // TODO: is it ok or not to cast \"t\" to int64_t ?\r\n            if (lhead->tail.load() != (int64_t)t) continue;\r\n            if (h > t) {\r\n                int64_t tmp = t;\r\n                if (lhead->tail.compare_exchange_strong(tmp, h)) break;\r\n                continue;\r\n            }\r\n            break;\r\n        }\r\n    }\r\n\r\n    int close_crq(Node *rq, const uint64_t tailticket, const int tries) {\r\n        if (tries < 10) {\r\n            int64_t tmp = tailticket + 1;\r\n            return rq->tail.compare_exchange_strong(tmp, (tailticket + 1)|(1ull<<63));\r\n        }\r\n        else {\r\n            return BIT_TEST_AND_SET(&rq->tail, 63);\r\n        }\r\n    }\r\n\r\n\r\npublic:\r\n    LCRQueue(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        // Shared object init\r\n        Node *sentinel = new Node;\r\n        head.store(sentinel, std::memory_order_relaxed);\r\n        tail.store(sentinel, std::memory_order_relaxed);\r\n    }\r\n\r\n\r\n    ~LCRQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        delete head.load();            // Delete the last node\r\n    }\r\n\r\n    static std::string className() { return \"LCRQueue\"; }\r\n\r\n\r\n    void enqueue(T* item, const int tid) {\r\n        int try_close = 0;\r\n        while (true) {\r\n            Node* ltail = hp.protectPtr(kHpTail, tail.load(), tid);\r\n            if (ltail != tail.load()) continue;\r\n            Node *lnext = ltail->next.load();\r\n            if (lnext != nullptr) {  // Help advance the tail\r\n                tail.compare_exchange_strong(ltail, lnext);\r\n                continue;\r\n            }\r\n\r\n            uint64_t tailticket = ltail->tail.fetch_add(1);\r\n            if (crq_is_closed(tailticket)) {\r\n                Node* newNode = new Node();\r\n                // Solo enqueue (superfluous?)\r\n                newNode->tail.store(1, std::memory_order_relaxed);\r\n                newNode->array[0].val.store(item, std::memory_order_relaxed);\r\n                newNode->array[0].idx.store(0, std::memory_order_relaxed);\r\n                Node* nullnode = nullptr;\r\n                if (ltail->next.compare_exchange_strong(nullnode, newNode)) {// Insert new ring\r\n                    tail.compare_exchange_strong(ltail, newNode); // Advance the tail\r\n                    hp.clear(tid);\r\n                    return;\r\n                }\r\n                delete newNode;\r\n                continue;\r\n            }\r\n            Cell* cell = &ltail->array[tailticket & (RING_SIZE-1)];\r\n            uint64_t idx = cell->idx.load();\r\n            if (cell->val.load() == nullptr) {\r\n                if (node_index(idx) <= tailticket) {\r\n                    // TODO: is the missing cast before \"t\" ok or not to add?\r\n                    if ((!node_unsafe(idx) || ltail->head.load() < (int64_t)tailticket)) {\r\n                        if (CAS2((void**)cell, nullptr, idx, item, tailticket)) {\r\n                            hp.clear(tid);\r\n                            return;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            if (((int64_t)(tailticket - ltail->head.load()) >= (int64_t)RING_SIZE) && close_crq(ltail, tailticket, ++try_close)) continue;\r\n        }\r\n    }\r\n\r\n\r\n    T* dequeue(const int tid) {\r\n        while (true) {\r\n            Node* lhead = hp.protectPtr(kHpHead, head.load(), tid);\r\n            if (lhead != head.load()) continue;\r\n            uint64_t headticket = lhead->head.fetch_add(1);\r\n            Cell* cell = &lhead->array[headticket & (RING_SIZE-1)];\r\n\r\n            int r = 0;\r\n            uint64_t tt = 0;\r\n\r\n            while (true) {\r\n                uint64_t cell_idx = cell->idx.load();\r\n                uint64_t unsafe = node_unsafe(cell_idx);\r\n                uint64_t idx = node_index(cell_idx);\r\n                T* val = cell->val.load();\r\n\r\n                if (idx > headticket) break;\r\n\r\n                if (val != nullptr) {\r\n                    if (idx == headticket) {\r\n                        if (CAS2((void**)cell, val, cell_idx, nullptr, unsafe | (headticket + RING_SIZE))) {\r\n                            hp.clear(tid);\r\n                            return val;\r\n                        }\r\n                    } else {\r\n                        if (CAS2((void**)cell, val, cell_idx, val, set_unsafe(idx))) break;\r\n                    }\r\n                } else {\r\n                    if ((r & ((1ull << 10) - 1)) == 0) tt = lhead->tail.load();\r\n                    // Optimization: try to bail quickly if queue is closed.\r\n                    int crq_closed = crq_is_closed(tt);\r\n                    uint64_t t = tail_index(tt);\r\n                    if (unsafe) { // Nothing to do, move along\r\n                        if (CAS2((void**)cell, val, cell_idx, val, unsafe | (headticket + RING_SIZE)))\r\n                            break;\r\n                    } else if (t < headticket + 1 || r > 200000 || crq_closed) {\r\n                        if (CAS2((void**)cell, val, idx, val, headticket + RING_SIZE)) {\r\n                            if (r > 200000 && tt > RING_SIZE) BIT_TEST_AND_SET(&lhead->tail, 63);\r\n                            break;\r\n                        }\r\n                    } else {\r\n                        ++r;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (tail_index(lhead->tail.load()) <= headticket + 1) {\r\n                fixState(lhead);\r\n                // try to return empty\r\n                Node* lnext = lhead->next.load();\r\n                if (lnext == nullptr) {\r\n                    hp.clear(tid);\r\n                    return nullptr;  // Queue is empty\r\n                }\r\n                if (tail_index(lhead->tail) <= headticket + 1) {\r\n                    if (head.compare_exchange_strong(lhead, lnext)) hp.retire(lhead, tid);\r\n                }\r\n            }\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _LCRQ_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/MichaelScottQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _MICHAEL_SCOTT_QUEUE_HP_H_\r\n#define _MICHAEL_SCOTT_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"HazardPointers.hpp\"\r\n\r\n\r\n/**\r\n * <h1> Michael-Scott Queue </h1>\r\n *\r\n * enqueue algorithm: MS enqueue\r\n * dequeue algorithm: MS dequeue\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Pointers (lock-free)\r\n *\r\n *\r\n * Maged Michael and Michael Scott's Queue with Hazard Pointers\r\n * <p>\r\n * Lock-Free Linked List as described in Maged Michael and Michael Scott's paper:\r\n * {@link http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf}\r\n * <a href=\"http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf\">\r\n * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms</a>\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n */\r\ntemplate<typename T>\r\nclass MichaelScottQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        T* item;\r\n        std::atomic<Node*> next;\r\n\r\n        Node(T* userItem) : item{userItem}, next{nullptr} { }\r\n\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    bool casTail(Node *cmp, Node *val) {\r\n\t\treturn tail.compare_exchange_strong(cmp, val);\r\n\t}\r\n\r\n    bool casHead(Node *cmp, Node *val) {\r\n        return head.compare_exchange_strong(cmp, val);\r\n    }\r\n\r\n    // Pointers to head and tail of the list\r\n    alignas(128) std::atomic<Node*> head;\r\n    alignas(128) std::atomic<Node*> tail;\r\n\r\n    static const int MAX_THREADS = 128;\r\n    const int maxThreads;\r\n\r\n    // We need two hazard pointers for dequeue()\r\n    HazardPointers<Node> hp {2, maxThreads};\r\n    const int kHpTail = 0;\r\n    const int kHpHead = 0;\r\n    const int kHpNext = 1;\r\n\r\npublic:\r\n    MichaelScottQueue(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        Node* sentinelNode = new Node(nullptr);\r\n        head.store(sentinelNode, std::memory_order_relaxed);\r\n        tail.store(sentinelNode, std::memory_order_relaxed);\r\n    }\r\n\r\n\r\n    ~MichaelScottQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        delete head.load();            // Delete the last node\r\n    }\r\n\r\n    static std::string className() { return \"MichaelScottQueue\"; }\r\n\r\n    void enqueue(T* item, const int tid) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* newNode = new Node(item);\r\n        while (true) {\r\n            Node* ltail = hp.protectPtr(kHpTail, tail, tid);\r\n            if (ltail == tail.load()) {\r\n                Node* lnext = ltail->next.load();\r\n                if (lnext == nullptr) {\r\n                    // It seems this is the last node, so add the newNode here\r\n                    // and try to move the tail to the newNode\r\n                    if (ltail->casNext(nullptr, newNode)) {\r\n                        casTail(ltail, newNode);\r\n                        hp.clear(tid);\r\n                        return;\r\n                    }\r\n                } else {\r\n                    casTail(ltail, lnext);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    T* dequeue(const int tid) {\r\n        Node* node = hp.protect(kHpHead, head, tid);\r\n        while (node != tail.load()) {\r\n            Node* lnext = hp.protect(kHpNext, node->next, tid);\r\n            if (casHead(node, lnext)) {\r\n                T* item = lnext->item;  // Another thread may clean up lnext after we do hp.clear()\r\n                hp.clear(tid);\r\n                hp.retire(node, tid);\r\n                return item;\r\n            }\r\n            node = hp.protect(kHpHead, head, tid);\r\n        }\r\n        hp.clear(tid);\r\n        return nullptr;                  // Queue is empty\r\n    }\r\n};\r\n\r\n#endif /* _MICHAEL_SCOTT_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/OFLFArrayLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _OF_LF_ARRAY_LINKED_LIST_QUEUE_H_\r\n#define _OF_LF_ARRAY_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/OneFileLF.hpp\"\r\n\r\n/**\r\n * <h1> An Array Linked List Queue using OneFile STM (Lock-Free) </h1>\r\n *\r\n * TODO\r\n *\r\n *\r\n * enqueue algorithm: sequential implementation + MWC\r\n * dequeue algorithm: sequential implementation + MWC\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into MWC)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass OFLFArrayLinkedListQueue : public oflf::tmbase {\r\n\r\nprivate:\r\n    /*\r\n    struct cell {\r\n        onefilelf::tmtype<T*> val;\r\n    } __attribute__ ((aligned (128)));\r\n    */\r\n\r\n    struct Node : oflf::tmbase {\r\n        static const int ITEM_NUM = 1024;   // TODO: use a larger ring buffer size here, 1024 for example\r\n        oflf::tmtype<uint64_t> headidx {0};\r\n        //cell                    items[ITEM_NUM];\r\n        oflf::tmtype<T*>       items[ITEM_NUM];\r\n        oflf::tmtype<uint64_t> tailidx {0};\r\n        oflf::tmtype<Node*>    next {nullptr};\r\n        Node(T* item) {\r\n            items[0] = item;\r\n            tailidx = 1;\r\n            headidx = 0;\r\n            for (int i = 1; i < ITEM_NUM; i++) items[i] = nullptr;\r\n        }\r\n    };\r\n\r\n    oflf::tmtype<Node*>  head {nullptr};\r\n    oflf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    OFLFArrayLinkedListQueue(unsigned int maxThreads=0) {\r\n        Node* sentinelNode = new Node(nullptr);\r\n        sentinelNode->tailidx = 0;\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    ~OFLFArrayLinkedListQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        delete lhead;\r\n    }\r\n\r\n\r\n    static std::string className() { return \"OF-LF-ArrayLinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return oflf::updateTx<bool>([this,item] () -> bool {\r\n            Node* ltail = tail;\r\n            uint64_t ltailidx = ltail->tailidx;\r\n            if (ltailidx < Node::ITEM_NUM) {\r\n                ltail->items[ltailidx] = item;\r\n                ++ltail->tailidx;\r\n                return true;\r\n            }\r\n            Node* newNode = oflf::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return oflf::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            uint64_t lheadidx = lhead->headidx;\r\n            // Check if queue is empty\r\n            if (lhead == tail && lheadidx == tail->tailidx) return nullptr;\r\n            if (lheadidx < Node::ITEM_NUM) {\r\n                ++lhead->headidx;\r\n                return lhead->items[lheadidx];\r\n            }\r\n            lhead = lhead->next;\r\n            oflf::tmDelete<Node>(head);\r\n            head = lhead;\r\n            ++lhead->headidx;\r\n            return lhead->items[0];\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _OF_LF_ARRAY_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/OFLFArrayQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _OFLF_STM_ARRAY_QUEUE_H_\r\n#define _OFLF_STM_ARRAY_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/OneFileLF.hpp\"\r\n\r\n/**\r\n * <h1> An Array Queue </h1>\r\n *\r\n */\r\ntemplate<typename T>\r\nclass OFLFArrayQueue : public oflf::tmbase {\r\n\r\nprivate:\r\n    static const int MAX_ITEMS = 2048;\r\n    oflf::tmtype<uint64_t> headidx {0};\r\n    oflf::tmtype<T*>       items[MAX_ITEMS];\r\n    oflf::tmtype<uint64_t> tailidx {0};\r\n\r\n\r\npublic:\r\n    OFLFArrayQueue(unsigned int maxThreads=0) {\r\n        oflf::updateTx<bool>([this] () {\r\n            for (int i = 0; i < MAX_ITEMS; i++) items[i] = nullptr;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    ~OFLFArrayQueue() { }\r\n\r\n\r\n    static std::string className() { return \"OF-LF-ArrayQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return oflf::updateTx<bool>([this,item] () -> bool {\r\n            if (tailidx >= headidx+MAX_ITEMS) return false; // queue is full\r\n            items[tailidx % MAX_ITEMS] = item;\r\n            ++tailidx;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return oflf::updateTx<T*>([this] () -> T* {\r\n            if (tailidx == headidx) return nullptr; // queue is empty\r\n            T* item = items[headidx % MAX_ITEMS];\r\n            ++headidx;\r\n            return item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _OF_LF_STM_ARRAY_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/OFLFLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _OF_LF_LINKED_LIST_QUEUE_H_\r\n#define _OF_LF_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/OneFileLF.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using OneFile STM (Lock-Free) </h1>\r\n *\r\n * enqueue algorithm: sequential implementation + OFLF\r\n * dequeue algorithm: sequential implementation + OFLF\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: lock-free Hazard Eras (integrated into OFLF)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass OFLFLinkedListQueue : public oflf::tmbase {\r\n\r\nprivate:\r\n    struct Node : oflf::tmbase {\r\n        T* item;\r\n        oflf::tmtype<Node*> next {nullptr};\r\n        Node(T* userItem) : item{userItem} { }\r\n    };\r\n\r\n    oflf::tmtype<Node*>  head {nullptr};\r\n    oflf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    OFLFLinkedListQueue(unsigned int maxThreads=0) {\r\n        Node* sentinelNode = oflf::tmNew<Node>(nullptr);\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    ~OFLFLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        oflf::tmDelete(lhead);\r\n    }\r\n\r\n\r\n    static std::string className() { return \"OF-LF-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* newNode = oflf::tmNew<Node>(item); // Let's allocate outside the transaction, less overhead\r\n        return oflf::updateTx<bool>([this,newNode] () -> bool {\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return oflf::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return nullptr;\r\n            head = lhead->next;\r\n            oflf::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _OF_LF_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/OFWFArrayLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _OF_WF_ARRAY_LINKED_LIST_QUEUE_H_\r\n#define _OF_WF_ARRAY_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/OneFileWF.hpp\"\r\n\r\n/**\r\n * <h1> An Array Linked List Queue using OneFile STM (Wait-Free) </h1>\r\n *\r\n * TODO\r\n *\r\n *\r\n * enqueue algorithm: sequential implementation + MWC\r\n * dequeue algorithm: sequential implementation + MWC\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into MWC)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass OFWFArrayLinkedListQueue  : public ofwf::tmbase {\r\n\r\nprivate:\r\n    struct Node : ofwf::tmbase {\r\n        static const int ITEM_NUM = 1024;\r\n        ofwf::tmtype<uint64_t> headidx {0};\r\n        ofwf::tmtype<T*>       items[ITEM_NUM];\r\n        ofwf::tmtype<uint64_t> tailidx {0};\r\n        ofwf::tmtype<Node*>    next {nullptr};\r\n        Node(T* item) {\r\n            items[0] = item;\r\n            tailidx = 1;\r\n            headidx = 0;\r\n            for (int i = 1; i < ITEM_NUM; i++) items[i] = nullptr;\r\n        }\r\n    };\r\n\r\n    ofwf::tmtype<Node*>  head {nullptr};\r\n    ofwf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    OFWFArrayLinkedListQueue(unsigned int maxThreads=0) {\r\n        Node* sentinelNode = new Node(nullptr);\r\n        sentinelNode->tailidx = 0;\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    ~OFWFArrayLinkedListQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        delete lhead;\r\n    }\r\n\r\n\r\n    static std::string className() { return \"OF-WF-ArrayLinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return ofwf::updateTx<bool>([this,item] () -> bool {\r\n            Node* ltail = tail;\r\n            uint64_t ltailidx = ltail->tailidx;\r\n            if (ltailidx < Node::ITEM_NUM) {\r\n                ltail->items[ltailidx] = item;\r\n                ++ltail->tailidx;\r\n                return true;\r\n            }\r\n            Node* newNode = ofwf::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return ofwf::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            uint64_t lheadidx = lhead->headidx;\r\n            // Check if queue is empty\r\n            if (lhead == tail && lheadidx == tail->tailidx) return nullptr;\r\n            if (lheadidx < Node::ITEM_NUM) {\r\n                ++lhead->headidx;\r\n                return lhead->items[lheadidx];\r\n            }\r\n            lhead = lhead->next;\r\n            ofwf::tmDelete<Node>(head);\r\n            head = lhead;\r\n            ++lhead->headidx;\r\n            return lhead->items[0];\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _OF_WF_ARRAY_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/OFWFLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _OF_WF_LINKED_LIST_QUEUE_H_\r\n#define _OF_WF_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/OneFileWF.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using OneFile STM (Wait-Free) </h1>\r\n *\r\n * enqueue algorithm: sequential implementation + OFWF\r\n * dequeue algorithm: sequential implementation + OFWF\r\n * Consistency: Linearizable\r\n * enqueue() progress: wait-free\r\n * dequeue() progress: wait-free\r\n * Memory Reclamation: wait-free Hazard Eras (integrated into OFWF)\r\n * enqueue min ops: 3 DCAS + 1 CAS\r\n * dequeue min ops: 2 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass OFWFLinkedListQueue : public ofwf::tmbase {\r\n\r\nprivate:\r\n    struct Node : ofwf::tmbase {\r\n        T* item;\r\n        ofwf::tmtype<Node*> next;\r\n        Node(T* userItem) : item{userItem}, next{nullptr} { }\r\n    };\r\n\r\n    ofwf::tmtype<Node*>  head {nullptr};\r\n    ofwf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    OFWFLinkedListQueue(unsigned int maxThreads=0) {\r\n        Node* sentinelNode = ofwf::tmNew<Node>(nullptr);\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    ~OFWFLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        ofwf::tmDelete(lhead);\r\n    }\r\n\r\n\r\n    static std::string className() { return \"OF-WF-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free bounded\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* newNode = ofwf::tmNew<Node>(item); // Let's allocate outside the transaction, less overhead\r\n        return ofwf::updateTx<bool>([this,newNode] () -> bool {\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free bounded\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return (T*)ofwf::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return nullptr;\r\n            head = lhead->next;\r\n            ofwf::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _OF_WF_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/README.md",
    "content": "# Queues #\r\n\r\nThis folder contains multiple multi-producer-multi-consumer queue implementations, all of them with integrated memory reclamation having the same progress condition:\r\n\r\n- FAAArrayQueue: Memory unbounded, lock-free, one array per node, hazard pointers\r\nhttp://...\r\n\r\n- LCRQueue: Memory unbounded, lock-free, one array per node, hazard pointers, can re-use entries in some situations\r\nhttp://\r\n\r\n- OFLFLinkedListqueue: Memory unbounded, lock-free, one entry per node, hazard eras\r\nUses OneFile STM (Lock-Free)\r\n\r\n- OFWFLinkedListqueue: Memory unbounded, wait-free bounded, one entry per node, hazard eras\r\nUses OneFile STM (Wait-Free)\r\n\r\n- SimQueue: Memory unbounded, wait-free bounded, one entry per node, modified hazard pointers\r\nhttp://\r\n\r\n- TurnQueue: Memory unbounded, wait-free bounded, one entry per node, hazard pointers\r\nhttp:// \r\n"
  },
  {
    "path": "datastructures/queues/SimQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _CR_SIM_QUEUE_HP_H_\r\n#define _CR_SIM_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"HazardPointersSimQueue.hpp\"\r\n\r\n\r\n/**\r\n * <h1> Sim Queue </h1>\r\n *\r\n * Based on the SimQueue (FK queue)\r\n *\r\n * http://thalis.cs.uoi.gr/tech_reports/publications/TR2011-01.pdf\r\n *\r\n * enqueue algorithm: P-Sim\r\n * dequeue algorithm: P-Sim\r\n * Consistency: Linearizable\r\n * enqueue() progress: wait-free bounded O(N_threads)\r\n * dequeue() progress: wait-free bounded O(N_threads)\r\n * Memory Reclamation: Hazard Pointers with custom scanner for Nodes. EnqState and DeqState re-usage.\r\n *\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n */\r\ntemplate<typename T>\r\nclass SimQueue {\r\n\r\nprivate:\r\n    static const int MAX_THREADS = 128;\r\n\r\n    struct Node {\r\n        T* item;\r\n        std::atomic<Node*> next {nullptr};\r\n        Node(T* item) : item{item} { }\r\n    };\r\n\r\n\r\n    struct EnqState {\r\n        std::atomic<Node*>  tail {nullptr};         // link_a\r\n        std::atomic<Node*>  nextNode {nullptr};     // link_b\r\n        std::atomic<Node*>  nextTail {nullptr};     // ptr\r\n        std::atomic<bool>   applied[MAX_THREADS];\r\n\r\n        EnqState() {\r\n            for(int i=0; i < MAX_THREADS; i++){\r\n                applied[i].store(false, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    };\r\n\r\n\r\n    struct DeqState {\r\n        std::atomic<Node*>  head {nullptr};\r\n        std::atomic<T*>     items[MAX_THREADS];\r\n        std::atomic<bool>   applied[MAX_THREADS];\r\n\r\n        DeqState() {\r\n            for(int i=0; i < MAX_THREADS; i++){\r\n                applied[i].store(false, std::memory_order_relaxed);\r\n                items[i].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    };\r\n\r\n\r\n    typedef union pointer_t {\r\n        struct StructData{\r\n            int64_t seq : 48;\r\n            int64_t index: 16;\r\n        } u;           // struct_data\r\n        int64_t raw;   // raw_data\r\n    } pointer_t;\r\n\r\n\r\n    const int maxThreads;\r\n\r\n    alignas(128) std::atomic<pointer_t> enqPointer;\r\n    alignas(128) std::atomic<pointer_t> deqPointer;\r\n    // Enqueue requests\r\n    alignas(128) std::atomic<T*> items[MAX_THREADS];          // Always access relaxed\r\n    alignas(128) std::atomic<bool> enqueuers[MAX_THREADS];\r\n    // Re-usable EnqState instances\r\n    alignas(128) EnqState enqReused[MAX_THREADS*2];\r\n    // Dequeue requests\r\n    alignas(128) std::atomic<bool> dequeuers[MAX_THREADS];\r\n    // Re-usable DeqState instances\r\n    alignas(128) DeqState deqReused[MAX_THREADS*2];\r\n    alignas(128) Node* pool[MAX_THREADS][MAX_THREADS];\r\n\r\n\r\n    // Passed to Hazard Pointers\r\n    std::function<bool(Node*)> find = [this](Node* ptr) {\r\n        pointer_t lpointer = enqPointer.load();\r\n        if (enqReused[lpointer.u.index].tail.load() == ptr) return true;\r\n        /*\r\n        lpointer = deqPointer.load();\r\n        if (deqReused[lpointer.u.index].head.load() == ptr) return true;\r\n        */\r\n        return false;\r\n    };\r\n\r\n    HazardPointersSimQueue<Node>  hp {find, 1, maxThreads};\r\n    const int kHpTail = 0;\r\n    const int kHpNode = 0;\r\n\r\n    Node* sentinel = new Node(nullptr);\r\n\r\npublic:\r\n    SimQueue(int maxThreads=MAX_THREADS) : maxThreads(maxThreads) {\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            enqueuers[i].store(false, std::memory_order_relaxed);\r\n            dequeuers[i].store(false, std::memory_order_relaxed);\r\n            for(int j=0;j<maxThreads;j++){\r\n                pool[i][j]=new Node(nullptr);\r\n            }\r\n        }\r\n        pointer_t temp;\r\n        temp.u.seq = 0;\r\n        temp.u.index = 0;\r\n        enqPointer.store(temp);\r\n        deqPointer.store(temp);\r\n        enqReused[0].tail.store(sentinel, std::memory_order_relaxed);\r\n        enqReused[0].nextTail.store(sentinel, std::memory_order_relaxed);\r\n        deqReused[0].head.store(sentinel, std::memory_order_relaxed);\r\n    }\r\n\r\n\r\n    ~SimQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        delete deqReused[deqPointer.load().u.index].head.load();\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            for (int j = 0; j < maxThreads; j++) {\r\n                delete pool[i][j];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    static std::string className() { return \"SimQueue\"; }\r\n\r\n\r\n    /**\r\n     * Progress condition: wait-free bounded\r\n     */\r\n    void enqueue(T* item, const int tid) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        // Publish enqueue request\r\n        items[tid].store(item, std::memory_order_relaxed);\r\n        bool newrequest = !enqueuers[tid].load(std::memory_order_relaxed);\r\n        enqueuers[tid].store(newrequest);\r\n        for (int iter = 0; iter < 3; iter++) {\r\n            pointer_t lpointer = enqPointer.load();\r\n            EnqState* const lstate = &enqReused[lpointer.u.index];\r\n            Node* ltail = hp.protectPtr(kHpTail, lstate->tail.load(), tid);\r\n            Node* lnext = lstate->nextNode.load(); // No need for HP because we don't dereference it\r\n            Node* lnextTail = lstate->nextTail.load(); // No need for HP\r\n            if (lpointer.raw != enqPointer.load().raw) continue;\r\n\r\n            // Advance the tail if needed\r\n            if (ltail->next.load() != lnext) {\r\n                ltail->next.store(lnext, std::memory_order_release);\r\n            }\r\n            // Check if my request has been done\r\n            if (lstate->applied[tid].load() == newrequest) {\r\n                if (lpointer.raw == enqPointer.load().raw) break;\r\n            }\r\n            // Help opened enqueue requests, starting from zero\r\n            Node* first = nullptr;\r\n            Node* node = nullptr;\r\n            const int myIndex = (lpointer.u.index == 2*tid) ? 2*tid+1 : 2*tid ;\r\n            EnqState* const myState = &enqReused[myIndex];\r\n            int numNodes = 0;\r\n            for (int j = 0; j < maxThreads; j++) {\r\n                // Check if it is an open request\r\n                const bool enqj = enqueuers[j].load();\r\n                myState->applied[j].store(enqj, std::memory_order_relaxed);\r\n                if (enqj == lstate->applied[j].load()) continue;\r\n                Node* prev = node;\r\n                node = pool[tid][numNodes++];\r\n                node->item = items[j].load(std::memory_order_relaxed);\r\n                if (first == nullptr) {\r\n                    first = node;\r\n                } else {\r\n                    prev->next.store(node, std::memory_order_relaxed);\r\n                }\r\n                if (lpointer.raw != enqPointer.load().raw) break;\r\n            }\r\n\r\n            // Try to apply the new sublist\r\n            if (lpointer.raw != enqPointer.load().raw) continue;\r\n            node->next.store(nullptr, std::memory_order_relaxed);\r\n            myState->tail.store(lnextTail, std::memory_order_relaxed);\r\n            myState->nextNode.store(first, std::memory_order_relaxed);\r\n            myState->nextTail.store(node, std::memory_order_relaxed);\r\n            pointer_t myPointer;\r\n            myPointer.u.seq = lpointer.u.seq + 1;\r\n            myPointer.u.index = myIndex;\r\n            if (enqPointer.compare_exchange_strong(lpointer, myPointer)) {\r\n                for (int k = 0; k < numNodes; k++) {   // Refill pool\r\n                    pool[tid][k] = new Node(nullptr);\r\n                }\r\n            }\r\n        }\r\n        hp.clear(tid);\r\n    }\r\n\r\n\r\n\r\n    /**\r\n     * Progress condition: wait-free bounded\r\n     *\r\n     * We use just one HP index, but it was though to get there.\r\n     */\r\n    T* dequeue(const int tid) {\r\n        // Publish dequeue request\r\n        bool newrequest = !dequeuers[tid].load(std::memory_order_relaxed);\r\n        dequeuers[tid].store(newrequest);\r\n        for (int iter = 0; iter < 2; iter++) {\r\n            pointer_t lpointer = deqPointer.load();\r\n            DeqState* lstate = &deqReused[lpointer.u.index];\r\n            // Check if my request has been done\r\n            if (lstate->applied[tid].load() == newrequest) {\r\n                if (lpointer.raw == deqPointer.load().raw) break;\r\n            }\r\n            // Help opened dequeue requests, starting from turn+1\r\n            Node* newHead = hp.protectPtr(kHpNode, lstate->head, tid);\r\n            if (lpointer.raw != deqPointer.load().raw) continue;\r\n            const int myIndex = (lpointer.u.index == 2*tid) ? 2*tid+1 : 2*tid ;\r\n            DeqState* const myState = &deqReused[myIndex];\r\n            Node* node = newHead;\r\n            for (int j = 0; j < maxThreads; j++) {\r\n                // Check if it is an open request\r\n                const bool applied = lstate->applied[j].load();\r\n                if (dequeuers[j].load() == applied) {\r\n                    myState->items[j].store(lstate->items[j], std::memory_order_relaxed);\r\n                    myState->applied[j].store(applied, std::memory_order_relaxed);\r\n                    continue;\r\n                }\r\n                myState->applied[j].store(!applied, std::memory_order_relaxed);\r\n                if (node->next.load() == nullptr) {\r\n                    myState->items[j].store(nullptr,std::memory_order_relaxed);\r\n                } else {\r\n                    node = hp.protectPtr(kHpNode, node->next, tid);\r\n                    if (lpointer.raw != deqPointer.load().raw) break;\r\n                    myState->items[j].store(node->item, std::memory_order_relaxed);\r\n                    newHead = node;\r\n                }\r\n            }\r\n            if (lpointer.raw != deqPointer.load().raw) continue;\r\n            pointer_t newDeqIndex;\r\n            newDeqIndex.u.seq = lpointer.u.seq + 1;\r\n            newDeqIndex.u.index = myIndex;\r\n            myState->head.store(newHead, std::memory_order_relaxed);\r\n            node = lstate->head;\r\n            if (deqPointer.compare_exchange_strong(lpointer, newDeqIndex)) {\r\n                while (node != newHead) {\r\n                    Node* next = node->next.load();\r\n                    hp.retire(node,tid);\r\n                    node = next;\r\n                }\r\n                break;\r\n            }\r\n        }\r\n        hp.clear(tid);\r\n        return deqReused[deqPointer.load().u.index].items[tid].load();\r\n    }\r\n};\r\n\r\n#endif /* _SIM_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/TinySTMArrayLinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _TINY_STM_ARRAY_LINKED_LIST_QUEUE_H_\r\n#define _TINY_STM_ARRAY_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/TinySTM.hpp\"\r\n\r\n/**\r\n * <h1> An Array Linked List Queue using Tiny STM </h1>\r\n */\r\ntemplate<typename T>\r\nclass TinySTMArrayLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node : tinystm::tmbase {\r\n        static const int ITEM_NUM = 1024;\r\n        tinystm::tmtype<uint64_t> headidx {0};\r\n        tinystm::tmtype<T*>       items[ITEM_NUM];\r\n        tinystm::tmtype<uint64_t> tailidx {0};\r\n        tinystm::tmtype<Node*>    next {nullptr};\r\n        Node(T* item) {\r\n            items[0] = item;\r\n            tailidx = 1;\r\n            headidx = 0;\r\n            for (int i = 1; i < ITEM_NUM; i++) items[i] = nullptr;\r\n        }\r\n    };\r\n\r\n    tinystm::tmtype<Node*>  head {nullptr};\r\n    tinystm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    TinySTMArrayLinkedListQueue(unsigned int maxThreads=0) {\r\n        tinystm::updateTx<bool>([this] () {\r\n            Node* sentinelNode = tinystm::tmNew<Node>(nullptr);\r\n            sentinelNode->tailidx = 0;\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    ~TinySTMArrayLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        tinystm::updateTx<bool>([this] () {\r\n            Node* lhead = head;\r\n            tinystm::tmDelete(lhead);\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"TinySTM-ArrayLinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return tinystm::updateTx<bool>([this,item] () -> bool {\r\n            Node* ltail = tail;\r\n            uint64_t ltailidx = ltail->tailidx;\r\n            if (ltailidx < Node::ITEM_NUM) {\r\n                ltail->items[ltailidx] = item;\r\n                ++ltail->tailidx;\r\n                return true;\r\n            }\r\n            Node* newNode = tinystm::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return tinystm::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            uint64_t lheadidx = lhead->headidx;\r\n            // Check if queue is empty\r\n            if (lhead == tail && lheadidx == tail->tailidx) return nullptr;\r\n            if (lheadidx < Node::ITEM_NUM) {\r\n                ++lhead->headidx;\r\n                return lhead->items[lheadidx];\r\n            }\r\n            lhead = lhead->next;\r\n            tinystm::tmDelete(head.load());\r\n            head = lhead;\r\n            ++lhead->headidx;\r\n            return lhead->items[0];\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _TINY_STM_ARRAY_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/TinySTMLinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _TINY_STM_LINKED_LIST_QUEUE_H_\r\n#define _TINY_STM_LINKED_LIST_QUEUE_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n\r\n#include \"stms/TinySTM.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using Tiny STM</h1>\r\n\r\n */\r\ntemplate<typename T>\r\nclass TinySTMLinkedListQueue : public tinystm::tmbase {\r\n\r\nprivate:\r\n    struct Node : tinystm::tmbase {\r\n        T* item;\r\n        tinystm::tmtype<Node*> next {nullptr};\r\n        Node(T* userItem) : item{userItem} { }\r\n    };\r\n\r\n    tinystm::tmtype<Node*>  head {nullptr};\r\n    tinystm::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    TinySTMLinkedListQueue(unsigned int maxThreads=0) {\r\n        tinystm::updateTx<bool>([this] () {\r\n            Node* sentinelNode = tinystm::tmNew<Node>(nullptr);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    ~TinySTMLinkedListQueue() {\r\n        while (dequeue() != nullptr); // Drain the queue\r\n        tinystm::updateTx<bool>([this] () {\r\n            Node* lhead = head;\r\n            tinystm::tmDelete(lhead);\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"TinySTM-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return tinystm::updateTx<bool>([this,item] () -> bool {\r\n            Node* newNode = tinystm::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T* dequeue(const int tid=0) {\r\n        return tinystm::updateTx<T*>([this] () -> T* {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return nullptr;\r\n            head = lhead->next;\r\n            tinystm::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _TINY_STM_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/queues/TurnQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _TURN_QUEUE_HP_H_\r\n#define _TURN_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"HazardPointers.hpp\"\r\n\r\n\r\n/**\r\n * <h1> Turn Queue </h1>\r\n *\r\n * A concurrent wait-free queue that is Multi-Producer-Multi-Consumer and does\r\n * its own wait-free memory reclamation.\r\n * Based on the paper \"A Wait-Free Queue with Wait-Free Memory Reclamation\"\r\n * https://github.com/pramalhe/ConcurrencyFreaks/tree/master/papers/crturnqueue-2016.pdf\r\n *\r\n * <p>\r\n * Enqueue algorithm: CR Turn enqueue\r\n * Dequeue algorithm: CR Turn dequeue\r\n * Consistency: Linearizable\r\n * enqueue() progress: wait-free bounded O(N_threads)\r\n * dequeue() progress: wait-free bounded O(N_threads)\r\n * Memory Reclamation: Hazard Pointers (wait-free)\r\n *\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n * @author Andreia Correia\r\n * @author Pedro Ramalhete\r\n */\r\ntemplate<typename T>\r\nclass TurnQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        T* item;\r\n        const int enqTid;\r\n        std::atomic<int> deqTid;\r\n        std::atomic<Node*> next;\r\n\r\n        Node(T* item, int tid) : item{item}, enqTid{tid}, deqTid{IDX_NONE}, next{nullptr} { }\r\n\r\n        bool casDeqTid(int cmp, int val) {\r\n     \t    return deqTid.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    static const int IDX_NONE = -1;\r\n    static const int MAX_THREADS = 128;\r\n    const int maxThreads;\r\n\r\n    // Pointers to head and tail of the list\r\n    alignas(128) std::atomic<Node*> head;\r\n    alignas(128) std::atomic<Node*> tail;\r\n    // Enqueue requests\r\n    alignas(128) std::atomic<Node*> enqueuers[MAX_THREADS];\r\n    // Dequeue requests\r\n    alignas(128) std::atomic<Node*> deqself[MAX_THREADS];\r\n    alignas(128) std::atomic<Node*> deqhelp[MAX_THREADS];\r\n\r\n\r\n    HazardPointers<Node> hp {3, maxThreads}; // We need three hazard pointers\r\n    const int kHpTail = 0;\r\n    const int kHpHead = 0;\r\n    const int kHpNext = 1;\r\n    const int kHpDeq = 2;\r\n\r\n    Node* sentinelNode = new Node(nullptr, 0);\r\n\r\n\r\n    /**\r\n     * Called only from dequeue()\r\n     *\r\n     * Search for the next request to dequeue and assign it to lnext.deqTid\r\n     * It is only a request to dequeue if deqself[i] equals deqhelp[i].\r\n     */\r\n    inline int searchNext(Node* lhead, Node* lnext) {\r\n        const int turn = lhead->deqTid.load();\r\n        for (int idx=turn+1; idx < turn+maxThreads+1; idx++) {\r\n            const int idDeq = idx%maxThreads;\r\n            if (deqself[idDeq].load() != deqhelp[idDeq].load()) continue;\r\n            if (lnext->deqTid.load() == IDX_NONE) lnext->casDeqTid(IDX_NONE, idDeq);\r\n            break;\r\n        }\r\n        return lnext->deqTid.load();\r\n    }\r\n\r\n\r\n    /**\r\n     * Called only from dequeue()\r\n     *\r\n     * If the ldeqTid is not our own, we must use an HP to protect against\r\n     * deqhelp[ldeqTid] being retired-deleted-newed-reenqueued.\r\n     */\r\n    inline void casDeqAndHead(Node* lhead, Node* lnext, const int tid) {\r\n        const int ldeqTid = lnext->deqTid.load();\r\n        if (ldeqTid == tid) {\r\n            deqhelp[ldeqTid].store(lnext, std::memory_order_release);\r\n        } else {\r\n            Node* ldeqhelp = hp.protectPtr(kHpDeq, deqhelp[ldeqTid].load(), tid);\r\n            if (ldeqhelp != lnext && lhead == head.load()) {\r\n                deqhelp[ldeqTid].compare_exchange_strong(ldeqhelp, lnext); // Assign next to request\r\n            }\r\n        }\r\n        head.compare_exchange_strong(lhead, lnext);\r\n    }\r\n\r\n\r\n    /**\r\n     * Called only from dequeue()\r\n     *\r\n     * Giveup procedure, for when there are no nodes left to dequeue\r\n     */\r\n    inline void giveUp(Node* myReq, const int tid) {\r\n        Node* lhead = head.load();\r\n        if (deqhelp[tid].load() != myReq || lhead == tail.load()) return;\r\n        hp.protectPtr(kHpHead, lhead, tid);\r\n        if (lhead != head.load()) return;\r\n        Node* lnext = hp.protectPtr(kHpNext, lhead->next.load(), tid);\r\n        if (lhead != head.load()) return;\r\n        if (searchNext(lhead, lnext) == IDX_NONE) lnext->casDeqTid(IDX_NONE, tid);\r\n        casDeqAndHead(lhead, lnext, tid);\r\n    }\r\n\r\npublic:\r\n    TurnQueue(int maxThreads=MAX_THREADS) : maxThreads(maxThreads) {\r\n        head.store(sentinelNode, std::memory_order_relaxed);\r\n        tail.store(sentinelNode, std::memory_order_relaxed);\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            enqueuers[i].store(nullptr, std::memory_order_relaxed);\r\n            // deqself[i] != deqhelp[i] means that isRequest=false\r\n            deqself[i].store(new Node(nullptr, 0), std::memory_order_relaxed);\r\n            deqhelp[i].store(new Node(nullptr, 0), std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n\r\n    ~TurnQueue() {\r\n        delete sentinelNode;\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        for (int i=0; i < maxThreads; i++) delete deqself[i].load();\r\n        for (int i=0; i < maxThreads; i++) delete deqhelp[i].load();\r\n    }\r\n\r\n\r\n    static std::string className() { return \"TurnQueue\"; }\r\n\r\n\r\n    /**\r\n     * Steps when uncontended:\r\n     * 1. Add node to enqueuers[]\r\n     * 2. Insert node in tail.next using a CAS\r\n     * 3. Advance tail to tail.next\r\n     * 4. Remove node from enqueuers[]\r\n     *\r\n     * @param tid The tid must be a UNIQUE index for each thread, in the range 0 to maxThreads-1\r\n     */\r\n    void enqueue(T* item, const int tid) {\r\n        if (item == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* myNode = new Node(item,tid);\r\n        enqueuers[tid].store(myNode);\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            if (enqueuers[tid].load() == nullptr) {\r\n                hp.clear(tid);\r\n                return; // Some thread did all the steps\r\n            }\r\n            Node* ltail = hp.protectPtr(kHpTail, tail.load(), tid);\r\n            if (ltail != tail.load()) continue; // If the tail advanced maxThreads times, then my node has been enqueued\r\n            if (enqueuers[ltail->enqTid].load() == ltail) {  // Help a thread do step 4\r\n                Node* tmp = ltail;\r\n                enqueuers[ltail->enqTid].compare_exchange_strong(tmp, nullptr);\r\n            }\r\n            for (int j = 1; j < maxThreads+1; j++) {         // Help a thread do step 2\r\n                Node* nodeToHelp = enqueuers[(j + ltail->enqTid) % maxThreads].load();\r\n                if (nodeToHelp == nullptr) continue;\r\n                Node* nodenull = nullptr;\r\n                ltail->next.compare_exchange_strong(nodenull, nodeToHelp);\r\n                break;\r\n            }\r\n            Node* lnext = ltail->next.load();\r\n     \t    if (lnext != nullptr) tail.compare_exchange_strong(ltail, lnext); // Help a thread do step 3\r\n        }\r\n        enqueuers[tid].store(nullptr, std::memory_order_release); // Do step 4, just in case it's not done\r\n        hp.clear(tid);\r\n    }\r\n\r\n\r\n    /**\r\n     * Steps when uncontended:\r\n     * 1. Publish request to dequeue in dequeuers[tid];\r\n     * 2. CAS node->deqTid from IDX_START to tid;\r\n     * 3. Set dequeuers[tid] to the newly owned node;\r\n     * 4. Advance the head with casHead();\r\n     *\r\n     * We must protect either head or tail with HP before doing the check for\r\n     * empty queue, otherwise we may get into retired-deleted-newed-reenqueued.\r\n     *\r\n     * @param tid: The tid must be a UNIQUE index for each thread, in the range 0 to maxThreads-1\r\n     */\r\n    T* dequeue(const int tid) {\r\n        Node* prReq = deqself[tid].load();     // Previous request\r\n        Node* myReq = deqhelp[tid].load();\r\n        deqself[tid].store(myReq);             // Step 1\r\n        for (int i=0; i < maxThreads; i++) {\r\n            if (deqhelp[tid].load() != myReq) break; // No need for HP\r\n            Node* lhead = hp.protectPtr(kHpHead, head.load(), tid);\r\n            if (lhead != head.load()) continue;\r\n            if (lhead == tail.load()) {        // Give up\r\n                deqself[tid].store(prReq);     // Rollback request to dequeue\r\n                giveUp(myReq, tid);\r\n                if (deqhelp[tid].load() != myReq) {\r\n                    deqself[tid].store(myReq, std::memory_order_relaxed);\r\n                    break;\r\n                }\r\n                hp.clear(tid);\r\n                return nullptr;\r\n            }\r\n            Node* lnext = hp.protectPtr(kHpNext, lhead->next.load(), tid);\r\n            if (lhead != head.load()) continue;\r\n \t\t    if (searchNext(lhead, lnext) != IDX_NONE) casDeqAndHead(lhead, lnext, tid);\r\n        }\r\n        Node* myNode = deqhelp[tid].load();\r\n        Node* lhead = hp.protectPtr(kHpHead, head.load(), tid);     // Do step 4 if needed\r\n        if (lhead == head.load() && myNode == lhead->next.load()) head.compare_exchange_strong(lhead, myNode);\r\n        hp.clear(tid);\r\n        hp.retire(prReq, tid);\r\n        return myNode->item;\r\n    }\r\n\r\n};\r\n\r\n#endif /* _CR_TURN_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "datastructures/sequential/HashSet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _UC_HASH_SET_H_\r\n#define _UC_HASH_SET_H_\r\n\r\n#include <iostream>\r\n#include <functional>\r\n#include <unordered_set>\r\n\r\n// TODO: change CKey* to CKey&\r\n\r\n// This is a wrapper to std::set, which should be a Red-Black tree\r\ntemplate<typename CKey>\r\nclass HashSet {\r\n\r\nprivate:\r\n    std::unordered_set<CKey> set;\r\n\r\npublic:\r\n\r\n    static std::string className() { return \"HashSet\"; }\r\n\r\n\r\n    bool add(CKey key) {\r\n        if (set.find(key) == set.end()) {\r\n            set.insert(key); // TODO: can we improve this so we don't have to lookup twice?\r\n            return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    bool remove(CKey key) {\r\n        auto iter = set.find(key);\r\n        if (iter == set.end()) return false;\r\n        set.erase(iter);\r\n        return true;\r\n    }\r\n\r\n    bool contains(CKey key) {\r\n        if (set.find(key) == set.end()) return false;\r\n        return true;  // TODO: optimize this\r\n    }\r\n\r\n    bool iterateAll(std::function<bool(CKey*)> itfun) {\r\n\t\tfor (auto it = set.begin(); it != set.end(); ++it) {\r\n\t\t\tCKey key = *it;\r\n\t\t\tif (!itfun(&key)) return false;\r\n\t\t}\r\n\t\treturn true;\r\n    }\r\n\r\n};\r\n\r\n#endif /* _UC_HASH_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/sequential/LinkedListQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _SEQUENTIAL_LINKED_LIST_QUEUE_H_\r\n#define _SEQUENTIAL_LINKED_LIST_QUEUE_H_\r\n\r\n/**\r\n * <h1> A sequential implementation of Linked List Queue </h1>\r\n *\r\n * This is meant to be used by the Universal Constructs\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass LinkedListQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        T* item;\r\n        Node* next {nullptr};\r\n        Node(T* userItem) : item{userItem} { }\r\n    };\r\n\r\n    Node*  head {nullptr};\r\n    Node*  tail {nullptr};\r\n\r\n\r\npublic:\r\n    LinkedListQueue(unsigned int maxThreads=0) {\r\n        Node* sentinelNode = new Node(nullptr);\r\n        head = sentinelNode;\r\n        tail = sentinelNode;\r\n    }\r\n\r\n\r\n    // Universal Constructs need a copy constructor on the underlying data structure\r\n    LinkedListQueue(const LinkedListQueue& other) {\r\n        head = new Node(nullptr);\r\n        Node* node = head;\r\n        Node* onode = other.head->next;\r\n        while (onode != nullptr) {\r\n            node->next = new Node(onode->item);\r\n            node = node->next;\r\n            onode = onode->next;\r\n        }\r\n        tail = node;\r\n    }\r\n\r\n\r\n    ~LinkedListQueue() {\r\n        while (dequeue(0) != nullptr); // Drain the queue\r\n        Node* lhead = head;\r\n        delete lhead;\r\n    }\r\n\r\n\r\n    static std::string className() { return \"LinkedListQueue\"; }\r\n\r\n\r\n    bool enqueue(T* item, const int tid=0) {\r\n        if (item == nullptr) return false;\r\n        Node* newNode = new Node(item);\r\n        tail->next = newNode;\r\n        tail = newNode;\r\n        return true;\r\n    }\r\n\r\n\r\n    T* dequeue(const int tid=0) {\r\n        Node* lhead = head;\r\n        if (lhead == tail) return nullptr;\r\n        head = lhead->next;\r\n        delete lhead;\r\n        return head->item;\r\n    }\r\n};\r\n\r\n#endif /* _SEQUENTIAL_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "datastructures/sequential/LinkedListSet.hpp",
    "content": "#ifndef _SEQUENTIAL_LINKED_LIST_SET_H_\r\n#define _SEQUENTIAL_LINKED_LIST_SET_H_\r\n\r\n#include <string>\r\n\r\n/**\r\n * <h1> A sequential implementation of La inked List Set </h1>\r\n *\r\n * This is meant to be used by the Universal Constructs\r\n *\r\n */\r\ntemplate<typename K>\r\nclass LinkedListSet {\r\n\r\nprivate:\r\n\r\n    struct Node {\r\n        K     key;\r\n        Node* next{nullptr};\r\n        Node(const K& key) : key{key}, next{nullptr} { }\r\n        Node(){ }\r\n    };\r\n\r\n    Node*  head {nullptr};\r\n    Node*  tail {nullptr};\r\n\r\n\r\npublic:\r\n    LinkedListSet() {\r\n\t\tNode* lhead = new Node();\r\n\t\tNode* ltail = new Node();\r\n\t\thead = lhead;\r\n\t\thead->next = ltail;\r\n\t\ttail = ltail;\r\n\r\n    }\r\n\r\n\r\n    // Universal Constructs need a copy constructor on the underlying data structure\r\n    LinkedListSet(const LinkedListSet& other) {\r\n        head = new Node();\r\n        Node* node = head;\r\n        Node* onode = other.head->next;\r\n        while (onode != other.tail) {\r\n            node->next = new Node(onode->key);\r\n            node = node->next;\r\n            onode = onode->next;\r\n        }\r\n        tail = new Node();\r\n        node->next = tail;\r\n    }\r\n\r\n\r\n    ~LinkedListSet() {\r\n\t\t// Delete all the nodes in the list\r\n\t\tNode* prev = head;\r\n\t\tNode* node = prev->next;\r\n\t\twhile (node != tail) {\r\n\t\t\tdelete prev;\r\n\t\t\tprev = node;\r\n\t\t\tnode = node->next;\r\n\t\t}\r\n\t\tdelete prev;\r\n\t\tdelete tail;\r\n    }\r\n\r\n\r\n    static std::string className() { return \"LinkedListSet\"; }\r\n\r\n\r\n    /*\r\n     * Adds a node with a key, returns false if the key is already in the set\r\n     */\r\n    bool add(const K& key) {\r\n        Node *prev, *node;\r\n        find(key, prev, node);\r\n        bool retval = !(node != tail && key == node->key);\r\n        if (!retval) return retval;\r\n        Node* newNode = new Node(key);\r\n        prev->next = newNode;\r\n        newNode->next = node;\r\n        return retval;\r\n    }\r\n\r\n\r\n    /*\r\n     * Removes a node with an key, returns false if the key is not in the set\r\n     */\r\n    bool remove(const K& key) {\r\n        Node *prev, *node;\r\n        find(key, prev, node);\r\n        bool retval = (node != tail && key == node->key);\r\n        if (!retval) return retval;\r\n        prev->next = node->next;\r\n        delete node;\r\n        return retval;\r\n    }\r\n\r\n\r\n    /*\r\n     * Returns true if it finds a node with a matching key\r\n     */\r\n    bool contains(const K& key) {\r\n        Node *prev, *node;\r\n        find(key, prev, node);\r\n        return (node != tail && key == node->key);\r\n    }\r\n\r\n    void find(const K& key, Node*& prev, Node*& node) {\r\n        for (prev = head; (node = prev->next) != tail; prev = node){\r\n            if ( !(node->key < key) ) break;\r\n        }\r\n    }\r\n\r\n    // Used only for benchmarks\r\n    bool addAll(K** keys, const int size) {\r\n        bool retval = false;\r\n        for (int i = 0; i < size; i++) {\r\n            Node *prev, *node;\r\n            find(*keys[i], prev, node);\r\n            retval = !(node != tail && *keys[i] == node->key);\r\n            if (retval) {\r\n                Node* newNode = new Node(*keys[i]);\r\n                prev->next = newNode;\r\n                newNode->next = node;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n};\r\n\r\n#endif /* _SEQUENTIAL_LINKED_LIST_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/sequential/RedBlackBST.hpp",
    "content": "#ifndef _RED_BLACK_BST_H_\r\n#define _RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n// Single-threaded implementation of a Red-Black Tree Map\r\n//http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V>\r\nclass RedBlackBST {\r\n\r\n\r\n    struct Node {\r\n        K* key;\r\n        V* val;\r\n        Node* left {nullptr};\r\n        Node* right {nullptr};\r\n        bool color;    // color of parent link\r\n        int size;      // subtree count\r\n        Node(K* key, V* val, bool color, int size) : key{key}, val{val}, color{color}, size{size} {}\r\n    };\r\n\r\n    Node *root {nullptr};   // root of the BST\r\n\r\n\r\n    static const bool RED   = true;\r\n    static const bool BLACK = false;\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    RedBlackBST(unsigned int maxThreads=128) { }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    V* get(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return get(root, key);\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    V* get(Node* x, K* key) {\r\n        while (x != nullptr) {\r\n            if      (*key < *x->key) x = x->left;\r\n            else if (*x->key < *key) x = x->right;\r\n            else              return x->val;\r\n        }\r\n        return nullptr;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool contains(K* key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    void put(K* key, V* val) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (val == nullptr) {\r\n            deleteKey(key);\r\n            return;\r\n        }\r\n\r\n        root = put(root, key, val);\r\n        root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, K* key, V* val) {\r\n        if (h == nullptr) return new Node(key, val, RED, 1);\r\n        if      (*key < *h->key) h->left  = put(h->left,  key, val);\r\n        else if (*h->key < *key) h->right = put(h->right, key, val);\r\n        else              h->val   = val;\r\n\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))      h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))     flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = RED;\r\n\r\n        root = deleteMin(root);\r\n        if (!isEmpty()) root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n\r\n        h->left = deleteMin(h->left);\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    void deleteKey(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (!contains(key)) return;\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = RED;\r\n\r\n        root = deleteKey(root, key);\r\n        if (!isEmpty()) root->color = BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, K* key) {\r\n        // assert get(h, key) != null;\r\n\r\n        if (*key < *h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left))\r\n                h = moveRedLeft(h);\r\n            h->left = deleteKey(h->left, key);\r\n        }\r\n        else {\r\n            if (isRed(h->left))\r\n                h = rotateRight(h);\r\n            if (*key == *h->key && (h->right == nullptr))\r\n                return nullptr;\r\n            if (!isRed(h->right) && !isRed(h->right->left))\r\n                h = moveRedRight(h);\r\n            if (*key == *h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                h->right = deleteMin(h->right);\r\n            }\r\n            else h->right = deleteKey(h->right, key);\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                      h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))     flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, K* key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (*key == *x->key) return x;\r\n        if (*key < *x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (isEmpty()) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, K* key) {\r\n        if (x == nullptr) return nullptr;\r\n        int cmp = key.compareTo(x->key);\r\n        if (*key == *x->key) return x;\r\n        if (*x->key < *key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            throw std::invalid_argument(\"item can not be nullptr\");\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(K* key) {\r\n        if (key == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(K* key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (*key < *x->key) return rank(key, x->left);\r\n        else if (*x->key < *key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(K* lo, K* hi) {\r\n        if (lo == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n        if (hi == nullptr) throw std::invalid_argument(\"item can not be nullptr\");\r\n\r\n        if (*lo < *hi) return 0;\r\n        if (contains(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Set methods\r\n    bool add(K* key, const int tid) {\r\n        if (contains(key)) return false;\r\n        put(key,key);\r\n        return true;\r\n    }\r\n\r\n    bool remove(K* key, const int tid) {\r\n        if (!contains(key)) return false;\r\n        deleteKey(key);\r\n        return true;\r\n    }\r\n\r\n    inline bool contains(K* key, const int tid) {\r\n        return contains(key);\r\n    }\r\n\r\n    std::string className() { return \"RedBlackBST\"; }\r\n\r\n};\r\n\r\n#endif   // _RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "datastructures/sequential/SortedArraySet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _SORTEDARRAYSET_H_\r\n#define _SORTEDARRAYSET_H_\r\n\r\n#include <iostream>\r\n\r\n// TODO: Test this for correctness\r\n\r\n/**\r\n * This is storing the pointers to the T instances, not the actual T instances.\r\n */\r\ntemplate<typename T>\r\nclass SortedArraySet {\r\n\r\nprivate:\r\n    unsigned max_size = 32;\r\n    T** vec;  // TODO: change this to T if we change the API from T* to T&\r\n    unsigned size = 0;\r\n    static const int NOT_FOUND = 0;\r\n    //std::atomic<bool> flag {false}; // For de debugging\r\n\r\n    int lookup(T* key) {\r\n        // Cover the special case of an empty array\r\n        if (size== 0) return NOT_FOUND;\r\n        int minPos = 0;\r\n        int maxPos = size-1;\r\n        //std::cout << \"vec[0] = \" << vec[0] << \"\\n\";\r\n        // Special cases for first and last items\r\n        if (*key < *(vec[0])) return NOT_FOUND;\r\n        if (*key == *(vec[0])) return 0;\r\n        if (*key == *(vec[maxPos])) return maxPos;\r\n        if (*(vec[maxPos]) < *key) return maxPos+1;\r\n        while (true) {\r\n            int pos = (maxPos-minPos)/2 + minPos;\r\n\r\n            if (*key < *(vec[pos])) {\r\n                maxPos = pos;\r\n            } else if (*key == *(vec[pos])) {\r\n                return pos;\r\n            } else {\r\n                minPos = pos;\r\n            }\r\n            if (maxPos-minPos <= 1) {\r\n                return maxPos;\r\n            }\r\n        }\r\n    }\r\n\r\n\r\npublic:\r\n    SortedArraySet() {\r\n        vec = new T*[max_size];\r\n    }\r\n\r\n    ~SortedArraySet() {\r\n        delete[] vec;\r\n    }\r\n\r\n    // We need a copy constructor to be able to use it in CXMutation\r\n    SortedArraySet(const SortedArraySet<T>& fromssv) {\r\n\r\n        vec = new T*[fromssv.max_size];\r\n        max_size = fromssv.max_size;\r\n        size = fromssv.size;\r\n        for(unsigned i=0;i<size;i++){\r\n            vec[i]=fromssv.vec[i];\r\n        }\r\n    }\r\n\r\n    static std::string className() { return \"SortedArraySet\"; }\r\n\r\n    void erase(int index){\r\n        //print();\r\n        for(unsigned i=index;i<size-1;i++){\r\n            vec[i] = vec[i+1];\r\n        }\r\n        size--;\r\n        //print();\r\n    }\r\n\r\n    /**\r\n     * When the curr.key is seen to be null it means we reached the tail node\r\n     */\r\n    bool remove(T* key) {\r\n        //if (flag.load()) std::cout << \"remove() ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOR\\n\";\r\n        //flag.store(true);\r\n        unsigned index = lookup(key);\r\n        if (index == size) {\r\n            //std::cout<<\"remove key \"<<key->seq<<\" \"<<key->tid<<\" vex \"<<index<<\"\\n\";\r\n            //flag.store(false);\r\n            return false;\r\n        }\r\n        if (*key == *(vec[index])) {\r\n            erase(index);\r\n            //flag.store(false);\r\n            return true;\r\n        }\r\n        //flag.store(false);\r\n        return false;\r\n    }\r\n\r\n\r\n    bool add(T* key) {\r\n        //if (flag.load()) std::cout << \"add() ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOR\\n\";\r\n        //flag.store(true);\r\n        unsigned index = lookup(key);\r\n        if (index != size && *key == *(vec[index])) {\r\n            //std::cout<<\"key \"<<key->seq<<\" \"<<key->tid<<\" vex \"<<index<<\" \"<<vec[index]->seq<< \" \" << vec[index]->tid<<\"\\n\";\r\n            //assert(false);\r\n            //flag.store(false);\r\n            return false;\r\n        }\r\n\r\n        if(size+1==max_size){\r\n            T** newvec = new T*[2*max_size];\r\n            for(unsigned i=0;i<index;i++){\r\n                newvec[i]=vec[i];\r\n            }\r\n\r\n            for(unsigned i=index;i<size;i++){\r\n                newvec[i+1]=vec[i];\r\n            }\r\n            newvec[index]= key;\r\n            delete[] vec;\r\n            vec = newvec;\r\n            max_size = 2*max_size;\r\n        }else{\r\n            if(index<size){\r\n                for(unsigned i=size;i>=index+1;i--){\r\n                    vec[i]=vec[i-1];\r\n                }\r\n            }\r\n            vec[index] = key;\r\n        }\r\n        size++;\r\n        //flag.store(false);\r\n        return true;\r\n    }\r\n\r\n\r\n     bool contains(T* key) {\r\n        //if (flag.load()) std::cout << \"contains() ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOR\\n\";\r\n        unsigned index = lookup(key);\r\n        if (index == size) {\r\n            return false;\r\n        }\r\n        return *key == *(vec[index]);\r\n    }\r\n\r\n\r\n    bool print() { // For debug purposes\r\n        for(unsigned i=0;i<size;i++){\r\n            std:: cout << vec[i] << \",\";\r\n        }\r\n        std::cout << \"\\n\";\r\n        return true;\r\n    }\r\n\r\n};\r\n\r\n#endif /* _SORTEDARRAYSET_H_ */\r\n"
  },
  {
    "path": "datastructures/sequential/SortedVectorSet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _SORTED_VECTOR_SET_H_\r\n#define _SORTED_VECTOR_SET_H_\r\n\r\n#include <vector>\r\n#include <iostream>\r\n\r\n// TODO: Test this for correctness\r\n\r\n/**\r\n * This is storing the pointers to the T instances, not the actual T instances.\r\n */\r\ntemplate<typename T>\r\nclass SortedVectorSet {\r\n\r\nprivate:\r\n    std::vector<T*> vec;  // TODO: change this to T if we change the API from T* to T&\r\n    static const int NOT_FOUND = 0;\r\n    //std::atomic<bool> flag {false}; // For de debugging\r\n\r\n    int lookup(T* key) {\r\n        // Cover the special case of an empty array\r\n        if (vec.size()== 0) return NOT_FOUND;\r\n        int minPos = 0;\r\n        int maxPos = vec.size()-1;\r\n        // Special cases for first and last items\r\n        if (*key < *(vec[0])) return NOT_FOUND;\r\n        if (*key == *(vec[0])) return 0;\r\n        if (*key == *(vec[maxPos])) return maxPos;\r\n        if (*(vec[maxPos]) < *key) return maxPos+1;\r\n        while (true) {\r\n            int pos = (maxPos-minPos)/2 + minPos;\r\n            if (*key < *(vec[pos])) {\r\n                maxPos = pos;\r\n            } else if (*key == *(vec[pos])) {\r\n                return pos;\r\n            } else {\r\n                minPos = pos;\r\n            }\r\n            if (maxPos-minPos <= 1) {\r\n                return maxPos;\r\n            }\r\n        }\r\n    }\r\n\r\n\r\npublic:\r\n    SortedVectorSet() { }\r\n\r\n    // We need a copy constructor to be able to use it in CXMutation\r\n    SortedVectorSet(const SortedVectorSet<T>& from) {\r\n        vec = from.vec; // Do a copy of the vector\r\n    }\r\n\r\n    static std::string className() { return \"SortedVectorSet\"; }\r\n\r\n    /**\r\n     * When the curr.key is seen to be null it means we reached the tail node\r\n     */\r\n    bool remove(T* key) {\r\n        //if (flag.load()) std::cout << \"remove() ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOR\\n\";\r\n        //flag.store(true);\r\n        unsigned index = lookup(key);\r\n        if (index == vec.size()) {\r\n            //std::cout<<\"remove key \"<<key->seq<<\" \"<<key->tid<<\" vex \"<<index<<\"\\n\";\r\n            //flag.store(false);\r\n            return false;\r\n        }\r\n        if (*key == *(vec[index])) {\r\n            vec.erase(vec.begin()+index);\r\n            //flag.store(false);\r\n            return true;\r\n        }\r\n        //flag.store(false);\r\n        return false;\r\n    }\r\n\r\n\r\n    bool add(T* key) {\r\n        //if (flag.load()) std::cout << \"add() ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOR\\n\";\r\n        //flag.store(true);\r\n        unsigned index = lookup(key);\r\n        if (index != vec.size() && *key == *(vec[index])) {\r\n            //std::cout<<\"key \"<<key->seq<<\" \"<<key->tid<<\" vex \"<<index<<\" \"<<vec[index]->seq<< \" \" << vec[index]->tid<<\"\\n\";\r\n            //assert(false);\r\n            //flag.store(false);\r\n            return false;\r\n        }\r\n        vec.insert(vec.begin()+index, key);\r\n        //flag.store(false);\r\n        return true;\r\n    }\r\n\r\n\r\n     bool contains(T* key) {\r\n        //if (flag.load()) std::cout << \"contains() ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOR\\n\";\r\n        unsigned index = lookup(key);\r\n        if (index == vec.size()) {\r\n            return false;\r\n        }\r\n        return *key == *(vec[index]);\r\n    }\r\n\r\n\r\n    bool print() { // For debug purposes\r\n        for (T* p : vec) std:: cout << p << \",\";\r\n        std::cout << \"\\n\";\r\n        return true;\r\n    }\r\n};\r\n\r\n#endif /* _SORTED_VECTOR_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/sequential/TreeSet.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _CX_TREE_SET_H_\r\n#define _CX_TREE_SET_H_\r\n\r\n#include <iostream>\r\n#include <functional>\r\n#include <set>\r\n\r\n//#include \"../datastructures/sequential/RedBlackBST.hpp\"\r\n\r\n// TODO: change CKey* to CKey&\r\n\r\n// This is a wrapper to std::set, which should be a Red-Black tree\r\ntemplate<typename CKey>\r\nclass TreeSet {\r\n\r\nprivate:\r\n    std::set<CKey> set;\r\n    // Use this instead if we want to have control over the Red-Black tree\r\n    //RedBlackBST<CKey,CKey> set;\r\n\r\npublic:\r\n\r\n    static std::string className() { return \"TreeSet\"; }\r\n\r\n\r\n    bool add(CKey key) {\r\n        if (set.find(key) == set.end()) {\r\n            set.insert(key); // TODO: can we improve this so we don't have to lookup twice?\r\n            return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    bool remove(CKey key) {\r\n        auto iter = set.find(key);\r\n        if (iter == set.end()) return false;\r\n        set.erase(iter);\r\n        return true;\r\n    }\r\n\r\n    bool contains(CKey key) {\r\n        if (set.find(key) == set.end()) return false;\r\n        return true;  // TODO: optimize this\r\n    }\r\n\r\n    bool iterateAll(std::function<bool(CKey*)> itfunc) {\r\n\t\tfor (auto it = set.begin(); it != set.end(); ++it) {\r\n\t\t\tCKey key = *it;\r\n\t\t\tif (!itfunc(&key)) return false;\r\n\t\t}\r\n\t\treturn true;\r\n    }\r\n/*\r\n    bool add(CKey* key) {\r\n        return set.add(key, 0);\r\n    }\r\n\r\n    bool remove(CKey* key) {\r\n        return set.remove(key, 0);\r\n    }\r\n\r\n    bool contains(CKey* key) {\r\n        return set.contains(key, 0);\r\n    }\r\n*/\r\n};\r\n\r\n#endif /* _TREE_SET_H_ */\r\n"
  },
  {
    "path": "datastructures/treemaps/ESTMRedBlackTree.hpp",
    "content": "#ifndef _ESTM_RED_BLACK_BST_H_\r\n#define _ESTM_RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n#include \"stms/ESTM.hpp\"\r\n\r\n// Adapted from Java to C++ from the original at http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V>\r\nclass ESTMRedBlackTree {\r\n    const int64_t COLOR_RED   = 0;\r\n    const int64_t COLOR_BLACK = 1;\r\n\r\n    struct Node {\r\n        estm::tmtype<K>       key;\r\n        estm::tmtype<V>       val;\r\n        estm::tmtype<Node*>   left {nullptr};\r\n        estm::tmtype<Node*>   right {nullptr};\r\n        estm::tmtype<int64_t> color;    // color of parent link\r\n        estm::tmtype<int64_t> size;     // subtree count\r\n        Node(const K& key, const V& val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\r\n    };\r\n\r\n    estm::tmtype<Node*> root {nullptr};   // root of the BST\r\n\r\n    inline void assignAndFreeIfNull(estm::tmtype<Node*>& z, Node* w) {\r\n        Node* tofree = z;\r\n        z = w;\r\n        if (w == nullptr) estm::tmDelete(tofree);\r\n    }\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    ESTMRedBlackTree(int maxThreads=0){ }\r\n\r\n    ~ESTMRedBlackTree() {\r\n        // The transaction log is not enough to delete everything if there are too many, so we delete 1000 per transaction\r\n        for (int i = 0; i < 1000; i++) {\r\n            estm::updateTx<bool>([&] () {\r\n                if (root == nullptr) return true;\r\n                deleteMin();\r\n                return true;\r\n            });\r\n        }\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == COLOR_RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerGet(K& key, V& oldValue, const bool saveOldValue) {\r\n        bool found = get(root, key);\r\n        if (!found) return false;\r\n        //if (saveOldValue) oldValue = *val; // Copy of V\r\n        return true;\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    bool get(Node* x, K& key) {\r\n        while (x != nullptr) {\r\n            if      (key < x->key) x = x->left;\r\n            else if (x->key < key) x = x->right;\r\n            else              return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool containsKey(const K& key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerPut(const K& key, const V& value) {\r\n    \tbool ret = false;\r\n        root = put(root, key, value, ret);\r\n        root->color = COLOR_BLACK;\r\n        return ret;\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, const K& key, const V& val, bool& ret) {\r\n        if (h == nullptr) {\r\n        \tret = true;\r\n        \treturn estm::tmNew<Node>(key, val, COLOR_RED, 1);\r\n        }\r\n        if      (key < h->key) h->left  = put(h->left,  key, val, ret);\r\n        else if (h->key < key) h->right = put(h->right, key, val, ret);\r\n        else              h->val   = val;\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) return;\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteMin(root));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) return;\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     */\r\n    void innerRemove(const K& key) {\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right)) root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteKey(root, key));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, const K& key) {\r\n        // assert get(h, key) != null;\r\n        if (key < h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left)) {\r\n                h = moveRedLeft(h);\r\n            }\r\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\r\n        } else {\r\n            if (isRed(h->left)) {\r\n                h = rotateRight(h);\r\n            }\r\n            if (key == h->key && (h->right == nullptr)) {\r\n                return nullptr;\r\n            }\r\n            if (!isRed(h->right) && !isRed(h->right->left)) {\r\n                h = moveRedRight(h);\r\n            }\r\n            if (key == h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\r\n            } else {\r\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\r\n            }\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                        h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) return nullptr;\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) return nullptr;\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (key < x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (x->key < key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            return nullptr;\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(const K& key) {\r\n        if (key == nullptr) return -1;\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(const K& key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (key < x->key) return rank(key, x->left);\r\n        else if (x->key < key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(const K& lo, const K& hi) {\r\n        if (lo == nullptr) return 0;\r\n        if (hi == nullptr) return 0;\r\n\r\n        if (hi < lo) return 0;\r\n        if (containsKey(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        // TODO: port these two lines\r\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(const K& key, const int tid=0) {\r\n        bool retval = false;\r\n        estm::updateTx([&] () {\r\n        \tretval = innerPut(key,key);\r\n        });\r\n        return retval;\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K& key, const int tid=0) {\r\n        bool retval = false;\r\n        estm::updateTx([&] () {\r\n            V notused;\r\n            retval = innerGet(key,notused,false);\r\n            if (retval) innerRemove(key);\r\n        });\r\n        return retval;\r\n    }\r\n\r\n    bool contains(K& key, const int tid=0) {\r\n        bool retval = false;\r\n        estm::readTx([&] () {\r\n            V notused;\r\n            retval = innerGet(key,notused,false);\r\n        });\r\n        return retval;\r\n    }\r\n\r\n    // This is not fully transactionally but it's ok because we use it only on initialization.\r\n    // We could make it fully transactionally, but we would have to increase the size of allocation/store logs.\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return estm::ESTM::className() + \"-RedBlackTree\"; }\r\n\r\n};\r\n\r\n#endif   // _ESTM_RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "datastructures/treemaps/HazardEras.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2016-2017, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_ERAS_H_\r\n#define _HAZARD_ERAS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <vector>\r\n#include <algorithm>\r\n\r\n/*\r\n * <h1> Hazard Eras </h1>\r\n * This a light-weight implementation of hazard eras, where each thread has a\r\n * thread-local list of retired objects.\r\n *\r\n * This is based on the paper \"Hazard Eras - Non-Blocking Memory Reclamation\"\r\n * by Pedro Ramalhete and Andreia Correia:\r\n * https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf\r\n *\r\n * The type T is for the objects/nodes and it's it must have the members newEra, delEra\r\n *\r\n * R is zero.\r\n *\r\n * <p>\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\ntemplate<typename T>\r\nclass HazardEras {\r\n\r\nprivate:\r\n    static const uint64_t NONE = 0;\r\n    static const int      HE_MAX_THREADS = 128;\r\n    static const int      MAX_HES = 5;        // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HE_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n\r\n    const int             maxHEs;\r\n    const int             maxThreads;\r\n\r\n    alignas(128) std::atomic<uint64_t>  eraClock {1};\r\n    alignas(128) std::atomic<uint64_t>* he[HE_MAX_THREADS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<T*>        retiredList[HE_MAX_THREADS*CLPAD];\r\n\r\npublic:\r\n    HazardEras(int maxHEs=MAX_HES, int maxThreads=HE_MAX_THREADS) : maxHEs{maxHEs}, maxThreads{maxThreads} {\r\n        for (int it = 0; it < HE_MAX_THREADS; it++) {\r\n            he[it] = new std::atomic<uint64_t>[CLPAD*2]; // We allocate four cache lines to allow for many hps and without false sharing\r\n            retiredList[it*CLPAD].reserve(maxThreads*maxHEs);\r\n            for (int ihe = 0; ihe < MAX_HES; ihe++) {\r\n                he[it][ihe].store(NONE, std::memory_order_relaxed);\r\n            }\r\n        }\r\n        static_assert(std::is_same<decltype(T::newEra), uint64_t>::value, \"T::newEra must be uint64_t\");\r\n        static_assert(std::is_same<decltype(T::delEra), uint64_t>::value, \"T::delEra must be uint64_t\");\r\n    }\r\n\r\n    ~HazardEras() {\r\n        for (int it = 0; it < HE_MAX_THREADS; it++) {\r\n            delete[] he[it];\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[it*CLPAD].size(); iret++) {\r\n                delete retiredList[it*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    inline uint64_t getEra() {\r\n        return eraClock.load();\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHEs)\r\n     */\r\n    inline void clear(const int tid) {\r\n        for (int ihe = 0; ihe < maxHEs; ihe++) {\r\n            he[tid][ihe].store(NONE, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    inline T* get_protected(int index, const std::atomic<T*>& atom, const int tid) {\r\n        auto prevEra = he[tid][index].load(std::memory_order_relaxed);\r\n\t\twhile (true) {\r\n\t\t    T* ptr = atom.load();\r\n\t\t    auto era = eraClock.load(std::memory_order_acquire);\r\n\t\t    if (era == prevEra) return ptr;\r\n            he[tid][index].store(era);\r\n            prevEra = era;\r\n\t\t}\r\n    }\r\n\r\n    inline void protectEraRelease(int index, int other, const int tid) {\r\n        auto era = he[tid][other].load(std::memory_order_relaxed);\r\n        if (he[tid][index].load(std::memory_order_relaxed) == era) return;\r\n        he[tid][index].store(era, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /*\r\n     * Does a single iteration. Must be integrated into the algorithm that's using HE.\r\n     * In other words, we must re-check if era has changed\r\n     *\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    inline T* protectPtr(int index, const std::atomic<T*>& atom, uint64_t& prevEra, const int tid) {\r\n        T* ptr = atom.load(std::memory_order_acquire);\r\n        auto era = eraClock.load();\r\n        if (prevEra != era) {\r\n            prevEra = era;\r\n            he[tid][index].store(era, std::memory_order_relaxed);\r\n            std::atomic_thread_fence(std::memory_order_seq_cst);\r\n        }\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * Retire an object (node)\r\n     * Progress Condition: wait-free bounded\r\n     *\r\n     * Doing rlist.erase() is not the most efficient way to remove entries from a std::vector, but ok...\r\n     */\r\n    void retire(T* ptr, const int mytid) {\r\n        auto currEra = eraClock.load();\r\n        ptr->delEra = currEra;\r\n        auto& rlist = retiredList[mytid*CLPAD];\r\n        rlist.push_back(ptr);\r\n        if (eraClock == currEra) eraClock.fetch_add(1);\r\n        for (unsigned iret = 0; iret < rlist.size();) {\r\n            auto obj = rlist[iret];\r\n            if (canDelete(obj, mytid)) {\r\n                rlist.erase(rlist.begin() + iret);\r\n                delete obj;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n\r\nprivate:\r\n    bool canDelete(T* obj, const int mytid) {\r\n        for (int tid = 0; tid < maxThreads; tid++) {\r\n            for (int ihe = 0; ihe < maxHEs; ihe++) {\r\n                const auto era = he[tid][ihe].load(std::memory_order_acquire);\r\n                if (era == NONE || era < obj->newEra || era > obj->delEra) continue;\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n};\r\n\r\n#endif /* _HAZARD_ERAS_H_ */\r\n"
  },
  {
    "path": "datastructures/treemaps/NatarajanTreeHE.hpp",
    "content": "/*\r\n\r\nCopyright 2017 University of Rochester\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\nhttp://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n\r\nAdapted from https://github.com/roghnin/Interval-Based-Reclamation/blob/master/src/rideables/NatarajanTree.hpp\r\n\r\nDue to the usage of <optional>, this needs C++17 to compile\r\n\r\nPedro: I've adapted this for our benchmarks but the adaptation may contain errors, please do not use this code in production!\r\n*/\r\n\r\n\r\n#ifndef _NATARAJAN_TREE_HAZARD_ERAS_H_\r\n#define _NATARAJAN_TREE_HAZARD_ERAS_H_\r\n\r\n#include <iostream>\r\n#include <atomic>\r\n#include <algorithm>\r\n#include <map>\r\n#include <optional>\r\n#include \"common/HazardEras.hpp\"\r\n\r\n\r\ntemplate <class K, class V>\r\nclass NatarajanTreeHE {\r\nprivate:\r\n    const int MAX_THREADS = 128;\r\n    /* structs*/\r\n    struct Node {\r\n        int level;\r\n        K key;\r\n        V val;\r\n        std::atomic<Node*> left;\r\n        std::atomic<Node*> right;\r\n        uint64_t newEra {0};          // TODO: put he.getEra() here\r\n        uint64_t delEra;\r\n        Node(uint64_t newEra) : newEra{newEra} {};\r\n        Node(uint64_t newEra, K k, V v, Node* l, Node* r,int lev):level(lev),key(k),val(v),left(l),right(r),newEra{newEra} {};\r\n        Node(uint64_t newEra, K k, V v, Node* l, Node* r):level(-1),key(k),val(v),left(l),right(r),newEra{newEra} {};\r\n    };\r\n    struct SeekRecord{\r\n        Node* ancestor;\r\n        Node* successor;\r\n        Node* parent;\r\n        Node* leaf;\r\n    };\r\n\r\n    /* variables */\r\n    HazardEras<Node> he {5, MAX_THREADS};\r\n\r\n    K infK{};\r\n    V defltV{};\r\n    Node* r;\r\n    Node* s;\r\n    SeekRecord* records;\r\n    const size_t GET_POINTER_BITS = 0xfffffffffffffffc;//for machine 64-bit or less.\r\n\r\n    /* helper functions */\r\n    //flag and tags helpers\r\n    inline Node* getPtr(Node* mptr){\r\n        return (Node*) ((size_t)mptr & GET_POINTER_BITS);\r\n    }\r\n    inline bool getFlg(Node* mptr){\r\n        return (bool)((size_t)mptr & 1);\r\n    }\r\n    inline bool getTg(Node* mptr){\r\n        return (bool)((size_t)mptr & 2);\r\n    }\r\n    inline Node* mixPtrFlgTg(Node* ptr, bool flg, bool tg){\r\n        return (Node*) ((size_t)ptr | flg | ((size_t)tg<<1));\r\n    }\r\n    //node comparison\r\n    inline bool isInf(Node* n){\r\n        return getInfLevel(n)!=-1;\r\n    }\r\n    inline int getInfLevel(Node* n){\r\n        //0 for inf0, 1 for inf1, 2 for inf2, -1 for general val\r\n        n=getPtr(n);\r\n        return n->level;\r\n    }\r\n    inline bool nodeLess(Node* n1, Node* n2){\r\n        n1=getPtr(n1);\r\n        n2=getPtr(n2);\r\n        int i1=getInfLevel(n1);\r\n        int i2=getInfLevel(n2);\r\n        return i1<i2 || (i1==-1&&i2==-1&&n1->key<n2->key);\r\n    }\r\n    inline bool nodeEqual(Node* n1, Node* n2){\r\n        n1=getPtr(n1);\r\n        n2=getPtr(n2);\r\n        int i1=getInfLevel(n1);\r\n        int i2=getInfLevel(n2);\r\n        if(i1==-1&&i2==-1)\r\n            return n1->key==n2->key;\r\n        else\r\n            return i1==i2;\r\n    }\r\n    inline bool nodeLessEqual(Node* n1, Node* n2){\r\n        return !nodeLess(n2,n1);\r\n    }\r\n\r\n    /* private interfaces */\r\n    void seek(K key, int tid);\r\n    bool cleanup(K key, int tid);\r\n    void doRangeQuery(Node& k1, Node& k2, int tid, Node* root, std::map<K,V>& res);\r\npublic:\r\n    NatarajanTreeHE(const int maxThreads=0) {\r\n        r = new Node(he.getEra(), infK,defltV,nullptr,nullptr,2);\r\n        s = new Node(he.getEra(), infK,defltV,nullptr,nullptr,1);\r\n        r->right = new Node(he.getEra(), infK,defltV,nullptr,nullptr,2);\r\n        r->left = s;\r\n        s->right = new Node(he.getEra(), infK,defltV,nullptr,nullptr,1);\r\n        s->left = new Node(he.getEra(), infK,defltV,nullptr,nullptr,0);\r\n        records = new SeekRecord[MAX_THREADS]{};\r\n    };\r\n    ~NatarajanTreeHE(){};\r\n\r\n    static std::string className() { return \"NatarajanTreeHE\"; }\r\n    std::optional<V> get(K key, int tid);\r\n    std::optional<V> put(K key, V val, int tid);\r\n    bool insert(K key, V val, int tid);\r\n    std::optional<V> innerRemove(K key, int tid);\r\n    std::optional<V> replace(K key, V val, int tid);\r\n    std::map<K, V> rangeQuery(K key1, K key2, int& len, int tid);\r\n\r\n    // Used only by our tree benchmarks\r\n    bool add(K key, int tid);\r\n    bool remove(K key, int tid);\r\n    bool contains(K key, int tid);\r\n    void addAll(K** keys, const int size, const int tid);\r\n};\r\n\r\n//-------Definition----------\r\ntemplate <class K, class V>\r\nvoid NatarajanTreeHE<K,V>::seek(K key, int tid){\r\n    /* initialize the seek record using sentinel nodes */\r\n    Node keyNode{he.getEra(),key,defltV,nullptr,nullptr};//node to be compared\r\n    SeekRecord* seekRecord = &(records[tid]);\r\n    seekRecord->ancestor = r;\r\n    seekRecord->successor = he.get_protected(1, r->left, tid);\r\n    seekRecord->parent = he.get_protected(2, r->left, tid);\r\n    seekRecord->leaf = getPtr(he.get_protected(3, s->left, tid));\r\n\r\n    /* initialize other variables used in the traversal */\r\n    Node* parentField = he.get_protected(3, seekRecord->parent->left, tid);\r\n    Node* currentField = he.get_protected(4, seekRecord->leaf->left,tid);\r\n    Node* current = getPtr(currentField);\r\n\r\n    /* traverse the tree */\r\n    while(current!=nullptr){\r\n        /* check if the edge from the current parent node is tagged */\r\n        if(!getTg(parentField)){\r\n            /*\r\n             * found an untagged edge in the access path;\r\n             * advance ancestor and successor pointers.\r\n             */\r\n            seekRecord->ancestor=seekRecord->parent;\r\n            he.protectEraRelease(0, 1, tid);\r\n            seekRecord->successor=seekRecord->leaf;\r\n            he.protectEraRelease(1, 3, tid);\r\n        }\r\n\r\n        /* advance parent and leaf pointers */\r\n        seekRecord->parent = seekRecord->leaf;\r\n        he.protectEraRelease(2, 3, tid);\r\n        seekRecord->leaf = current;\r\n        he.protectEraRelease(3, 4, tid);\r\n\r\n        /* update other variables used in traversal */\r\n        parentField=currentField;\r\n        if(nodeLess(&keyNode,current)){\r\n            currentField = he.get_protected(4, current->left, tid);\r\n        }\r\n        else{\r\n            currentField = he.get_protected(4, current->right, tid);\r\n        }\r\n        current=getPtr(currentField);\r\n    }\r\n    /* traversal complete */\r\n    return;\r\n}\r\n\r\ntemplate <class K, class V>\r\nbool NatarajanTreeHE<K,V>::cleanup(K key, int tid){\r\n    Node keyNode{he.getEra(),key,defltV,nullptr,nullptr};//node to be compared\r\n    bool res=false;\r\n\r\n    /* retrieve addresses stored in seek record */\r\n    SeekRecord* seekRecord=&(records[tid]);\r\n    Node* ancestor=getPtr(seekRecord->ancestor);\r\n    Node* successor=getPtr(seekRecord->successor);\r\n    Node* parent=getPtr(seekRecord->parent);\r\n    Node* leaf=getPtr(seekRecord->leaf);\r\n\r\n    std::atomic<Node*>* successorAddr=nullptr;\r\n    std::atomic<Node*>* childAddr=nullptr;\r\n    std::atomic<Node*>* siblingAddr=nullptr;\r\n\r\n    /* obtain address of field of ancestor node that will be modified */\r\n    if(nodeLess(&keyNode,ancestor))\r\n        successorAddr=&(ancestor->left);\r\n    else\r\n        successorAddr=&(ancestor->right);\r\n\r\n    /* obtain addresses of child fields of parent node */\r\n    if(nodeLess(&keyNode,parent)){\r\n        childAddr=&(parent->left);\r\n        siblingAddr=&(parent->right);\r\n    }\r\n    else{\r\n        childAddr=&(parent->right);\r\n        siblingAddr=&(parent->left);\r\n    }\r\n    Node* tmpChild=childAddr->load(std::memory_order_acquire);\r\n    if(!getFlg(tmpChild)){\r\n        /* the leaf is not flagged, thus sibling node should be flagged */\r\n        tmpChild=siblingAddr->load(std::memory_order_acquire);\r\n        /* switch the sibling address */\r\n        siblingAddr=childAddr;\r\n    }\r\n\r\n    /* use TAS to tag sibling edge */\r\n    while(true){\r\n        Node* untagged=siblingAddr->load(std::memory_order_acquire);\r\n        Node* tagged=mixPtrFlgTg(getPtr(untagged),getFlg(untagged),true);\r\n        if(siblingAddr->compare_exchange_strong(untagged,tagged,std::memory_order_acq_rel)){\r\n            break;\r\n        }\r\n    }\r\n    /* read the flag and address fields */\r\n    Node* tmpSibling=siblingAddr->load(std::memory_order_acquire);\r\n\r\n    /* make the sibling node a direct child of the ancestor node */\r\n    res=successorAddr->compare_exchange_strong(successor,\r\n        mixPtrFlgTg(getPtr(tmpSibling),getFlg(tmpSibling),false),\r\n        std::memory_order_acq_rel);\r\n\r\n    if(res==true){\r\n        he.retire(getPtr(tmpChild),tid);\r\n        he.retire(successor,tid);\r\n    }\r\n    return res;\r\n}\r\n\r\n/* to test rangeQuery */\r\n// template <>\r\n// optional<int> NatarajanTree<int,int>::get(int key, int tid){\r\n//  int len=0;\r\n//  auto x = rangeQuery(key-500,key,len,tid);\r\n//  Node keyNode{key,defltV,nullptr,nullptr};//node to be compared\r\n//  optional<int> res={};\r\n//  SeekRecord* seekRecord=&(records[tid].ui);\r\n//  Node* leaf=nullptr;\r\n//  seek(key,tid);\r\n//  leaf=getPtr(seekRecord->leaf);\r\n//  if(nodeEqual(&keyNode,leaf)){\r\n//      res = leaf->val;\r\n//  }\r\n//  return res;\r\n// }\r\n\r\ntemplate <class K, class V>\r\nstd::optional<V> NatarajanTreeHE<K,V>::get(K key, int tid){\r\n    Node keyNode{he.getEra(),key,defltV,nullptr,nullptr};//node to be compared\r\n    std::optional<V> res={};\r\n    SeekRecord* seekRecord=&(records[tid]);\r\n    Node* leaf=nullptr;\r\n    seek(key,tid);\r\n    leaf=getPtr(seekRecord->leaf);\r\n    if(nodeEqual(&keyNode,leaf)){\r\n        res = leaf->val;\r\n    }\r\n    he.clear(tid);\r\n    return res;\r\n}\r\n\r\ntemplate <class K, class V>\r\nstd::optional<V> NatarajanTreeHE<K,V>::put(K key, V val, int tid){\r\n    std::optional<V> res={};\r\n    SeekRecord* seekRecord=&(records[tid]);\r\n\r\n    Node* newInternal=nullptr;\r\n    Node* newLeaf = new Node(he.getEra(),key,val,nullptr,nullptr);//also to compare keys\r\n\r\n    Node* parent=nullptr;\r\n    Node* leaf=nullptr;\r\n    std::atomic<Node*>* childAddr=nullptr;\r\n\r\n    while(true){\r\n        seek(key,tid);\r\n        leaf=getPtr(seekRecord->leaf);\r\n        parent=getPtr(seekRecord->parent);\r\n        if(!nodeEqual(newLeaf,leaf)){//key does not exist\r\n            /* obtain address of the child field to be modified */\r\n            if(nodeLess(newLeaf,parent))\r\n                childAddr=&(parent->left);\r\n            else\r\n                childAddr=&(parent->right);\r\n\r\n            /* create left and right leave of newInternal */\r\n            Node* newLeft=nullptr;\r\n            Node* newRight=nullptr;\r\n            if(nodeLess(newLeaf,leaf)){\r\n                newLeft=newLeaf;\r\n                newRight=leaf;\r\n            }\r\n            else{\r\n                newLeft=leaf;\r\n                newRight=newLeaf;\r\n            }\r\n\r\n            /* create newInternal */\r\n            if(isInf(leaf)){\r\n                int lev=getInfLevel(leaf);\r\n                newInternal = new Node(he.getEra(),infK,defltV,newLeft,newRight,lev);\r\n            }\r\n            else\r\n                newInternal = new Node(he.getEra(),std::max(key,leaf->key),defltV,newLeft,newRight);\r\n\r\n            /* try to add the new nodes to the tree */\r\n            Node* tmpExpected=getPtr(leaf);\r\n            if(childAddr->compare_exchange_strong(tmpExpected,getPtr(newInternal),std::memory_order_acq_rel)){\r\n                res={};\r\n                break;//insertion succeeds\r\n            }\r\n            else{//fails; help conflicting delete operation\r\n                delete newInternal;\r\n                Node* tmpChild=childAddr->load(std::memory_order_acquire);\r\n                if(getPtr(tmpChild)==leaf && (getFlg(tmpChild)||getTg(tmpChild))){\r\n                    /*\r\n                     * address of the child has not changed\r\n                     * and either the leaf node or its sibling\r\n                     * has been flagged for deletion\r\n                     */\r\n                    cleanup(key,tid);\r\n                }\r\n            }\r\n        }\r\n        else{//key exists, update and return old\r\n            res=leaf->val;\r\n            if(nodeLess(newLeaf,parent))\r\n                childAddr=&(parent->left);\r\n            else\r\n                childAddr=&(parent->right);\r\n            if(childAddr->compare_exchange_strong(leaf,newLeaf,std::memory_order_acq_rel)){\r\n                he.retire(leaf,tid);\r\n                break;\r\n            }\r\n        }\r\n    }\r\n    he.clear(tid);\r\n    return res;\r\n}\r\n\r\ntemplate <class K, class V>\r\nbool NatarajanTreeHE<K,V>::insert(K key, V val, int tid) {\r\n    bool res=false;\r\n    SeekRecord* seekRecord=&(records[tid]);\r\n\r\n    Node* newInternal=nullptr;\r\n    Node* newLeaf = new Node(he.getEra(),key,val,nullptr,nullptr);//also for comparing keys\r\n\r\n    Node* parent=nullptr;\r\n    Node* leaf=nullptr;\r\n    std::atomic<Node*>* childAddr=nullptr;\r\n    while(true){\r\n        seek(key,tid);\r\n        leaf=getPtr(seekRecord->leaf);\r\n        parent=getPtr(seekRecord->parent);\r\n        if(!nodeEqual(newLeaf,leaf)){//key does not exist\r\n            /* obtain address of the child field to be modified */\r\n            if(nodeLess(newLeaf,parent))\r\n                childAddr=&(parent->left);\r\n            else\r\n                childAddr=&(parent->right);\r\n\r\n            /* create left and right leave of newInternal */\r\n            Node* newLeft=nullptr;\r\n            Node* newRight=nullptr;\r\n            if(nodeLess(newLeaf,leaf)){\r\n                newLeft=newLeaf;\r\n                newRight=leaf;\r\n            }\r\n            else{\r\n                newLeft=leaf;\r\n                newRight=newLeaf;\r\n            }\r\n\r\n            /* create newInternal */\r\n            if(isInf(leaf)){\r\n                int lev=getInfLevel(leaf);\r\n                newInternal = new Node(he.getEra(),infK,defltV,newLeft,newRight,lev);\r\n            }\r\n            else\r\n                newInternal = new Node(he.getEra(),std::max(key,leaf->key),defltV,newLeft,newRight);\r\n\r\n            /* try to add the new nodes to the tree */\r\n            Node* tmpExpected=getPtr(leaf);\r\n            if(childAddr->compare_exchange_strong(tmpExpected,getPtr(newInternal),std::memory_order_acq_rel)){\r\n                res=true;\r\n                break;//insertion succeeds\r\n            }\r\n            else{//fails; help conflicting delete operation\r\n                delete newInternal;\r\n                Node* tmpChild=childAddr->load(std::memory_order_acquire);\r\n                if(getPtr(tmpChild)==leaf && (getFlg(tmpChild)||getTg(tmpChild))){\r\n                    /*\r\n                     * address of the child has not changed\r\n                     * and either the leaf node or its sibling\r\n                     * has been flagged for deletion\r\n                     */\r\n                    cleanup(key,tid);\r\n                }\r\n            }\r\n        }\r\n        else{//key exists, insertion fails\r\n            delete newLeaf;\r\n            res=false;\r\n            break;\r\n        }\r\n    }\r\n    he.clear(tid);\r\n    return res;\r\n}\r\n\r\ntemplate <class K, class V>\r\nstd::optional<V> NatarajanTreeHE<K,V>::innerRemove(K key, int tid){\r\n    bool injecting = true;\r\n    std::optional<V> res={};\r\n    SeekRecord* seekRecord=&(records[tid]);\r\n\r\n    Node keyNode{he.getEra(),key,defltV,nullptr,nullptr};//node to be compared\r\n\r\n    Node* parent=nullptr;\r\n    Node* leaf=nullptr;\r\n    std::atomic<Node*>* childAddr=nullptr;\r\n    while(true){\r\n        seek(key,tid);\r\n        parent=getPtr(seekRecord->parent);\r\n        /* obtain address of the child field to be modified */\r\n        if(nodeLess(&keyNode,parent))\r\n            childAddr=&(parent->left);\r\n        else\r\n            childAddr=&(parent->right);\r\n\r\n        if(injecting){\r\n            /* injection mode: check if the key exists */\r\n            leaf=getPtr(seekRecord->leaf);\r\n            if(!nodeEqual(leaf,&keyNode)){//does not exist\r\n                res={};\r\n                break;\r\n            }\r\n\r\n            /* inject the delete operation into the tree */\r\n            Node* tmpExpected=getPtr(leaf);\r\n            res=leaf->val;\r\n            if(childAddr->compare_exchange_strong(tmpExpected,\r\n                mixPtrFlgTg(tmpExpected,true,false), std::memory_order_acq_rel)){\r\n                /* advance to cleanup mode to remove the leaf node */\r\n                injecting=false;\r\n                if(cleanup(key,tid)) break;\r\n            }\r\n            else{\r\n                Node* tmpChild=childAddr->load(std::memory_order_acquire);\r\n                if(getPtr(tmpChild)==leaf && (getFlg(tmpChild)||getTg(tmpChild))){\r\n                    /*\r\n                     * address of the child has not\r\n                     * changed and either the leaf\r\n                     * node or its sibling has been\r\n                     * flagged for deletion\r\n                     */\r\n                    cleanup(key,tid);\r\n                }\r\n            }\r\n        }\r\n        else{\r\n            /* cleanup mode: check if flagged node still exists */\r\n            if(seekRecord->leaf!=leaf){\r\n                /* leaf no longer in the tree */\r\n                break;\r\n            }\r\n            else{\r\n                /* leaf still in the tree; remove */\r\n                if(cleanup(key,tid)) break;\r\n            }\r\n        }\r\n    }\r\n    he.clear(tid);\r\n    return res;\r\n}\r\n\r\ntemplate <class K, class V>\r\nstd::optional<V> NatarajanTreeHE<K,V>::replace(K key, V val, int tid){\r\n    std::optional<V> res={};\r\n    SeekRecord* seekRecord=&(records[tid]);\r\n\r\n    Node* newInternal=nullptr;\r\n    Node* newLeaf = new Node(he.getEra(),key,val,nullptr,nullptr);//also to compare keys\r\n\r\n    Node* parent=nullptr;\r\n    Node* leaf=nullptr;\r\n    std::atomic<Node*>* childAddr=nullptr;\r\n    while(true){\r\n        seek(key,tid);\r\n        parent=getPtr(seekRecord->parent);\r\n        leaf=getPtr(seekRecord->leaf);\r\n        if(!nodeEqual(newLeaf,leaf)){//key does not exist, replace fails\r\n            delete newLeaf;\r\n            res={};\r\n            break;\r\n        }\r\n        else{//key exists, update and return old\r\n            res=leaf->val;\r\n            if(nodeLess(newLeaf,parent))\r\n                childAddr=&(parent->left);\r\n            else\r\n                childAddr=&(parent->right);\r\n            if(childAddr->compare_exchange_strong(leaf,newLeaf,std::memory_order_acq_rel)){\r\n                he.retire(leaf,tid);\r\n                break;\r\n            }\r\n        }\r\n    }\r\n    he.clear(tid);\r\n    return res;\r\n}\r\n\r\ntemplate <class K, class V>\r\nstd::map<K, V> NatarajanTreeHE<K,V>::rangeQuery(K key1, K key2, int& len, int tid){\r\n    //NOT HP-like GC safe.\r\n    if(key1>key2) return {};\r\n    Node k1{he.getEra(),key1,defltV,nullptr,nullptr};//node to be compared\r\n    Node k2{he.getEra(),key2,defltV,nullptr,nullptr};//node to be compared\r\n\r\n    Node* leaf = getPtr(he.get_protected(0, s->left, tid));\r\n    Node* current = getPtr(he.get_protected(1, leaf->left, tid));\r\n\r\n    std::map<K,V> res;\r\n    if(current!=nullptr)\r\n        doRangeQuery(k1,k2,tid,current,res);\r\n    len=res.size();\r\n    return res;\r\n}\r\n\r\ntemplate <class K, class V>\r\nvoid NatarajanTreeHE<K,V>::doRangeQuery(Node& k1, Node& k2, int tid, Node* root, std::map<K,V>& res){\r\n    Node* left = getPtr(he.get_protected(2, root->left, tid));\r\n    Node* right = getPtr(he.get_protected(3, root->right, tid));\r\n    if(left==nullptr&&right==nullptr){\r\n        if(nodeLessEqual(&k1,root)&&nodeLessEqual(root,&k2)){\r\n            res.emplace(root->key,root->val);\r\n        }\r\n        return;\r\n    }\r\n    if(left!=nullptr){\r\n        if(nodeLess(&k1,root)){\r\n            doRangeQuery(k1,k2,tid,left,res);\r\n        }\r\n    }\r\n    if(right!=nullptr){\r\n        if(nodeLessEqual(root,&k2)){\r\n            doRangeQuery(k1,k2,tid,right,res);\r\n        }\r\n    }\r\n    return;\r\n}\r\n\r\n\r\n// Wrappers for the \"set\" benchmarks\r\ntemplate <class K, class V>\r\nbool NatarajanTreeHE<K,V>::add(K key, int tid) {\r\n    return insert(key,key,tid);\r\n}\r\n\r\ntemplate <class K, class V>\r\nbool NatarajanTreeHE<K,V>::remove(K key, int tid) {\r\n    return innerRemove(key,tid).has_value();\r\n}\r\n\r\ntemplate <class K, class V>\r\nbool NatarajanTreeHE<K,V>::contains(K key, int tid) {\r\n    return get(key,tid).has_value();\r\n}\r\n\r\n// Not lock-free\r\ntemplate <class K, class V>\r\nvoid NatarajanTreeHE<K,V>::addAll(K** keys, const int size, const int tid) {\r\n    for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n}\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/treemaps/OFLFRedBlackTree.hpp",
    "content": "#ifndef _OF_LF_RED_BLACK_BST_H_\r\n#define _OF_LF_RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n#include \"stms/OneFileLF.hpp\"               // This header defines the macros for the STM being compiled\r\n\r\n// Adapted from Java to C++ from the original at http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V>\r\nclass OFLFRedBlackTree {\r\n    const int64_t COLOR_RED   = 0;\r\n    const int64_t COLOR_BLACK = 1;\r\n\r\n    struct Node : public oflf::tmbase {\r\n        oflf::tmtype<K>       key;\r\n        oflf::tmtype<V>       val;\r\n        oflf::tmtype<Node*>   left {nullptr};\r\n        oflf::tmtype<Node*>   right {nullptr};\r\n        oflf::tmtype<int64_t> color;    // color of parent link\r\n        oflf::tmtype<int64_t> size;     // subtree count\r\n        Node(const K& key, const V& val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\r\n    };\r\n\r\n    oflf::tmtype<Node*> root {nullptr};   // root of the BST\r\n\r\n    inline void assignAndFreeIfNull(oflf::tmtype<Node*>& z, Node* w) {\r\n        Node* tofree = z;\r\n        z = w;\r\n        if (w == nullptr) oflf::tmDelete(tofree);\r\n    }\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    OFLFRedBlackTree(int numThreads=0){ }\r\n\r\n    ~OFLFRedBlackTree() {\r\n        for (int i = 0; i < 10000; i++) {\r\n            oflf::updateTx([&] () {\r\n                if (root == nullptr) return;\r\n                deleteMin();\r\n            });\r\n        }\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == COLOR_RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerGet(K& key, V& oldValue, const bool saveOldValue) {\r\n        bool found = get(root, key);\r\n        if (!found) return false;\r\n        //if (saveOldValue) oldValue = *val; // Copy of V\r\n        return true;\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    bool get(Node* x, K& key) {\r\n        while (x != nullptr) {\r\n            if      (key < x->key) x = x->left;\r\n            else if (x->key < key) x = x->right;\r\n            else              return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool containsKey(const K& key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerPut(const K& key, const V& value) {\r\n    \tbool ret = false;\r\n        root = put(root, key, value, ret);\r\n        root->color = COLOR_BLACK;\r\n        return ret;\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, const K& key, const V& val, bool& ret) {\r\n        if (h == nullptr) {\r\n            ret = true;\r\n            return oflf::tmNew<Node>(key, val, COLOR_RED, 1);\r\n        }\r\n        if      (key < h->key) h->left  = put(h->left,  key, val, ret);\r\n        else if (h->key < key) h->right = put(h->right, key, val, ret);\r\n        else              h->val   = val;\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) return;\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteMin(root));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) return;\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     */\r\n    void innerRemove(const K& key) {\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right)) root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteKey(root, key));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, const K& key) {\r\n        // assert get(h, key) != null;\r\n        if (key < h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left)) {\r\n                h = moveRedLeft(h);\r\n            }\r\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\r\n        } else {\r\n            if (isRed(h->left)) {\r\n                h = rotateRight(h);\r\n            }\r\n            if (key == h->key && (h->right == nullptr)) {\r\n                return nullptr;\r\n            }\r\n            if (!isRed(h->right) && !isRed(h->right->left)) {\r\n                h = moveRedRight(h);\r\n            }\r\n            if (key == h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\r\n            } else {\r\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\r\n            }\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                        h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) return nullptr;\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) return nullptr;\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (key < x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (x->key < key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            return nullptr;\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(const K& key) {\r\n        if (key == nullptr) return -1;\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(const K& key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (key < x->key) return rank(key, x->left);\r\n        else if (x->key < key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(const K& lo, const K& hi) {\r\n        if (lo == nullptr) return 0;\r\n        if (hi == nullptr) return 0;\r\n\r\n        if (hi < lo) return 0;\r\n        if (containsKey(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        // TODO: port these two lines\r\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(K key, const int tid=0) {\r\n        return oflf::updateTx<bool>([&] () {\r\n            return innerPut(key,key);\r\n        });\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K key, const int tid=0) {\r\n        return oflf::updateTx<bool>([&] () {\r\n            V notused;\r\n            bool retval = innerGet(key,notused,false);\r\n            if (retval) innerRemove(key);\r\n            return retval;\r\n        });\r\n    }\r\n\r\n    bool contains(K key, const int tid=0) {\r\n        return oflf::readTx<bool>([&] () {\r\n            V notused;\r\n            return innerGet(key,notused,false);\r\n        });\r\n    }\r\n\r\n    // This is not fully transactionally but it's ok because we use it only on initialization.\r\n    // We could make it fully transactionally, but we would have to increase the size of allocation/store logs.\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return \"OF-LF-RedBlackTree\"; }\r\n\r\n};\r\n\r\n#endif   // _TM_RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "datastructures/treemaps/OFWFRedBlackTree.hpp",
    "content": "#ifndef _OF_WF_RED_BLACK_BST_H_\r\n#define _OF_WF_RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n#include \"stms/OneFileWF.hpp\"               // This header defines the macros for the STM being compiled\r\n\r\n// Adapted from Java to C++ from the original at http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V>\r\nclass OFWFRedBlackTree {\r\n    const int64_t COLOR_RED   = 0;\r\n    const int64_t COLOR_BLACK = 1;\r\n\r\n    struct Node : public ofwf::tmbase {\r\n        ofwf::tmtype<K>       key;\r\n        ofwf::tmtype<V>       val;\r\n        ofwf::tmtype<Node*>   left {nullptr};\r\n        ofwf::tmtype<Node*>   right {nullptr};\r\n        ofwf::tmtype<int64_t> color;    // color of parent link\r\n        ofwf::tmtype<int64_t> size;     // subtree count\r\n        Node(const K& key, const V& val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\r\n    };\r\n\r\n    ofwf::tmtype<Node*> root {nullptr};   // root of the BST\r\n\r\n    inline void assignAndFreeIfNull(ofwf::tmtype<Node*>& z, Node* w) {\r\n        Node* tofree = z;\r\n        z = w;\r\n        if (w == nullptr) ofwf::tmDelete(tofree);\r\n    }\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    OFWFRedBlackTree(int numThreads=0){ }\r\n\r\n    ~OFWFRedBlackTree() {\r\n        for (int i = 0; i < 10000; i++) {\r\n            ofwf::updateTx([&] () {\r\n                if (root == nullptr) return;\r\n                deleteMin();\r\n            });\r\n        }\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == COLOR_RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerGet(K key, V& oldValue, const bool saveOldValue) {\r\n        bool found = get(root, key);\r\n        if (!found) return false;\r\n        //if (saveOldValue) oldValue = *val; // Copy of V\r\n        return true;\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    bool get(Node* x, K& key) {\r\n        while (x != nullptr) {\r\n            if      (key < x->key) x = x->left;\r\n            else if (x->key < key) x = x->right;\r\n            else              return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool containsKey(const K& key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerPut(const K& key, const V& value) {\r\n    \tbool ret = false;\r\n        root = put(root, key, value, ret);\r\n        root->color = COLOR_BLACK;\r\n        return ret;\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, const K& key, const V& val, bool& ret) {\r\n        if (h == nullptr) {\r\n            ret = true;\r\n            return ofwf::tmNew<Node>(key, val, COLOR_RED, 1);\r\n        }\r\n        if      (key < h->key) h->left  = put(h->left,  key, val, ret);\r\n        else if (h->key < key) h->right = put(h->right, key, val, ret);\r\n        else              h->val   = val;\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) return;\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteMin(root));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) return;\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     */\r\n    void innerRemove(K key) {\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right)) root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteKey(root, key));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, const K& key) {\r\n        // assert get(h, key) != null;\r\n        if (key < h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left)) {\r\n                h = moveRedLeft(h);\r\n            }\r\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\r\n        } else {\r\n            if (isRed(h->left)) {\r\n                h = rotateRight(h);\r\n            }\r\n            if (key == h->key && (h->right == nullptr)) {\r\n                return nullptr;\r\n            }\r\n            if (!isRed(h->right) && !isRed(h->right->left)) {\r\n                h = moveRedRight(h);\r\n            }\r\n            if (key == h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\r\n            } else {\r\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\r\n            }\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                        h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) return nullptr;\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) return nullptr;\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (key < x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (x->key < key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            return nullptr;\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(const K& key) {\r\n        if (key == nullptr) return -1;\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(const K& key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (key < x->key) return rank(key, x->left);\r\n        else if (x->key < key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(const K& lo, const K& hi) {\r\n        if (lo == nullptr) return 0;\r\n        if (hi == nullptr) return 0;\r\n\r\n        if (hi < lo) return 0;\r\n        if (containsKey(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        // TODO: port these two lines\r\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(K key, const int tid=0) {\r\n        return ofwf::updateTx<bool>([=] () {\r\n            return innerPut(key,key);\r\n        });\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K key, const int tid=0) {\r\n        return ofwf::updateTx<bool>([=] () {\r\n            V notused;\r\n            bool retval = innerGet(key,notused,false);\r\n            if (retval) innerRemove(key);\r\n            return retval;\r\n        });\r\n    }\r\n\r\n    bool contains(K key, const int tid=0) {\r\n        return ofwf::readTx<bool>([=] () {\r\n            V notused;\r\n            return innerGet(key,notused,false);\r\n        });\r\n    }\r\n\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return \"OF-WF-RedBlackTree\"; }\r\n\r\n};\r\n\r\n#endif   // _OF_WF_RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "datastructures/treemaps/TinySTMRedBlackTree.hpp",
    "content": "#ifndef _TINY_STM_RED_BLACK_BST_H_\r\n#define _TINY_STM_RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n#include \"stms/TinySTM.hpp\"\r\n\r\n// Adapted from Java to C++ from the original at http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V>\r\nclass TinySTMRedBlackTree {\r\n    const int64_t COLOR_RED   = 0;\r\n    const int64_t COLOR_BLACK = 1;\r\n\r\n    struct Node {\r\n        tinystm::tmtype<K>       key;\r\n        tinystm::tmtype<V>       val;\r\n        tinystm::tmtype<Node*>   left {nullptr};\r\n        tinystm::tmtype<Node*>   right {nullptr};\r\n        tinystm::tmtype<int64_t> color;    // color of parent link\r\n        tinystm::tmtype<int64_t> size;     // subtree count\r\n        Node(const K& key, const V& val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\r\n    };\r\n\r\n    tinystm::tmtype<Node*> root {nullptr};   // root of the BST\r\n\r\n    inline void assignAndFreeIfNull(tinystm::tmtype<Node*>& z, Node* w) {\r\n        Node* tofree = z;\r\n        z = w;\r\n        if (w == nullptr) tinystm::tmDelete(tofree);\r\n    }\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    TinySTMRedBlackTree(int maxThreads=0){ }\r\n\r\n    ~TinySTMRedBlackTree() {\r\n        // The transaction log is not enough to delete everything if there are too many, so we delete 1000 per transaction\r\n        for (int i = 0; i < 1000; i++) {\r\n            tinystm::updateTx<bool>([&] () {\r\n                if (root == nullptr) return true;\r\n                deleteMin();\r\n                return true;\r\n            });\r\n        }\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == COLOR_RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerGet(K& key, V& oldValue, const bool saveOldValue) {\r\n        bool found = get(root, key);\r\n        if (!found) return false;\r\n        //if (saveOldValue) oldValue = *val; // Copy of V\r\n        return true;\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    bool get(Node* x, K& key) {\r\n        while (x != nullptr) {\r\n            if      (key < x->key) x = x->left;\r\n            else if (x->key < key) x = x->right;\r\n            else              return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool containsKey(const K& key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerPut(const K& key, const V& value) {\r\n    \tbool ret = false;\r\n        root = put(root, key, value, ret);\r\n        root->color = COLOR_BLACK;\r\n        return ret;\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, const K& key, const V& val, bool& ret) {\r\n        if (h == nullptr) {\r\n        \tret = true;\r\n        \treturn tinystm::tmNew<Node>(key, val, COLOR_RED, 1);\r\n        }\r\n        if      (key < h->key) h->left  = put(h->left,  key, val, ret);\r\n        else if (h->key < key) h->right = put(h->right, key, val, ret);\r\n        else              h->val   = val;\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) return;\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteMin(root));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) return;\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     */\r\n    void innerRemove(const K& key) {\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right)) root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteKey(root, key));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, const K& key) {\r\n        // assert get(h, key) != null;\r\n        if (key < h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left)) {\r\n                h = moveRedLeft(h);\r\n            }\r\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\r\n        } else {\r\n            if (isRed(h->left)) {\r\n                h = rotateRight(h);\r\n            }\r\n            if (key == h->key && (h->right == nullptr)) {\r\n                return nullptr;\r\n            }\r\n            if (!isRed(h->right) && !isRed(h->right->left)) {\r\n                h = moveRedRight(h);\r\n            }\r\n            if (key == h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\r\n            } else {\r\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\r\n            }\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                        h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) return nullptr;\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) return nullptr;\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (key < x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (x->key < key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            return nullptr;\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(const K& key) {\r\n        if (key == nullptr) return -1;\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(const K& key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (key < x->key) return rank(key, x->left);\r\n        else if (x->key < key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(const K& lo, const K& hi) {\r\n        if (lo == nullptr) return 0;\r\n        if (hi == nullptr) return 0;\r\n\r\n        if (hi < lo) return 0;\r\n        if (containsKey(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        // TODO: port these two lines\r\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(K key, const int tid=0) {\r\n        return tinystm::updateTx<bool>([&] () {\r\n            return innerPut(key,key);\r\n        });\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K key, const int tid=0) {\r\n        return tinystm::updateTx<bool>([&] () {\r\n            V notused;\r\n            bool retval = innerGet(key,notused,false);\r\n            if (retval) innerRemove(key);\r\n            return retval;\r\n        });\r\n    }\r\n\r\n    bool contains(K key, const int tid=0) {\r\n        return tinystm::readTx<bool>([&] () {\r\n            V notused;\r\n            return innerGet(key,notused,false);\r\n        });\r\n    }\r\n\r\n    // This is not fully transactionally but it's ok because we use it only on initialization.\r\n    // We could make it fully transactionally, but we would have to increase the size of allocation/store logs.\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return tinystm::TinySTM::className() + \"-RedBlackTree\"; }\r\n\r\n};\r\n\r\n#endif   // _TINY_STM_RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/Makefile",
    "content": "GPP = g++\nFLAGS = -std=c++11 -mcx16 -O3 -g\nFLAGS += -DPHYSICAL_PROCESSORS=48 -DMAX_TID_POW2=64\n\nLDFLAGS += -I./common\nLDFLAGS += -I./common/dcss\nLDFLAGS += -I./common/atomic_ops\nLDFLAGS += -I./common/descriptors\nLDFLAGS += -I./common/recordmgr\nLDFLAGS += -I./common/rq\nLDFLAGS += -I./common/rq/snapcollector\nLDFLAGS += -I./ds/brown_ext_abtree_lf\nLDFLAGS += -lpthread\n\nall: minimal_example\n\nminimal_example:\n\t$(GPP) $(FLAGS) -o $@.out $@.cpp $(LDFLAGS)\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/TrevorBrownABTree.hpp",
    "content": "#ifndef _TREVOR_BROWN_AB_TREE_HP_H_\r\n#define _TREVOR_BROWN_AB_TREE_HP_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n#include \"common/ThreadRegistry.hpp\"\r\n#include \"ds/brown_ext_abtree_lf/brown_ext_abtree_lf_adapter.h\"\r\n\r\n/*\r\n * This is a wrapper to Trevor Brown's AB-Tree so we can use it in our benchmarks\r\n * TODO: We've enabled Hazard Pointers as memory reclamation\r\n */\r\n\r\ntemplate<typename K>\r\nclass TrevorBrownABTree {\r\n\r\n    static const int NODE_DEGREE = 16;\r\n    const int ANY_KEY = 0;\r\n    const int NUM_THREADS = 128;\r\n\r\n    //ds_adapter<NODE_DEGREE, K, reclaimer_hazardptr<K>>* tree;\r\n    ds_adapter<NODE_DEGREE, K>* tree;\r\n\r\npublic:\r\n    TrevorBrownABTree(int numThreads) {\r\n        //tree = new ds_adapter<NODE_DEGREE, K, reclaimer_hazardptr<K>>(NUM_THREADS, ANY_KEY);\r\n        tree = new ds_adapter<NODE_DEGREE, K>(NUM_THREADS, ANY_KEY);\r\n    }\r\n\r\n    ~TrevorBrownABTree() {\r\n        delete tree;\r\n    }\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(K key, const int tid=0) {\r\n        int threadID = tl_tcico.tid;\r\n        if (threadID == ThreadCheckInCheckOut::NOT_ASSIGNED) {\r\n            threadID = ThreadRegistry::getTID();\r\n            tree->initThread(threadID);\r\n        }\r\n        return tree->insert(threadID, key, (void *) 1) != tree->getNoValue();\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K key, const int tid=0) {\r\n        int threadID = tl_tcico.tid;\r\n        if (threadID == ThreadCheckInCheckOut::NOT_ASSIGNED) {\r\n            threadID = ThreadRegistry::getTID();\r\n            tree->initThread(threadID);\r\n        }\r\n        return tree->erase(threadID, key) != tree->getNoValue();\r\n    }\r\n\r\n    bool contains(K key, const int tid=0) {\r\n        int threadID = tl_tcico.tid;\r\n        if (threadID == ThreadCheckInCheckOut::NOT_ASSIGNED) {\r\n            threadID = ThreadRegistry::getTID();\r\n            tree->initThread(threadID);\r\n        }\r\n        return tree->contains(threadID, key);\r\n    }\r\n\r\n    // This is not fully transactionally but it's ok because we use it only on initialization.\r\n    // We could make it fully transactionally, but we would have to increase the size of allocation/store logs.\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return \"TrevorBrown-AB-Tree\"; }\r\n\r\n};\r\n\r\n#endif   // _TREVOR_BROWN_AB_TREE_HP_H_\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/generalize-small.h",
    "content": "/* char_load */\r\n#if defined(AO_HAVE_char_load_acquire) && !defined(AO_HAVE_char_load)\r\n#  define AO_char_load(addr) AO_char_load_acquire(addr)\r\n#  define AO_HAVE_char_load\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_acquire)\r\n#  define AO_char_load_acquire(addr) AO_char_load_full(addr)\r\n#  define AO_HAVE_char_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_read)\r\n#  define AO_char_load_read(addr) AO_char_load_full(addr)\r\n#  define AO_HAVE_char_load_read\r\n#endif\r\n\r\n#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_acquire)\r\n#  define AO_char_load_acquire_read(addr) AO_char_load_acquire(addr)\r\n#  define AO_HAVE_char_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_load_acquire)\r\n   AO_INLINE unsigned char\r\n   AO_char_load_acquire(const volatile unsigned char *addr)\r\n   {\r\n     unsigned char result = AO_char_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_char_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_read) && \\\r\n    !defined(AO_HAVE_char_load_read)\r\n   AO_INLINE unsigned char\r\n   AO_char_load_read(const volatile unsigned char *addr)\r\n   {\r\n     unsigned char result = AO_char_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_read();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_char_load_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_load_acquire) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_load_full)\r\n#  define AO_char_load_full(addr) (AO_nop_full(), AO_char_load_acquire(addr))\r\n#  define AO_HAVE_char_load_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_read)\r\n#  define AO_char_load_acquire_read(addr) AO_char_load_read(addr)\r\n#  define AO_HAVE_char_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_load_acquire_read) && !defined(AO_HAVE_char_load)\r\n#  define AO_char_load(addr) AO_char_load_acquire_read(addr)\r\n#  define AO_HAVE_char_load\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_char_load_acquire_read)\r\n#    define AO_char_load_dd_acquire_read(addr) \\\r\n        AO_char_load_acquire_read(addr)\r\n#    define AO_HAVE_char_load_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_char_load)\r\n#    define AO_char_load_dd_acquire_read(addr) \\\r\n        AO_char_load(addr)\r\n#    define AO_HAVE_char_load_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n\r\n/* char_store */\r\n\r\n#if defined(AO_HAVE_char_store_release) && !defined(AO_HAVE_char_store)\r\n#  define AO_char_store(addr, val) AO_char_store_release(addr,val)\r\n#  define AO_HAVE_char_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_release)\r\n#  define AO_char_store_release(addr,val) AO_char_store_full(addr,val)\r\n#  define AO_HAVE_char_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_write)\r\n#  define AO_char_store_write(addr,val) AO_char_store_full(addr,val)\r\n#  define AO_HAVE_char_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store_release) && \\\r\n        !defined(AO_HAVE_char_store_release_write)\r\n#  define AO_char_store_release_write(addr, val) \\\r\n        AO_char_store_release(addr,val)\r\n#  define AO_HAVE_char_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store_write) && !defined(AO_HAVE_char_store)\r\n#  define AO_char_store(addr, val) AO_char_store_write(addr,val)\r\n#  define AO_HAVE_char_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_store_release)\r\n#  define AO_char_store_release(addr,val) \\\r\n        (AO_nop_full(), AO_char_store(addr,val))\r\n#  define AO_HAVE_char_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_char_store) && \\\r\n     !defined(AO_HAVE_char_store_write)\r\n#  define AO_char_store_write(addr, val) \\\r\n        (AO_nop_write(), AO_char_store(addr,val))\r\n#  define AO_HAVE_char_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store_write) && \\\r\n     !defined(AO_HAVE_char_store_release_write)\r\n#  define AO_char_store_release_write(addr, val) AO_char_store_write(addr,val)\r\n#  define AO_HAVE_char_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_store_release) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_store_full)\r\n#  define AO_char_store_full(addr, val) \\\r\n        (AO_char_store_release(addr, val), AO_nop_full())\r\n#  define AO_HAVE_char_store_full\r\n#endif\r\n\r\n\r\n/* char_fetch_and_add */\r\n#if defined(AO_HAVE_char_compare_and_swap_full) && \\\r\n    !defined(AO_HAVE_char_fetch_and_add_full)\r\n   AO_INLINE AO_t\r\n   AO_char_fetch_and_add_full(volatile unsigned char *addr,\r\n                               unsigned char incr)\r\n   {\r\n     unsigned char old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_char_compare_and_swap_full(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_char_fetch_and_add_full\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_compare_and_swap_acquire) && \\\r\n    !defined(AO_HAVE_char_fetch_and_add_acquire)\r\n   AO_INLINE AO_t\r\n   AO_char_fetch_and_add_acquire(volatile unsigned char *addr,\r\n                                  unsigned char incr)\r\n   {\r\n     unsigned char old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_char_compare_and_swap_acquire(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_char_fetch_and_add_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_compare_and_swap_release) && \\\r\n    !defined(AO_HAVE_char_fetch_and_add_release)\r\n   AO_INLINE AO_t\r\n   AO_char_fetch_and_add_release(volatile unsigned char *addr,\r\n                                  unsigned char incr)\r\n   {\r\n     unsigned char old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_char_compare_and_swap_release(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_char_fetch_and_add_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_fetch_and_add_full)\r\n#  if !defined(AO_HAVE_char_fetch_and_add_release)\r\n#    define AO_char_fetch_and_add_release(addr, val) \\\r\n         AO_char_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_char_fetch_and_add_release\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_add_acquire)\r\n#    define AO_char_fetch_and_add_acquire(addr, val) \\\r\n         AO_char_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_char_fetch_and_add_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_add_write)\r\n#    define AO_char_fetch_and_add_write(addr, val) \\\r\n         AO_char_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_char_fetch_and_add_write\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_add_read)\r\n#    define AO_char_fetch_and_add_read(addr, val) \\\r\n         AO_char_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_char_fetch_and_add_read\r\n#  endif\r\n#endif /* AO_HAVE_char_fetch_and_add_full */\r\n\r\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_release)\r\n#  define AO_char_fetch_and_add(addr, val) \\\r\n        AO_char_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_acquire)\r\n#  define AO_char_fetch_and_add(addr, val) \\\r\n        AO_char_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_write)\r\n#  define AO_char_fetch_and_add(addr, val) \\\r\n        AO_char_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_read)\r\n#  define AO_char_fetch_and_add(addr, val) \\\r\n        AO_char_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_fetch_and_add_full)\r\n#  define AO_char_fetch_and_add_full(addr, val) \\\r\n        (AO_nop_full(), AO_char_fetch_and_add_acquire(addr, val))\r\n#endif\r\n\r\n#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_write)\r\n#  define AO_char_fetch_and_add_release_write(addr, val) \\\r\n        AO_char_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_release)\r\n#  define AO_char_fetch_and_add_release_write(addr, val) \\\r\n        AO_char_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_read)\r\n#  define AO_char_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_char_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_char_fetch_and_add_acquire)\r\n#  define AO_char_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_char_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_char_fetch_and_add_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_char_fetch_and_add_acquire_read)\r\n#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_char_fetch_and_add_acquire_read(addr, val)\r\n#    define AO_HAVE_char_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_char_fetch_and_add)\r\n#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_char_fetch_and_add(addr, val)\r\n#    define AO_HAVE_char_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* char_fetch_and_add1 */\r\n\r\n#if defined(AO_HAVE_char_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_full)\r\n#  define AO_char_fetch_and_add1_full(addr) \\\r\n        AO_char_fetch_and_add_full(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_full\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_release)\r\n#  define AO_char_fetch_and_add1_release(addr) \\\r\n        AO_char_fetch_and_add_release(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_release\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_acquire)\r\n#  define AO_char_fetch_and_add1_acquire(addr) \\\r\n        AO_char_fetch_and_add_acquire(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_acquire\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_write)\r\n#  define AO_char_fetch_and_add1_write(addr) \\\r\n        AO_char_fetch_and_add_write(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_write\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_read)\r\n#  define AO_char_fetch_and_add1_read(addr) \\\r\n        AO_char_fetch_and_add_read(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_read\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_release_write)\r\n#  define AO_char_fetch_and_add1_release_write(addr) \\\r\n        AO_char_fetch_and_add_release_write(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_release_write\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1_acquire_read)\r\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\r\n        AO_char_fetch_and_add_acquire_read(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_add1)\r\n#  define AO_char_fetch_and_add1(addr) \\\r\n        AO_char_fetch_and_add(addr,1)\r\n#  define AO_HAVE_char_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_fetch_and_add1_full)\r\n#  if !defined(AO_HAVE_char_fetch_and_add1_release)\r\n#    define AO_char_fetch_and_add1_release(addr) \\\r\n         AO_char_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_add1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_add1_acquire)\r\n#    define AO_char_fetch_and_add1_acquire(addr) \\\r\n         AO_char_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_add1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_add1_write)\r\n#    define AO_char_fetch_and_add1_write(addr) \\\r\n         AO_char_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_add1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_add1_read)\r\n#    define AO_char_fetch_and_add1_read(addr) \\\r\n         AO_char_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_add1_read\r\n#  endif\r\n#endif /* AO_HAVE_char_fetch_and_add1_full */\r\n\r\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_release)\r\n#  define AO_char_fetch_and_add1(addr) \\\r\n        AO_char_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_char_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_acquire)\r\n#  define AO_char_fetch_and_add1(addr) \\\r\n        AO_char_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_char_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_write)\r\n#  define AO_char_fetch_and_add1(addr) \\\r\n        AO_char_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_char_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_read)\r\n#  define AO_char_fetch_and_add1(addr) \\\r\n        AO_char_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_char_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_fetch_and_add1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_fetch_and_add1_full)\r\n#  define AO_char_fetch_and_add1_full(addr) \\\r\n        (AO_nop_full(), AO_char_fetch_and_add1_acquire(addr))\r\n#  define AO_HAVE_char_fetch_and_add1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_write)\r\n#  define AO_char_fetch_and_add1_release_write(addr) \\\r\n        AO_char_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_char_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_release)\r\n#  define AO_char_fetch_and_add1_release_write(addr) \\\r\n        AO_char_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_char_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_read)\r\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\r\n        AO_char_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_char_fetch_and_add1_acquire)\r\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\r\n        AO_char_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_char_fetch_and_add1_acquire_read)\r\n#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_char_fetch_and_add1_acquire_read(addr)\r\n#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_char_fetch_and_add1)\r\n#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_char_fetch_and_add1(addr)\r\n#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* char_fetch_and_sub1 */\r\n\r\n#if defined(AO_HAVE_char_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_full)\r\n#  define AO_char_fetch_and_sub1_full(addr) \\\r\n        AO_char_fetch_and_add_full(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_full\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_release)\r\n#  define AO_char_fetch_and_sub1_release(addr) \\\r\n        AO_char_fetch_and_add_release(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_release\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_acquire)\r\n#  define AO_char_fetch_and_sub1_acquire(addr) \\\r\n        AO_char_fetch_and_add_acquire(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_acquire\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_write)\r\n#  define AO_char_fetch_and_sub1_write(addr) \\\r\n        AO_char_fetch_and_add_write(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_write\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_read)\r\n#  define AO_char_fetch_and_sub1_read(addr) \\\r\n        AO_char_fetch_and_add_read(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_read\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_release_write)\r\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\r\n        AO_char_fetch_and_add_release_write(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_release_write\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_acquire_read)\r\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_char_fetch_and_add_acquire_read(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_char_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_char_fetch_and_sub1)\r\n#  define AO_char_fetch_and_sub1(addr) \\\r\n        AO_char_fetch_and_add(addr,(unsigned char)(-1))\r\n#  define AO_HAVE_char_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_fetch_and_sub1_full)\r\n#  if !defined(AO_HAVE_char_fetch_and_sub1_release)\r\n#    define AO_char_fetch_and_sub1_release(addr) \\\r\n         AO_char_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_sub1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_sub1_acquire)\r\n#    define AO_char_fetch_and_sub1_acquire(addr) \\\r\n         AO_char_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_sub1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_sub1_write)\r\n#    define AO_char_fetch_and_sub1_write(addr) \\\r\n         AO_char_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_sub1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_char_fetch_and_sub1_read)\r\n#    define AO_char_fetch_and_sub1_read(addr) \\\r\n         AO_char_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_char_fetch_and_sub1_read\r\n#  endif\r\n#endif /* AO_HAVE_char_fetch_and_sub1_full */\r\n\r\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_release)\r\n#  define AO_char_fetch_and_sub1(addr) \\\r\n        AO_char_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_acquire)\r\n#  define AO_char_fetch_and_sub1(addr) \\\r\n        AO_char_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_write)\r\n#  define AO_char_fetch_and_sub1(addr) \\\r\n        AO_char_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_read)\r\n#  define AO_char_fetch_and_sub1(addr) \\\r\n        AO_char_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_char_fetch_and_sub1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_char_fetch_and_sub1_full)\r\n#  define AO_char_fetch_and_sub1_full(addr) \\\r\n        (AO_nop_full(), AO_char_fetch_and_sub1_acquire(addr))\r\n#  define AO_HAVE_char_fetch_and_sub1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_write)\r\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\r\n        AO_char_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_release)\r\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\r\n        AO_char_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_read)\r\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_char_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_char_fetch_and_sub1_acquire)\r\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_char_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_char_fetch_and_sub1_acquire_read)\r\n#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_char_fetch_and_sub1_acquire_read(addr)\r\n#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_char_fetch_and_sub1)\r\n#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_char_fetch_and_sub1(addr)\r\n#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* short_load */\r\n#if defined(AO_HAVE_short_load_acquire) && !defined(AO_HAVE_short_load)\r\n#  define AO_short_load(addr) AO_short_load_acquire(addr)\r\n#  define AO_HAVE_short_load\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_acquire)\r\n#  define AO_short_load_acquire(addr) AO_short_load_full(addr)\r\n#  define AO_HAVE_short_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_read)\r\n#  define AO_short_load_read(addr) AO_short_load_full(addr)\r\n#  define AO_HAVE_short_load_read\r\n#endif\r\n\r\n#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_acquire)\r\n#  define AO_short_load_acquire_read(addr) AO_short_load_acquire(addr)\r\n#  define AO_HAVE_short_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_load_acquire)\r\n   AO_INLINE unsigned short\r\n   AO_short_load_acquire(const volatile unsigned short *addr)\r\n   {\r\n     unsigned short result = AO_short_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_short_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_read) && \\\r\n    !defined(AO_HAVE_short_load_read)\r\n   AO_INLINE unsigned short\r\n   AO_short_load_read(const volatile unsigned short *addr)\r\n   {\r\n     unsigned short result = AO_short_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_read();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_short_load_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_load_acquire) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_load_full)\r\n#  define AO_short_load_full(addr) (AO_nop_full(), AO_short_load_acquire(addr))\r\n#  define AO_HAVE_short_load_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_read)\r\n#  define AO_short_load_acquire_read(addr) AO_short_load_read(addr)\r\n#  define AO_HAVE_short_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_load_acquire_read) && !defined(AO_HAVE_short_load)\r\n#  define AO_short_load(addr) AO_short_load_acquire_read(addr)\r\n#  define AO_HAVE_short_load\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_short_load_acquire_read)\r\n#    define AO_short_load_dd_acquire_read(addr) \\\r\n        AO_short_load_acquire_read(addr)\r\n#    define AO_HAVE_short_load_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_short_load)\r\n#    define AO_short_load_dd_acquire_read(addr) \\\r\n        AO_short_load(addr)\r\n#    define AO_HAVE_short_load_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n\r\n/* short_store */\r\n\r\n#if defined(AO_HAVE_short_store_release) && !defined(AO_HAVE_short_store)\r\n#  define AO_short_store(addr, val) AO_short_store_release(addr,val)\r\n#  define AO_HAVE_short_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_release)\r\n#  define AO_short_store_release(addr,val) AO_short_store_full(addr,val)\r\n#  define AO_HAVE_short_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_write)\r\n#  define AO_short_store_write(addr,val) AO_short_store_full(addr,val)\r\n#  define AO_HAVE_short_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store_release) && \\\r\n        !defined(AO_HAVE_short_store_release_write)\r\n#  define AO_short_store_release_write(addr, val) \\\r\n        AO_short_store_release(addr,val)\r\n#  define AO_HAVE_short_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store_write) && !defined(AO_HAVE_short_store)\r\n#  define AO_short_store(addr, val) AO_short_store_write(addr,val)\r\n#  define AO_HAVE_short_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_store_release)\r\n#  define AO_short_store_release(addr,val) \\\r\n        (AO_nop_full(), AO_short_store(addr,val))\r\n#  define AO_HAVE_short_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_short_store) && \\\r\n     !defined(AO_HAVE_short_store_write)\r\n#  define AO_short_store_write(addr, val) \\\r\n        (AO_nop_write(), AO_short_store(addr,val))\r\n#  define AO_HAVE_short_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store_write) && \\\r\n     !defined(AO_HAVE_short_store_release_write)\r\n#  define AO_short_store_release_write(addr, val) AO_short_store_write(addr,val)\r\n#  define AO_HAVE_short_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_store_release) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_store_full)\r\n#  define AO_short_store_full(addr, val) \\\r\n        (AO_short_store_release(addr, val), AO_nop_full())\r\n#  define AO_HAVE_short_store_full\r\n#endif\r\n\r\n\r\n/* short_fetch_and_add */\r\n#if defined(AO_HAVE_short_compare_and_swap_full) && \\\r\n    !defined(AO_HAVE_short_fetch_and_add_full)\r\n   AO_INLINE AO_t\r\n   AO_short_fetch_and_add_full(volatile unsigned short *addr,\r\n                               unsigned short incr)\r\n   {\r\n     unsigned short old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_short_compare_and_swap_full(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_short_fetch_and_add_full\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_compare_and_swap_acquire) && \\\r\n    !defined(AO_HAVE_short_fetch_and_add_acquire)\r\n   AO_INLINE AO_t\r\n   AO_short_fetch_and_add_acquire(volatile unsigned short *addr,\r\n                                  unsigned short incr)\r\n   {\r\n     unsigned short old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_short_compare_and_swap_acquire(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_short_fetch_and_add_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_compare_and_swap_release) && \\\r\n    !defined(AO_HAVE_short_fetch_and_add_release)\r\n   AO_INLINE AO_t\r\n   AO_short_fetch_and_add_release(volatile unsigned short *addr,\r\n                                  unsigned short incr)\r\n   {\r\n     unsigned short old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_short_compare_and_swap_release(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_short_fetch_and_add_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_fetch_and_add_full)\r\n#  if !defined(AO_HAVE_short_fetch_and_add_release)\r\n#    define AO_short_fetch_and_add_release(addr, val) \\\r\n         AO_short_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_short_fetch_and_add_release\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_add_acquire)\r\n#    define AO_short_fetch_and_add_acquire(addr, val) \\\r\n         AO_short_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_short_fetch_and_add_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_add_write)\r\n#    define AO_short_fetch_and_add_write(addr, val) \\\r\n         AO_short_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_short_fetch_and_add_write\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_add_read)\r\n#    define AO_short_fetch_and_add_read(addr, val) \\\r\n         AO_short_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_short_fetch_and_add_read\r\n#  endif\r\n#endif /* AO_HAVE_short_fetch_and_add_full */\r\n\r\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_release)\r\n#  define AO_short_fetch_and_add(addr, val) \\\r\n        AO_short_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_acquire)\r\n#  define AO_short_fetch_and_add(addr, val) \\\r\n        AO_short_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_write)\r\n#  define AO_short_fetch_and_add(addr, val) \\\r\n        AO_short_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_read)\r\n#  define AO_short_fetch_and_add(addr, val) \\\r\n        AO_short_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_fetch_and_add_full)\r\n#  define AO_short_fetch_and_add_full(addr, val) \\\r\n        (AO_nop_full(), AO_short_fetch_and_add_acquire(addr, val))\r\n#endif\r\n\r\n#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_write)\r\n#  define AO_short_fetch_and_add_release_write(addr, val) \\\r\n        AO_short_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_release)\r\n#  define AO_short_fetch_and_add_release_write(addr, val) \\\r\n        AO_short_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_read)\r\n#  define AO_short_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_short_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_short_fetch_and_add_acquire)\r\n#  define AO_short_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_short_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_short_fetch_and_add_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_short_fetch_and_add_acquire_read)\r\n#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_short_fetch_and_add_acquire_read(addr, val)\r\n#    define AO_HAVE_short_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_short_fetch_and_add)\r\n#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_short_fetch_and_add(addr, val)\r\n#    define AO_HAVE_short_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* short_fetch_and_add1 */\r\n\r\n#if defined(AO_HAVE_short_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_full)\r\n#  define AO_short_fetch_and_add1_full(addr) \\\r\n        AO_short_fetch_and_add_full(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_full\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_release)\r\n#  define AO_short_fetch_and_add1_release(addr) \\\r\n        AO_short_fetch_and_add_release(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_release\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_acquire)\r\n#  define AO_short_fetch_and_add1_acquire(addr) \\\r\n        AO_short_fetch_and_add_acquire(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_acquire\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_write)\r\n#  define AO_short_fetch_and_add1_write(addr) \\\r\n        AO_short_fetch_and_add_write(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_write\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_read)\r\n#  define AO_short_fetch_and_add1_read(addr) \\\r\n        AO_short_fetch_and_add_read(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_read\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_release_write)\r\n#  define AO_short_fetch_and_add1_release_write(addr) \\\r\n        AO_short_fetch_and_add_release_write(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_release_write\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1_acquire_read)\r\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\r\n        AO_short_fetch_and_add_acquire_read(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_add1)\r\n#  define AO_short_fetch_and_add1(addr) \\\r\n        AO_short_fetch_and_add(addr,1)\r\n#  define AO_HAVE_short_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_fetch_and_add1_full)\r\n#  if !defined(AO_HAVE_short_fetch_and_add1_release)\r\n#    define AO_short_fetch_and_add1_release(addr) \\\r\n         AO_short_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_add1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_add1_acquire)\r\n#    define AO_short_fetch_and_add1_acquire(addr) \\\r\n         AO_short_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_add1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_add1_write)\r\n#    define AO_short_fetch_and_add1_write(addr) \\\r\n         AO_short_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_add1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_add1_read)\r\n#    define AO_short_fetch_and_add1_read(addr) \\\r\n         AO_short_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_add1_read\r\n#  endif\r\n#endif /* AO_HAVE_short_fetch_and_add1_full */\r\n\r\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_release)\r\n#  define AO_short_fetch_and_add1(addr) \\\r\n        AO_short_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_short_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_acquire)\r\n#  define AO_short_fetch_and_add1(addr) \\\r\n        AO_short_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_short_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_write)\r\n#  define AO_short_fetch_and_add1(addr) \\\r\n        AO_short_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_short_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_read)\r\n#  define AO_short_fetch_and_add1(addr) \\\r\n        AO_short_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_short_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_fetch_and_add1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_fetch_and_add1_full)\r\n#  define AO_short_fetch_and_add1_full(addr) \\\r\n        (AO_nop_full(), AO_short_fetch_and_add1_acquire(addr))\r\n#  define AO_HAVE_short_fetch_and_add1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_write)\r\n#  define AO_short_fetch_and_add1_release_write(addr) \\\r\n        AO_short_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_short_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_release)\r\n#  define AO_short_fetch_and_add1_release_write(addr) \\\r\n        AO_short_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_short_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_read)\r\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\r\n        AO_short_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_short_fetch_and_add1_acquire)\r\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\r\n        AO_short_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_short_fetch_and_add1_acquire_read)\r\n#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_short_fetch_and_add1_acquire_read(addr)\r\n#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_short_fetch_and_add1)\r\n#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_short_fetch_and_add1(addr)\r\n#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* short_fetch_and_sub1 */\r\n\r\n#if defined(AO_HAVE_short_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_full)\r\n#  define AO_short_fetch_and_sub1_full(addr) \\\r\n        AO_short_fetch_and_add_full(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_full\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_release)\r\n#  define AO_short_fetch_and_sub1_release(addr) \\\r\n        AO_short_fetch_and_add_release(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_release\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_acquire)\r\n#  define AO_short_fetch_and_sub1_acquire(addr) \\\r\n        AO_short_fetch_and_add_acquire(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_acquire\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_write)\r\n#  define AO_short_fetch_and_sub1_write(addr) \\\r\n        AO_short_fetch_and_add_write(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_write\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_read)\r\n#  define AO_short_fetch_and_sub1_read(addr) \\\r\n        AO_short_fetch_and_add_read(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_read\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_release_write)\r\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\r\n        AO_short_fetch_and_add_release_write(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_release_write\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_acquire_read)\r\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_short_fetch_and_add_acquire_read(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_short_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_short_fetch_and_sub1)\r\n#  define AO_short_fetch_and_sub1(addr) \\\r\n        AO_short_fetch_and_add(addr,(unsigned short)(-1))\r\n#  define AO_HAVE_short_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_fetch_and_sub1_full)\r\n#  if !defined(AO_HAVE_short_fetch_and_sub1_release)\r\n#    define AO_short_fetch_and_sub1_release(addr) \\\r\n         AO_short_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_sub1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_sub1_acquire)\r\n#    define AO_short_fetch_and_sub1_acquire(addr) \\\r\n         AO_short_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_sub1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_sub1_write)\r\n#    define AO_short_fetch_and_sub1_write(addr) \\\r\n         AO_short_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_sub1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_short_fetch_and_sub1_read)\r\n#    define AO_short_fetch_and_sub1_read(addr) \\\r\n         AO_short_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_short_fetch_and_sub1_read\r\n#  endif\r\n#endif /* AO_HAVE_short_fetch_and_sub1_full */\r\n\r\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_release)\r\n#  define AO_short_fetch_and_sub1(addr) \\\r\n        AO_short_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_acquire)\r\n#  define AO_short_fetch_and_sub1(addr) \\\r\n        AO_short_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_write)\r\n#  define AO_short_fetch_and_sub1(addr) \\\r\n        AO_short_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_read)\r\n#  define AO_short_fetch_and_sub1(addr) \\\r\n        AO_short_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_short_fetch_and_sub1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_short_fetch_and_sub1_full)\r\n#  define AO_short_fetch_and_sub1_full(addr) \\\r\n        (AO_nop_full(), AO_short_fetch_and_sub1_acquire(addr))\r\n#  define AO_HAVE_short_fetch_and_sub1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_write)\r\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\r\n        AO_short_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_release)\r\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\r\n        AO_short_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_read)\r\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_short_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_short_fetch_and_sub1_acquire)\r\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_short_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_short_fetch_and_sub1_acquire_read)\r\n#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_short_fetch_and_sub1_acquire_read(addr)\r\n#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_short_fetch_and_sub1)\r\n#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_short_fetch_and_sub1(addr)\r\n#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* int_load */\r\n#if defined(AO_HAVE_int_load_acquire) && !defined(AO_HAVE_int_load)\r\n#  define AO_int_load(addr) AO_int_load_acquire(addr)\r\n#  define AO_HAVE_int_load\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_acquire)\r\n#  define AO_int_load_acquire(addr) AO_int_load_full(addr)\r\n#  define AO_HAVE_int_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_read)\r\n#  define AO_int_load_read(addr) AO_int_load_full(addr)\r\n#  define AO_HAVE_int_load_read\r\n#endif\r\n\r\n#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_acquire)\r\n#  define AO_int_load_acquire_read(addr) AO_int_load_acquire(addr)\r\n#  define AO_HAVE_int_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_load_acquire)\r\n   AO_INLINE unsigned int\r\n   AO_int_load_acquire(const volatile unsigned int *addr)\r\n   {\r\n     unsigned int result = AO_int_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_int_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_read) && \\\r\n    !defined(AO_HAVE_int_load_read)\r\n   AO_INLINE unsigned int\r\n   AO_int_load_read(const volatile unsigned int *addr)\r\n   {\r\n     unsigned int result = AO_int_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_read();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_int_load_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_load_acquire) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_load_full)\r\n#  define AO_int_load_full(addr) (AO_nop_full(), AO_int_load_acquire(addr))\r\n#  define AO_HAVE_int_load_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_read)\r\n#  define AO_int_load_acquire_read(addr) AO_int_load_read(addr)\r\n#  define AO_HAVE_int_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_load_acquire_read) && !defined(AO_HAVE_int_load)\r\n#  define AO_int_load(addr) AO_int_load_acquire_read(addr)\r\n#  define AO_HAVE_int_load\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_int_load_acquire_read)\r\n#    define AO_int_load_dd_acquire_read(addr) \\\r\n        AO_int_load_acquire_read(addr)\r\n#    define AO_HAVE_int_load_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_int_load)\r\n#    define AO_int_load_dd_acquire_read(addr) \\\r\n        AO_int_load(addr)\r\n#    define AO_HAVE_int_load_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n\r\n/* int_store */\r\n\r\n#if defined(AO_HAVE_int_store_release) && !defined(AO_HAVE_int_store)\r\n#  define AO_int_store(addr, val) AO_int_store_release(addr,val)\r\n#  define AO_HAVE_int_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_release)\r\n#  define AO_int_store_release(addr,val) AO_int_store_full(addr,val)\r\n#  define AO_HAVE_int_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_write)\r\n#  define AO_int_store_write(addr,val) AO_int_store_full(addr,val)\r\n#  define AO_HAVE_int_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store_release) && \\\r\n        !defined(AO_HAVE_int_store_release_write)\r\n#  define AO_int_store_release_write(addr, val) \\\r\n        AO_int_store_release(addr,val)\r\n#  define AO_HAVE_int_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store_write) && !defined(AO_HAVE_int_store)\r\n#  define AO_int_store(addr, val) AO_int_store_write(addr,val)\r\n#  define AO_HAVE_int_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_store_release)\r\n#  define AO_int_store_release(addr,val) \\\r\n        (AO_nop_full(), AO_int_store(addr,val))\r\n#  define AO_HAVE_int_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_int_store) && \\\r\n     !defined(AO_HAVE_int_store_write)\r\n#  define AO_int_store_write(addr, val) \\\r\n        (AO_nop_write(), AO_int_store(addr,val))\r\n#  define AO_HAVE_int_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store_write) && \\\r\n     !defined(AO_HAVE_int_store_release_write)\r\n#  define AO_int_store_release_write(addr, val) AO_int_store_write(addr,val)\r\n#  define AO_HAVE_int_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_store_release) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_store_full)\r\n#  define AO_int_store_full(addr, val) \\\r\n        (AO_int_store_release(addr, val), AO_nop_full())\r\n#  define AO_HAVE_int_store_full\r\n#endif\r\n\r\n\r\n/* int_fetch_and_add */\r\n#if defined(AO_HAVE_int_compare_and_swap_full) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add_full)\r\n   AO_INLINE AO_t\r\n   AO_int_fetch_and_add_full(volatile unsigned int *addr,\r\n                               unsigned int incr)\r\n   {\r\n     unsigned int old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_int_compare_and_swap_full(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_int_fetch_and_add_full\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_compare_and_swap_acquire) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add_acquire)\r\n   AO_INLINE AO_t\r\n   AO_int_fetch_and_add_acquire(volatile unsigned int *addr,\r\n                                  unsigned int incr)\r\n   {\r\n     unsigned int old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_int_compare_and_swap_acquire(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_int_fetch_and_add_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_compare_and_swap_release) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add_release)\r\n   AO_INLINE AO_t\r\n   AO_int_fetch_and_add_release(volatile unsigned int *addr,\r\n                                  unsigned int incr)\r\n   {\r\n     unsigned int old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_int_compare_and_swap_release(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_int_fetch_and_add_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_fetch_and_add_full)\r\n#  if !defined(AO_HAVE_int_fetch_and_add_release)\r\n#    define AO_int_fetch_and_add_release(addr, val) \\\r\n         AO_int_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_int_fetch_and_add_release\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_add_acquire)\r\n#    define AO_int_fetch_and_add_acquire(addr, val) \\\r\n         AO_int_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_int_fetch_and_add_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_add_write)\r\n#    define AO_int_fetch_and_add_write(addr, val) \\\r\n         AO_int_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_int_fetch_and_add_write\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_add_read)\r\n#    define AO_int_fetch_and_add_read(addr, val) \\\r\n         AO_int_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_int_fetch_and_add_read\r\n#  endif\r\n#endif /* AO_HAVE_int_fetch_and_add_full */\r\n\r\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_release)\r\n#  define AO_int_fetch_and_add(addr, val) \\\r\n        AO_int_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_acquire)\r\n#  define AO_int_fetch_and_add(addr, val) \\\r\n        AO_int_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_write)\r\n#  define AO_int_fetch_and_add(addr, val) \\\r\n        AO_int_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_read)\r\n#  define AO_int_fetch_and_add(addr, val) \\\r\n        AO_int_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add_full)\r\n#  define AO_int_fetch_and_add_full(addr, val) \\\r\n        (AO_nop_full(), AO_int_fetch_and_add_acquire(addr, val))\r\n#endif\r\n\r\n#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_write)\r\n#  define AO_int_fetch_and_add_release_write(addr, val) \\\r\n        AO_int_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_release)\r\n#  define AO_int_fetch_and_add_release_write(addr, val) \\\r\n        AO_int_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_read)\r\n#  define AO_int_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_int_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_int_fetch_and_add_acquire)\r\n#  define AO_int_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_int_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_int_fetch_and_add_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_int_fetch_and_add_acquire_read)\r\n#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_int_fetch_and_add_acquire_read(addr, val)\r\n#    define AO_HAVE_int_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_int_fetch_and_add)\r\n#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_int_fetch_and_add(addr, val)\r\n#    define AO_HAVE_int_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* int_fetch_and_add1 */\r\n\r\n#if defined(AO_HAVE_int_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_full)\r\n#  define AO_int_fetch_and_add1_full(addr) \\\r\n        AO_int_fetch_and_add_full(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_full\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_release)\r\n#  define AO_int_fetch_and_add1_release(addr) \\\r\n        AO_int_fetch_and_add_release(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_release\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_acquire)\r\n#  define AO_int_fetch_and_add1_acquire(addr) \\\r\n        AO_int_fetch_and_add_acquire(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_acquire\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_write)\r\n#  define AO_int_fetch_and_add1_write(addr) \\\r\n        AO_int_fetch_and_add_write(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_write\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_read)\r\n#  define AO_int_fetch_and_add1_read(addr) \\\r\n        AO_int_fetch_and_add_read(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_read\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_release_write)\r\n#  define AO_int_fetch_and_add1_release_write(addr) \\\r\n        AO_int_fetch_and_add_release_write(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_release_write\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1_acquire_read)\r\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\r\n        AO_int_fetch_and_add_acquire_read(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_add1)\r\n#  define AO_int_fetch_and_add1(addr) \\\r\n        AO_int_fetch_and_add(addr,1)\r\n#  define AO_HAVE_int_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_fetch_and_add1_full)\r\n#  if !defined(AO_HAVE_int_fetch_and_add1_release)\r\n#    define AO_int_fetch_and_add1_release(addr) \\\r\n         AO_int_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_add1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_add1_acquire)\r\n#    define AO_int_fetch_and_add1_acquire(addr) \\\r\n         AO_int_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_add1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_add1_write)\r\n#    define AO_int_fetch_and_add1_write(addr) \\\r\n         AO_int_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_add1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_add1_read)\r\n#    define AO_int_fetch_and_add1_read(addr) \\\r\n         AO_int_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_add1_read\r\n#  endif\r\n#endif /* AO_HAVE_int_fetch_and_add1_full */\r\n\r\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_release)\r\n#  define AO_int_fetch_and_add1(addr) \\\r\n        AO_int_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_int_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_acquire)\r\n#  define AO_int_fetch_and_add1(addr) \\\r\n        AO_int_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_int_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_write)\r\n#  define AO_int_fetch_and_add1(addr) \\\r\n        AO_int_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_int_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_read)\r\n#  define AO_int_fetch_and_add1(addr) \\\r\n        AO_int_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_int_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_fetch_and_add1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add1_full)\r\n#  define AO_int_fetch_and_add1_full(addr) \\\r\n        (AO_nop_full(), AO_int_fetch_and_add1_acquire(addr))\r\n#  define AO_HAVE_int_fetch_and_add1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_write)\r\n#  define AO_int_fetch_and_add1_release_write(addr) \\\r\n        AO_int_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_int_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_release)\r\n#  define AO_int_fetch_and_add1_release_write(addr) \\\r\n        AO_int_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_int_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_read)\r\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\r\n        AO_int_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_int_fetch_and_add1_acquire)\r\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\r\n        AO_int_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_int_fetch_and_add1_acquire_read)\r\n#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_int_fetch_and_add1_acquire_read(addr)\r\n#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_int_fetch_and_add1)\r\n#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_int_fetch_and_add1(addr)\r\n#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* int_fetch_and_sub1 */\r\n\r\n#if defined(AO_HAVE_int_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_full)\r\n#  define AO_int_fetch_and_sub1_full(addr) \\\r\n        AO_int_fetch_and_add_full(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_full\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_release)\r\n#  define AO_int_fetch_and_sub1_release(addr) \\\r\n        AO_int_fetch_and_add_release(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_release\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire)\r\n#  define AO_int_fetch_and_sub1_acquire(addr) \\\r\n        AO_int_fetch_and_add_acquire(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_acquire\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_write)\r\n#  define AO_int_fetch_and_sub1_write(addr) \\\r\n        AO_int_fetch_and_add_write(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_write\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_read)\r\n#  define AO_int_fetch_and_sub1_read(addr) \\\r\n        AO_int_fetch_and_add_read(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_read\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_release_write)\r\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\r\n        AO_int_fetch_and_add_release_write(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_release_write\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire_read)\r\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_int_fetch_and_add_acquire_read(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_int_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_int_fetch_and_sub1)\r\n#  define AO_int_fetch_and_sub1(addr) \\\r\n        AO_int_fetch_and_add(addr,(unsigned int)(-1))\r\n#  define AO_HAVE_int_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_fetch_and_sub1_full)\r\n#  if !defined(AO_HAVE_int_fetch_and_sub1_release)\r\n#    define AO_int_fetch_and_sub1_release(addr) \\\r\n         AO_int_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_sub1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_sub1_acquire)\r\n#    define AO_int_fetch_and_sub1_acquire(addr) \\\r\n         AO_int_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_sub1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_sub1_write)\r\n#    define AO_int_fetch_and_sub1_write(addr) \\\r\n         AO_int_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_sub1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_int_fetch_and_sub1_read)\r\n#    define AO_int_fetch_and_sub1_read(addr) \\\r\n         AO_int_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_int_fetch_and_sub1_read\r\n#  endif\r\n#endif /* AO_HAVE_int_fetch_and_sub1_full */\r\n\r\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_release)\r\n#  define AO_int_fetch_and_sub1(addr) \\\r\n        AO_int_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_acquire)\r\n#  define AO_int_fetch_and_sub1(addr) \\\r\n        AO_int_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_write)\r\n#  define AO_int_fetch_and_sub1(addr) \\\r\n        AO_int_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_read)\r\n#  define AO_int_fetch_and_sub1(addr) \\\r\n        AO_int_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_int_fetch_and_sub1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_full)\r\n#  define AO_int_fetch_and_sub1_full(addr) \\\r\n        (AO_nop_full(), AO_int_fetch_and_sub1_acquire(addr))\r\n#  define AO_HAVE_int_fetch_and_sub1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_write)\r\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\r\n        AO_int_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_release)\r\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\r\n        AO_int_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_read)\r\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_int_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_int_fetch_and_sub1_acquire)\r\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_int_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_int_fetch_and_sub1_acquire_read)\r\n#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_int_fetch_and_sub1_acquire_read(addr)\r\n#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_int_fetch_and_sub1)\r\n#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_int_fetch_and_sub1(addr)\r\n#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/generalize.h",
    "content": "/*\r\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Generalize atomic operations for atomic_ops.h.\r\n * Should not be included directly.\r\n *\r\n * We make no attempt to define useless operations, such as\r\n * AO_nop_acquire\r\n * AO_nop_release\r\n *\r\n * We have also so far neglected to define some others, which\r\n * do not appear likely to be useful, e.g. stores with acquire\r\n * or read barriers.\r\n *\r\n * This file is sometimes included twice by atomic_ops.h.\r\n * All definitions include explicit checks that we are not replacing\r\n * an earlier definition.  In general, more desirable expansions\r\n * appear earlier so that we are more likely to use them.\r\n *\r\n * We only make safe generalizations, except that by default we define\r\n * the ...dd_acquire_read operations to be equivalent to those without\r\n * a barrier.  On platforms for which this is unsafe, the platform-specific\r\n * file must define AO_NO_DD_ORDERING.\r\n */\r\n\r\n#ifndef ATOMIC_OPS_H\r\n# error Atomic_ops_generalize.h should not be included directly.\r\n#endif\r\n\r\n#if AO_CHAR_TS_T\r\n# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \\\r\n         AO_char_compare_and_swap_full(a,o,n)\r\n# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \\\r\n         AO_char_compare_and_swap_acquire(a,o,n)\r\n# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \\\r\n         AO_char_compare_and_swap_release(a,o,n)\r\n# define AO_TS_COMPARE_AND_SWAP(a,o,n) \\\r\n         AO_char_compare_and_swap(a,o,n)\r\n#endif\r\n\r\n#if AO_AO_TS_T\r\n# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \\\r\n         AO_compare_and_swap_full(a,o,n)\r\n# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \\\r\n         AO_compare_and_swap_acquire(a,o,n)\r\n# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \\\r\n         AO_compare_and_swap_release(a,o,n)\r\n# define AO_TS_COMPARE_AND_SWAP(a,o,n) \\\r\n         AO_compare_and_swap(a,o,n)\r\n#endif\r\n\r\n/* Generate test_and_set_full, if necessary and possible.       */\r\n#if !defined(AO_HAVE_test_and_set) && \\\r\n    !defined(AO_HAVE_test_and_set_release) && \\\r\n    !defined(AO_HAVE_test_and_set_acquire) && \\\r\n    !defined(AO_HAVE_test_and_set_read) && \\\r\n    !defined(AO_HAVE_test_and_set_full)\r\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_full) || \\\r\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_full)\r\n     AO_INLINE AO_TS_VAL_t\r\n     AO_test_and_set_full(volatile AO_TS_t *addr)\r\n     {\r\n       if (AO_TS_COMPARE_AND_SWAP_FULL(addr, AO_TS_CLEAR, AO_TS_SET))\r\n         return AO_TS_CLEAR;\r\n       else\r\n         return AO_TS_SET;\r\n     }\r\n#    define AO_HAVE_test_and_set_full\r\n#  endif /* AO_HAVE_compare_and_swap_full */\r\n\r\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_acquire) || \\\r\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_acquire)\r\n     AO_INLINE AO_TS_VAL_t\r\n     AO_test_and_set_acquire(volatile AO_TS_t *addr)\r\n     {\r\n       if (AO_TS_COMPARE_AND_SWAP_ACQUIRE(addr, AO_TS_CLEAR, AO_TS_SET))\r\n         return AO_TS_CLEAR;\r\n       else\r\n         return AO_TS_SET;\r\n     }\r\n#    define AO_HAVE_test_and_set_acquire\r\n#  endif /* AO_HAVE_compare_and_swap_acquire */\r\n\r\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_release) || \\\r\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_release)\r\n     AO_INLINE AO_TS_VAL_t\r\n     AO_test_and_set_release(volatile AO_TS_t *addr)\r\n     {\r\n       if (AO_TS_COMPARE_AND_SWAP_RELEASE(addr, AO_TS_CLEAR, AO_TS_SET))\r\n         return AO_TS_CLEAR;\r\n       else\r\n         return AO_TS_SET;\r\n     }\r\n#    define AO_HAVE_test_and_set_release\r\n#  endif /* AO_HAVE_compare_and_swap_release */\r\n\r\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap) || \\\r\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap)\r\n     AO_INLINE AO_TS_VAL_t\r\n     AO_test_and_set(volatile AO_TS_t *addr)\r\n     {\r\n       if (AO_TS_COMPARE_AND_SWAP(addr, AO_TS_CLEAR, AO_TS_SET))\r\n         return AO_TS_CLEAR;\r\n       else\r\n         return AO_TS_SET;\r\n     }\r\n#    define AO_HAVE_test_and_set\r\n#  endif /* AO_HAVE_compare_and_swap */\r\n\r\n#  if defined(AO_HAVE_test_and_set) && defined(AO_HAVE_nop_full) \\\r\n      && !defined(AO_HAVE_test_and_set_acquire)\r\n     AO_INLINE AO_TS_VAL_t\r\n     AO_test_and_set_acquire(volatile AO_TS_t *addr)\r\n     {\r\n       AO_TS_VAL_t result = AO_test_and_set(addr);\r\n       AO_nop_full();\r\n       return result;\r\n     }\r\n#    define AO_HAVE_test_and_set_acquire\r\n#  endif\r\n\r\n#endif /* No prior test and set */\r\n\r\n/* Nop */\r\n#if !defined(AO_HAVE_nop)\r\n   AO_INLINE void AO_nop(void) {}\r\n#  define AO_HAVE_nop\r\n#endif\r\n\r\n#if defined(AO_HAVE_test_and_set_full) && !defined(AO_HAVE_nop_full)\r\n   AO_INLINE void\r\n   AO_nop_full(void)\r\n   {\r\n     AO_TS_t dummy = AO_TS_INITIALIZER;\r\n     AO_test_and_set_full(&dummy);\r\n   }\r\n#  define AO_HAVE_nop_full\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_acquire)\r\n#  error AO_nop_acquire is useless: dont define.\r\n#endif\r\n#if defined(AO_HAVE_nop_release)\r\n#  error AO_nop_release is useless: dont define.\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_read)\r\n#  define AO_nop_read() AO_nop_full()\r\n#  define AO_HAVE_nop_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_write)\r\n#  define AO_nop_write() AO_nop_full()\r\n#  define AO_HAVE_nop_write\r\n#endif\r\n\r\n/* Load */\r\n#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_acquire)\r\n#  define AO_load_acquire(addr) AO_load_full(addr)\r\n#  define AO_HAVE_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_load_acquire) && !defined(AO_HAVE_load)\r\n#  define AO_load(addr) AO_load_acquire(addr)\r\n#  define AO_HAVE_load\r\n#endif\r\n\r\n#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_read)\r\n#  define AO_load_read(addr) AO_load_full(addr)\r\n#  define AO_HAVE_load_read\r\n#endif\r\n\r\n#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_acquire)\r\n#  define AO_load_acquire_read(addr) AO_load_acquire(addr)\r\n#  define AO_HAVE_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_load_acquire)\r\n   AO_INLINE AO_t\r\n   AO_load_acquire(const volatile AO_t *addr)\r\n   {\r\n     AO_t result = AO_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_load_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_read) && \\\r\n    !defined(AO_HAVE_load_read)\r\n   AO_INLINE AO_t\r\n   AO_load_read(const volatile AO_t *addr)\r\n   {\r\n     AO_t result = AO_load(addr);\r\n     /* Acquire barrier would be useless, since the load could be delayed  */\r\n     /* beyond it.                                                         */\r\n     AO_nop_read();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_load_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_load_acquire) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_load_full)\r\n#  define AO_load_full(addr) (AO_nop_full(), AO_load_acquire(addr))\r\n#  define AO_HAVE_load_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_read)\r\n#  define AO_load_acquire_read(addr) AO_load_read(addr)\r\n#  define AO_HAVE_load_acquire_read\r\n#endif\r\n\r\n#if defined(AO_HAVE_load_acquire_read) && !defined(AO_HAVE_load)\r\n#  define AO_load(addr) AO_load_acquire_read(addr)\r\n#  define AO_HAVE_load\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_load_acquire_read)\r\n#    define AO_load_dd_acquire_read(addr) AO_load_acquire_read(addr)\r\n#    define AO_HAVE_load_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_load)\r\n#    define AO_load_dd_acquire_read(addr) AO_load(addr)\r\n#    define AO_HAVE_load_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n\r\n/* Store */\r\n\r\n#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_release)\r\n#  define AO_store_release(addr,val) AO_store_full(addr,val)\r\n#  define AO_HAVE_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store)\r\n#  define AO_store(addr, val) AO_store_release(addr,val)\r\n#  define AO_HAVE_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_write)\r\n#  define AO_store_write(addr,val) AO_store_full(addr,val)\r\n#  define AO_HAVE_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store_release_write)\r\n#  define AO_store_release_write(addr, val) AO_store_release(addr,val)\r\n#  define AO_HAVE_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store)\r\n#  define AO_store(addr, val) AO_store_write(addr,val)\r\n#  define AO_HAVE_store\r\n#endif\r\n\r\n#if defined(AO_HAVE_store) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_store_release)\r\n#  define AO_store_release(addr,val) (AO_nop_full(), AO_store(addr,val))\r\n#  define AO_HAVE_store_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_store) && \\\r\n     !defined(AO_HAVE_store_write)\r\n#  define AO_store_write(addr, val) (AO_nop_write(), AO_store(addr,val))\r\n#  define AO_HAVE_store_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store_release_write)\r\n#  define AO_store_release_write(addr, val) AO_store_write(addr,val)\r\n#  define AO_HAVE_store_release_write\r\n#endif\r\n\r\n#if defined(AO_HAVE_store_release) && defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_store_full)\r\n#  define AO_store_full(addr, val) (AO_store_release(addr, val), AO_nop_full())\r\n#  define AO_HAVE_store_full\r\n#endif\r\n\r\n/* NEC LE-IT: Test and set */\r\n#if defined(AO_HAVE_test_and_set) && \\\r\n        defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_test_and_set_release)\r\n#       define AO_test_and_set_release(addr) \\\r\n        (AO_nop_full(), AO_test_and_set(addr))\r\n#  define AO_HAVE_test_and_set_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_test_and_set) && \\\r\n        defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_test_and_set_acquire)\r\nAO_INLINE AO_TS_t\r\nAO_test_and_set_acquire(volatile AO_TS_t *addr)\r\n{\r\n        AO_TS_t res = AO_test_and_set(addr);\r\n        AO_nop_full();\r\n        return res;\r\n}\r\n#  define AO_HAVE_test_and_set_acquire\r\n#endif\r\n\r\n\r\n/* Fetch_and_add */\r\n/* We first try to implement fetch_and_add variants in terms    */\r\n/* of the corresponding compare_and_swap variants to minimize   */\r\n/* adding barriers.                                             */\r\n#if defined(AO_HAVE_compare_and_swap_full) && \\\r\n    !defined(AO_HAVE_fetch_and_add_full)\r\n   AO_INLINE AO_t\r\n   AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)\r\n   {\r\n     AO_t old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_compare_and_swap_full(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_fetch_and_add_full\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_acquire) && \\\r\n    !defined(AO_HAVE_fetch_and_add_acquire)\r\n   AO_INLINE AO_t\r\n   AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)\r\n   {\r\n     AO_t old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_compare_and_swap_acquire(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_fetch_and_add_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_release) && \\\r\n    !defined(AO_HAVE_fetch_and_add_release)\r\n   AO_INLINE AO_t\r\n   AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)\r\n   {\r\n     AO_t old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_compare_and_swap_release(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_fetch_and_add_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap) && \\\r\n    !defined(AO_HAVE_fetch_and_add)\r\n   AO_INLINE AO_t\r\n   AO_fetch_and_add(volatile AO_t *addr, AO_t incr)\r\n   {\r\n     AO_t old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_compare_and_swap(addr, old, old+incr));\r\n     return old;\r\n   }\r\n#  define AO_HAVE_fetch_and_add\r\n#endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add_full)\r\n#  if !defined(AO_HAVE_fetch_and_add_release)\r\n#    define AO_fetch_and_add_release(addr, val) \\\r\n         AO_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_fetch_and_add_release\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_add_acquire)\r\n#    define AO_fetch_and_add_acquire(addr, val) \\\r\n         AO_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_fetch_and_add_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_add_write)\r\n#    define AO_fetch_and_add_write(addr, val) \\\r\n         AO_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_fetch_and_add_write\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_add_read)\r\n#    define AO_fetch_and_add_read(addr, val) \\\r\n         AO_fetch_and_add_full(addr, val)\r\n#    define AO_HAVE_fetch_and_add_read\r\n#  endif\r\n#endif /* AO_HAVE_fetch_and_add_full */\r\n\r\n#if !defined(AO_HAVE_fetch_and_add) && \\\r\n    defined(AO_HAVE_fetch_and_add_release)\r\n#  define AO_fetch_and_add(addr, val) \\\r\n        AO_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add) && \\\r\n    defined(AO_HAVE_fetch_and_add_acquire)\r\n#  define AO_fetch_and_add(addr, val) \\\r\n        AO_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add) && \\\r\n    defined(AO_HAVE_fetch_and_add_write)\r\n#  define AO_fetch_and_add(addr, val) \\\r\n        AO_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_fetch_and_add\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add) && \\\r\n    defined(AO_HAVE_fetch_and_add_read)\r\n#  define AO_fetch_and_add(addr, val) \\\r\n        AO_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_fetch_and_add\r\n#endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_fetch_and_add_full)\r\n#  define AO_fetch_and_add_full(addr, val) \\\r\n        (AO_nop_full(), AO_fetch_and_add_acquire(addr, val))\r\n#  define AO_HAVE_fetch_and_add_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_fetch_and_add_write)\r\n#  define AO_fetch_and_add_release_write(addr, val) \\\r\n        AO_fetch_and_add_write(addr, val)\r\n#  define AO_HAVE_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add_release_write) && \\\r\n    defined(AO_HAVE_fetch_and_add_release)\r\n#  define AO_fetch_and_add_release_write(addr, val) \\\r\n        AO_fetch_and_add_release(addr, val)\r\n#  define AO_HAVE_fetch_and_add_release_write\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_fetch_and_add_read)\r\n#  define AO_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_fetch_and_add_read(addr, val)\r\n#  define AO_HAVE_fetch_and_add_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \\\r\n    defined(AO_HAVE_fetch_and_add_acquire)\r\n#  define AO_fetch_and_add_acquire_read(addr, val) \\\r\n        AO_fetch_and_add_acquire(addr, val)\r\n#  define AO_HAVE_fetch_and_add_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_fetch_and_add_acquire_read)\r\n#    define AO_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_fetch_and_add_acquire_read(addr, val)\r\n#    define AO_HAVE_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_fetch_and_add)\r\n#    define AO_fetch_and_add_dd_acquire_read(addr, val) \\\r\n        AO_fetch_and_add(addr, val)\r\n#    define AO_HAVE_fetch_and_add_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* Fetch_and_add1 */\r\n\r\n#if defined(AO_HAVE_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_full)\r\n#  define AO_fetch_and_add1_full(addr) AO_fetch_and_add_full(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_full\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_release)\r\n#  define AO_fetch_and_add1_release(addr) AO_fetch_and_add_release(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_release\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_acquire)\r\n#  define AO_fetch_and_add1_acquire(addr) AO_fetch_and_add_acquire(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_acquire\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_write)\r\n#  define AO_fetch_and_add1_write(addr) AO_fetch_and_add_write(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_write\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_read)\r\n#  define AO_fetch_and_add1_read(addr) AO_fetch_and_add_read(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_read\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_release_write)\r\n#  define AO_fetch_and_add1_release_write(addr) \\\r\n        AO_fetch_and_add_release_write(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_release_write\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1_acquire_read)\r\n#  define AO_fetch_and_add1_acquire_read(addr) \\\r\n        AO_fetch_and_add_acquire_read(addr,1)\r\n#  define AO_HAVE_fetch_and_add1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_fetch_and_add1)\r\n#  define AO_fetch_and_add1(addr) \\\r\n        AO_fetch_and_add(addr,1)\r\n#  define AO_HAVE_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add1_full)\r\n#  if !defined(AO_HAVE_fetch_and_add1_release)\r\n#    define AO_fetch_and_add1_release(addr) \\\r\n         AO_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_fetch_and_add1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_add1_acquire)\r\n#    define AO_fetch_and_add1_acquire(addr) \\\r\n         AO_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_fetch_and_add1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_add1_write)\r\n#    define AO_fetch_and_add1_write(addr) \\\r\n         AO_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_fetch_and_add1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_add1_read)\r\n#    define AO_fetch_and_add1_read(addr) \\\r\n         AO_fetch_and_add1_full(addr)\r\n#    define AO_HAVE_fetch_and_add1_read\r\n#  endif\r\n#endif /* AO_HAVE_fetch_and_add1_full */\r\n\r\n#if !defined(AO_HAVE_fetch_and_add1) && \\\r\n    defined(AO_HAVE_fetch_and_add1_release)\r\n#  define AO_fetch_and_add1(addr) \\\r\n        AO_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add1) && \\\r\n    defined(AO_HAVE_fetch_and_add1_acquire)\r\n#  define AO_fetch_and_add1(addr) \\\r\n        AO_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add1) && \\\r\n    defined(AO_HAVE_fetch_and_add1_write)\r\n#  define AO_fetch_and_add1(addr) \\\r\n        AO_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_fetch_and_add1\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add1) && \\\r\n    defined(AO_HAVE_fetch_and_add1_read)\r\n#  define AO_fetch_and_add1(addr) \\\r\n        AO_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_fetch_and_add1\r\n#endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_fetch_and_add1_full)\r\n#  define AO_fetch_and_add1_full(addr) \\\r\n        (AO_nop_full(), AO_fetch_and_add1_acquire(addr))\r\n#  define AO_HAVE_fetch_and_add1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_fetch_and_add1_write)\r\n#  define AO_fetch_and_add1_release_write(addr) \\\r\n        AO_fetch_and_add1_write(addr)\r\n#  define AO_HAVE_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add1_release_write) && \\\r\n    defined(AO_HAVE_fetch_and_add1_release)\r\n#  define AO_fetch_and_add1_release_write(addr) \\\r\n        AO_fetch_and_add1_release(addr)\r\n#  define AO_HAVE_fetch_and_add1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_fetch_and_add1_read)\r\n#  define AO_fetch_and_add1_acquire_read(addr) \\\r\n        AO_fetch_and_add1_read(addr)\r\n#  define AO_HAVE_fetch_and_add1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \\\r\n    defined(AO_HAVE_fetch_and_add1_acquire)\r\n#  define AO_fetch_and_add1_acquire_read(addr) \\\r\n        AO_fetch_and_add1_acquire(addr)\r\n#  define AO_HAVE_fetch_and_add1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_fetch_and_add1_acquire_read)\r\n#    define AO_fetch_and_add1_dd_acquire_read(addr) \\\r\n        AO_fetch_and_add1_acquire_read(addr)\r\n#    define AO_HAVE_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_fetch_and_add1)\r\n#    define AO_fetch_and_add1_dd_acquire_read(addr) AO_fetch_and_add1(addr)\r\n#    define AO_HAVE_fetch_and_add1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* Fetch_and_sub1 */\r\n\r\n#if defined(AO_HAVE_fetch_and_add_full) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_full)\r\n#  define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_full\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_release) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_release)\r\n#  define AO_fetch_and_sub1_release(addr) \\\r\n        AO_fetch_and_add_release(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_release\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_acquire)\r\n#  define AO_fetch_and_sub1_acquire(addr) \\\r\n        AO_fetch_and_add_acquire(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_acquire\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_write) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_write)\r\n#  define AO_fetch_and_sub1_write(addr) \\\r\n        AO_fetch_and_add_write(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_write\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_read) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_read)\r\n#  define AO_fetch_and_sub1_read(addr) \\\r\n        AO_fetch_and_add_read(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_read\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_release_write) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_release_write)\r\n#  define AO_fetch_and_sub1_release_write(addr) \\\r\n        AO_fetch_and_add_release_write(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_release_write\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1_acquire_read)\r\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_fetch_and_add_acquire_read(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1_acquire_read\r\n#endif\r\n#if defined(AO_HAVE_fetch_and_add) &&\\\r\n    !defined(AO_HAVE_fetch_and_sub1)\r\n#  define AO_fetch_and_sub1(addr) \\\r\n        AO_fetch_and_add(addr,(AO_t)(-1))\r\n#  define AO_HAVE_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_fetch_and_sub1_full)\r\n#  if !defined(AO_HAVE_fetch_and_sub1_release)\r\n#    define AO_fetch_and_sub1_release(addr) \\\r\n         AO_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_fetch_and_sub1_release\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_sub1_acquire)\r\n#    define AO_fetch_and_sub1_acquire(addr) \\\r\n         AO_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_fetch_and_sub1_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_sub1_write)\r\n#    define AO_fetch_and_sub1_write(addr) \\\r\n         AO_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_fetch_and_sub1_write\r\n#  endif\r\n#  if !defined(AO_HAVE_fetch_and_sub1_read)\r\n#    define AO_fetch_and_sub1_read(addr) \\\r\n         AO_fetch_and_sub1_full(addr)\r\n#    define AO_HAVE_fetch_and_sub1_read\r\n#  endif\r\n#endif /* AO_HAVE_fetch_and_sub1_full */\r\n\r\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_release)\r\n#  define AO_fetch_and_sub1(addr) \\\r\n        AO_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_acquire)\r\n#  define AO_fetch_and_sub1(addr) \\\r\n        AO_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_write)\r\n#  define AO_fetch_and_sub1(addr) \\\r\n        AO_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_fetch_and_sub1\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_read)\r\n#  define AO_fetch_and_sub1(addr) \\\r\n        AO_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_fetch_and_sub1\r\n#endif\r\n\r\n#if defined(AO_HAVE_fetch_and_sub1_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_fetch_and_sub1_full)\r\n#  define AO_fetch_and_sub1_full(addr) \\\r\n        (AO_nop_full(), AO_fetch_and_sub1_acquire(addr))\r\n#  define AO_HAVE_fetch_and_sub1_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_write)\r\n#  define AO_fetch_and_sub1_release_write(addr) \\\r\n        AO_fetch_and_sub1_write(addr)\r\n#  define AO_HAVE_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_release)\r\n#  define AO_fetch_and_sub1_release_write(addr) \\\r\n        AO_fetch_and_sub1_release(addr)\r\n#  define AO_HAVE_fetch_and_sub1_release_write\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_read)\r\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_fetch_and_sub1_read(addr)\r\n#  define AO_HAVE_fetch_and_sub1_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \\\r\n    defined(AO_HAVE_fetch_and_sub1_acquire)\r\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\r\n        AO_fetch_and_sub1_acquire(addr)\r\n#  define AO_HAVE_fetch_and_sub1_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_fetch_and_sub1_acquire_read)\r\n#    define AO_fetch_and_sub1_dd_acquire_read(addr) \\\r\n        AO_fetch_and_sub1_acquire_read(addr)\r\n#    define AO_HAVE_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_fetch_and_sub1)\r\n#    define AO_fetch_and_sub1_dd_acquire_read(addr) AO_fetch_and_sub1(addr)\r\n#    define AO_HAVE_fetch_and_sub1_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* Atomic or */\r\n#if defined(AO_HAVE_compare_and_swap_full) && \\\r\n    !defined(AO_HAVE_or_full)\r\n   AO_INLINE void\r\n   AO_or_full(volatile AO_t *addr, AO_t incr)\r\n   {\r\n     AO_t old;\r\n     do\r\n       {\r\n         old = *addr;\r\n       }\r\n     while (!AO_compare_and_swap_full(addr, old, (old | incr)));\r\n   }\r\n#  define AO_HAVE_or_full\r\n#endif\r\n\r\n#if defined(AO_HAVE_or_full)\r\n#  if !defined(AO_HAVE_or_release)\r\n#    define AO_or_release(addr, val) \\\r\n         AO_or_full(addr, val)\r\n#    define AO_HAVE_or_release\r\n#  endif\r\n#  if !defined(AO_HAVE_or_acquire)\r\n#    define AO_or_acquire(addr, val) \\\r\n         AO_or_full(addr, val)\r\n#    define AO_HAVE_or_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_or_write)\r\n#    define AO_or_write(addr, val) \\\r\n         AO_or_full(addr, val)\r\n#    define AO_HAVE_or_write\r\n#  endif\r\n#  if !defined(AO_HAVE_or_read)\r\n#    define AO_or_read(addr, val) \\\r\n         AO_or_full(addr, val)\r\n#    define AO_HAVE_or_read\r\n#  endif\r\n#endif /* AO_HAVE_or_full */\r\n\r\n#if !defined(AO_HAVE_or) && \\\r\n    defined(AO_HAVE_or_release)\r\n#  define AO_or(addr, val) \\\r\n        AO_or_release(addr, val)\r\n#  define AO_HAVE_or\r\n#endif\r\n#if !defined(AO_HAVE_or) && \\\r\n    defined(AO_HAVE_or_acquire)\r\n#  define AO_or(addr, val) \\\r\n        AO_or_acquire(addr, val)\r\n#  define AO_HAVE_or\r\n#endif\r\n#if !defined(AO_HAVE_or) && \\\r\n    defined(AO_HAVE_or_write)\r\n#  define AO_or(addr, val) \\\r\n        AO_or_write(addr, val)\r\n#  define AO_HAVE_or\r\n#endif\r\n#if !defined(AO_HAVE_or) && \\\r\n    defined(AO_HAVE_or_read)\r\n#  define AO_or(addr, val) \\\r\n        AO_or_read(addr, val)\r\n#  define AO_HAVE_or\r\n#endif\r\n\r\n#if defined(AO_HAVE_or_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_or_full)\r\n#  define AO_or_full(addr, val) \\\r\n        (AO_nop_full(), AO_or_acquire(addr, val))\r\n#endif\r\n\r\n#if !defined(AO_HAVE_or_release_write) && \\\r\n    defined(AO_HAVE_or_write)\r\n#  define AO_or_release_write(addr, val) \\\r\n        AO_or_write(addr, val)\r\n#  define AO_HAVE_or_release_write\r\n#endif\r\n#if !defined(AO_HAVE_or_release_write) && \\\r\n    defined(AO_HAVE_or_release)\r\n#  define AO_or_release_write(addr, val) \\\r\n        AO_or_release(addr, val)\r\n#  define AO_HAVE_or_release_write\r\n#endif\r\n#if !defined(AO_HAVE_or_acquire_read) && \\\r\n    defined(AO_HAVE_or_read)\r\n#  define AO_or_acquire_read(addr, val) \\\r\n        AO_or_read(addr, val)\r\n#  define AO_HAVE_or_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_or_acquire_read) && \\\r\n    defined(AO_HAVE_or_acquire)\r\n#  define AO_or_acquire_read(addr, val) \\\r\n        AO_or_acquire(addr, val)\r\n#  define AO_HAVE_or_acquire_read\r\n#endif\r\n\r\n/* dd_aquire_read is meaningless.       */\r\n\r\n/* Test_and_set */\r\n\r\n#if defined(AO_HAVE_test_and_set_full)\r\n#  if !defined(AO_HAVE_test_and_set_release)\r\n#    define AO_test_and_set_release(addr) \\\r\n         AO_test_and_set_full(addr)\r\n#    define AO_HAVE_test_and_set_release\r\n#  endif\r\n#  if !defined(AO_HAVE_test_and_set_acquire)\r\n#    define AO_test_and_set_acquire(addr) \\\r\n         AO_test_and_set_full(addr)\r\n#    define AO_HAVE_test_and_set_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_test_and_set_write)\r\n#    define AO_test_and_set_write(addr) \\\r\n         AO_test_and_set_full(addr)\r\n#    define AO_HAVE_test_and_set_write\r\n#  endif\r\n#  if !defined(AO_HAVE_test_and_set_read)\r\n#    define AO_test_and_set_read(addr) \\\r\n         AO_test_and_set_full(addr)\r\n#    define AO_HAVE_test_and_set_read\r\n#  endif\r\n#endif /* AO_HAVE_test_and_set_full */\r\n\r\n#if !defined(AO_HAVE_test_and_set) && \\\r\n    defined(AO_HAVE_test_and_set_release)\r\n#  define AO_test_and_set(addr) \\\r\n        AO_test_and_set_release(addr)\r\n#  define AO_HAVE_test_and_set\r\n#endif\r\n#if !defined(AO_HAVE_test_and_set) && \\\r\n    defined(AO_HAVE_test_and_set_acquire)\r\n#  define AO_test_and_set(addr) \\\r\n        AO_test_and_set_acquire(addr)\r\n#  define AO_HAVE_test_and_set\r\n#endif\r\n#if !defined(AO_HAVE_test_and_set) && \\\r\n    defined(AO_HAVE_test_and_set_write)\r\n#  define AO_test_and_set(addr) \\\r\n        AO_test_and_set_write(addr)\r\n#  define AO_HAVE_test_and_set\r\n#endif\r\n#if !defined(AO_HAVE_test_and_set) && \\\r\n    defined(AO_HAVE_test_and_set_read)\r\n#  define AO_test_and_set(addr) \\\r\n        AO_test_and_set_read(addr)\r\n#  define AO_HAVE_test_and_set\r\n#endif\r\n\r\n#if defined(AO_HAVE_test_and_set_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_test_and_set_full)\r\n#  define AO_test_and_set_full(addr) \\\r\n        (AO_nop_full(), AO_test_and_set_acquire(addr))\r\n#  define AO_HAVE_test_and_set_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_test_and_set_release_write) && \\\r\n    defined(AO_HAVE_test_and_set_write)\r\n#  define AO_test_and_set_release_write(addr) \\\r\n        AO_test_and_set_write(addr)\r\n#  define AO_HAVE_test_and_set_release_write\r\n#endif\r\n#if !defined(AO_HAVE_test_and_set_release_write) && \\\r\n    defined(AO_HAVE_test_and_set_release)\r\n#  define AO_test_and_set_release_write(addr) \\\r\n        AO_test_and_set_release(addr)\r\n#  define AO_HAVE_test_and_set_release_write\r\n#endif\r\n#if !defined(AO_HAVE_test_and_set_acquire_read) && \\\r\n    defined(AO_HAVE_test_and_set_read)\r\n#  define AO_test_and_set_acquire_read(addr) \\\r\n        AO_test_and_set_read(addr)\r\n#  define AO_HAVE_test_and_set_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_test_and_set_acquire_read) && \\\r\n    defined(AO_HAVE_test_and_set_acquire)\r\n#  define AO_test_and_set_acquire_read(addr) \\\r\n        AO_test_and_set_acquire(addr)\r\n#  define AO_HAVE_test_and_set_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_test_and_set_acquire_read)\r\n#    define AO_test_and_set_dd_acquire_read(addr) \\\r\n        AO_test_and_set_acquire_read(addr)\r\n#    define AO_HAVE_test_and_set_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_test_and_set)\r\n#    define AO_test_and_set_dd_acquire_read(addr) AO_test_and_set(addr)\r\n#    define AO_HAVE_test_and_set_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* Compare_and_swap */\r\n#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\\\r\n    && !defined(AO_HAVE_compare_and_swap_acquire)\r\n   AO_INLINE int\r\n   AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val)\r\n   {\r\n     int result = AO_compare_and_swap(addr, old, new_val);\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_compare_and_swap_acquire\r\n#endif\r\n#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\\\r\n    && !defined(AO_HAVE_compare_and_swap_release)\r\n#  define AO_compare_and_swap_release(addr, old, new_val) \\\r\n        (AO_nop_full(), AO_compare_and_swap(addr, old, new_val))\r\n#  define AO_HAVE_compare_and_swap_release\r\n#endif\r\n#if defined(AO_HAVE_compare_and_swap_full)\r\n#  if !defined(AO_HAVE_compare_and_swap_release)\r\n#    define AO_compare_and_swap_release(addr, old, new_val) \\\r\n         AO_compare_and_swap_full(addr, old, new_val)\r\n#    define AO_HAVE_compare_and_swap_release\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_and_swap_acquire)\r\n#    define AO_compare_and_swap_acquire(addr, old, new_val) \\\r\n         AO_compare_and_swap_full(addr, old, new_val)\r\n#    define AO_HAVE_compare_and_swap_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_and_swap_write)\r\n#    define AO_compare_and_swap_write(addr, old, new_val) \\\r\n         AO_compare_and_swap_full(addr, old, new_val)\r\n#    define AO_HAVE_compare_and_swap_write\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_and_swap_read)\r\n#    define AO_compare_and_swap_read(addr, old, new_val) \\\r\n         AO_compare_and_swap_full(addr, old, new_val)\r\n#    define AO_HAVE_compare_and_swap_read\r\n#  endif\r\n#endif /* AO_HAVE_compare_and_swap_full */\r\n\r\n#if !defined(AO_HAVE_compare_and_swap) && \\\r\n    defined(AO_HAVE_compare_and_swap_release)\r\n#  define AO_compare_and_swap(addr, old, new_val) \\\r\n        AO_compare_and_swap_release(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap) && \\\r\n    defined(AO_HAVE_compare_and_swap_acquire)\r\n#  define AO_compare_and_swap(addr, old, new_val) \\\r\n        AO_compare_and_swap_acquire(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap) && \\\r\n    defined(AO_HAVE_compare_and_swap_write)\r\n#  define AO_compare_and_swap(addr, old, new_val) \\\r\n        AO_compare_and_swap_write(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap) && \\\r\n    defined(AO_HAVE_compare_and_swap_read)\r\n#  define AO_compare_and_swap(addr, old, new_val) \\\r\n        AO_compare_and_swap_read(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_compare_and_swap_full)\r\n#  define AO_compare_and_swap_full(addr, old, new_val) \\\r\n        (AO_nop_full(), AO_compare_and_swap_acquire(addr, old, new_val))\r\n#  define AO_HAVE_compare_and_swap_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_compare_and_swap_release_write) && \\\r\n    defined(AO_HAVE_compare_and_swap_write)\r\n#  define AO_compare_and_swap_release_write(addr, old, new_val) \\\r\n        AO_compare_and_swap_write(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap_release_write\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_release_write) && \\\r\n    defined(AO_HAVE_compare_and_swap_release)\r\n#  define AO_compare_and_swap_release_write(addr, old, new_val) \\\r\n        AO_compare_and_swap_release(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap_release_write\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \\\r\n    defined(AO_HAVE_compare_and_swap_read)\r\n#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \\\r\n        AO_compare_and_swap_read(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \\\r\n    defined(AO_HAVE_compare_and_swap_acquire)\r\n#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \\\r\n        AO_compare_and_swap_acquire(addr, old, new_val)\r\n#  define AO_HAVE_compare_and_swap_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_compare_and_swap_acquire_read)\r\n#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \\\r\n        AO_compare_and_swap_acquire_read(addr, old, new_val)\r\n#    define AO_HAVE_compare_and_swap_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_compare_and_swap)\r\n#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \\\r\n        AO_compare_and_swap(addr, old, new_val)\r\n#    define AO_HAVE_compare_and_swap_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n#include \"generalize-small.h\"\r\n\r\n/* Compare_double_and_swap_double */\r\n#if defined(AO_HAVE_compare_double_and_swap_double) && defined(AO_HAVE_nop_full)\\\r\n    && !defined(AO_HAVE_compare_double_and_swap_double_acquire)\r\n   AO_INLINE int\r\n   AO_compare_double_and_swap_double_acquire(volatile AO_double_t *addr,\r\n                                             AO_t o1, AO_t o2,\r\n                                             AO_t n1, AO_t n2)\r\n   {\r\n     int result = AO_compare_double_and_swap_double(addr, o1, o2, n1, n2);\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_compare_double_and_swap_double_acquire\r\n#endif\r\n#if defined(AO_HAVE_compare_double_and_swap_double) \\\r\n    && defined(AO_HAVE_nop_full)\\\r\n    && !defined(AO_HAVE_compare_double_and_swap_double_release)\r\n#  define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \\\r\n        (AO_nop_full(), AO_compare_double_and_swap_double(addr, o1, o2, n1, n2))\r\n#  define AO_HAVE_compare_double_and_swap_double_release\r\n#endif\r\n#if defined(AO_HAVE_compare_double_and_swap_double_full)\r\n#  if !defined(AO_HAVE_compare_double_and_swap_double_release)\r\n#    define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \\\r\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\r\n#    define AO_HAVE_compare_double_and_swap_double_release\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_double_and_swap_double_acquire)\r\n#    define AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2) \\\r\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\r\n#    define AO_HAVE_compare_double_and_swap_double_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_double_and_swap_double_write)\r\n#    define AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2) \\\r\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\r\n#    define AO_HAVE_compare_double_and_swap_double_write\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_double_and_swap_double_read)\r\n#    define AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2) \\\r\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\r\n#    define AO_HAVE_compare_double_and_swap_double_read\r\n#  endif\r\n#endif /* AO_HAVE_compare_double_and_swap_double_full */\r\n\r\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_release)\r\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double\r\n#endif\r\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_acquire)\r\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double\r\n#endif\r\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_write)\r\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double\r\n#endif\r\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_read)\r\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_double_and_swap_double_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_compare_double_and_swap_double_full)\r\n#  define AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2) \\\r\n        (AO_nop_full(), AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2))\r\n#  define AO_HAVE_compare_double_and_swap_double_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_write)\r\n#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double_release_write\r\n#endif\r\n#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_release)\r\n#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double_release_write\r\n#endif\r\n#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_read)\r\n#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \\\r\n    defined(AO_HAVE_compare_double_and_swap_double_acquire)\r\n#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)\r\n#  define AO_HAVE_compare_double_and_swap_double_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_compare_double_and_swap_double_acquire_read)\r\n#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2)\r\n#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_compare_double_and_swap_double)\r\n#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \\\r\n        AO_compare_double_and_swap_double(addr, o1, o2, n1, n2)\r\n#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* Compare_and_swap_double */\r\n#if defined(AO_HAVE_compare_and_swap_double) && defined(AO_HAVE_nop_full)\\\r\n    && !defined(AO_HAVE_compare_and_swap_double_acquire)\r\n   AO_INLINE int\r\n   AO_compare_and_swap_double_acquire(volatile AO_double_t *addr,\r\n                                             AO_t o1,\r\n                                             AO_t n1, AO_t n2)\r\n   {\r\n     int result = AO_compare_and_swap_double(addr, o1, n1, n2);\r\n     AO_nop_full();\r\n     return result;\r\n   }\r\n#  define AO_HAVE_compare_and_swap_double_acquire\r\n#endif\r\n#if defined(AO_HAVE_compare_and_swap_double) \\\r\n    && defined(AO_HAVE_nop_full)\\\r\n    && !defined(AO_HAVE_compare_and_swap_double_release)\r\n#  define AO_compare_and_swap_double_release(addr, o1, n1, n2) \\\r\n        (AO_nop_full(), AO_compare_and_swap_double(addr, o1, n1, n2))\r\n#  define AO_HAVE_compare_and_swap_double_release\r\n#endif\r\n#if defined(AO_HAVE_compare_and_swap_double_full)\r\n#  if !defined(AO_HAVE_compare_and_swap_double_release)\r\n#    define AO_compare_and_swap_double_release(addr, o1, n1, n2) \\\r\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\r\n#    define AO_HAVE_compare_and_swap_double_release\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_and_swap_double_acquire)\r\n#    define AO_compare_and_swap_double_acquire(addr, o1, n1, n2) \\\r\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\r\n#    define AO_HAVE_compare_and_swap_double_acquire\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_and_swap_double_write)\r\n#    define AO_compare_and_swap_double_write(addr, o1, n1, n2) \\\r\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\r\n#    define AO_HAVE_compare_and_swap_double_write\r\n#  endif\r\n#  if !defined(AO_HAVE_compare_and_swap_double_read)\r\n#    define AO_compare_and_swap_double_read(addr, o1, n1, n2) \\\r\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\r\n#    define AO_HAVE_compare_and_swap_double_read\r\n#  endif\r\n#endif /* AO_HAVE_compare_and_swap_double_full */\r\n\r\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_release)\r\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_release(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_acquire)\r\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_acquire(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_write)\r\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_write(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_read)\r\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_read(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_double_acquire) &&\\\r\n    defined(AO_HAVE_nop_full) && \\\r\n    !defined(AO_HAVE_compare_and_swap_double_full)\r\n#  define AO_compare_and_swap_double_full(addr, o1, n1, n2) \\\r\n        (AO_nop_full(), AO_compare_and_swap_double_acquire(addr, o1, n1, n2))\r\n#  define AO_HAVE_compare_and_swap_double_full\r\n#endif\r\n\r\n#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_write)\r\n#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_write(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double_release_write\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_release)\r\n#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_release(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double_release_write\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_read)\r\n#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_read(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double_acquire_read\r\n#endif\r\n#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \\\r\n    defined(AO_HAVE_compare_and_swap_double_acquire)\r\n#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_acquire(addr, o1, n1, n2)\r\n#  define AO_HAVE_compare_and_swap_double_acquire_read\r\n#endif\r\n\r\n#ifdef AO_NO_DD_ORDERING\r\n#  if defined(AO_HAVE_compare_and_swap_double_acquire_read)\r\n#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2)\r\n#    define AO_HAVE_compare_and_swap_double_dd_acquire_read\r\n#  endif\r\n#else\r\n#  if defined(AO_HAVE_compare_and_swap_double)\r\n#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \\\r\n        AO_compare_and_swap_double(addr, o1, n1, n2)\r\n#    define AO_HAVE_compare_and_swap_double_dd_acquire_read\r\n#  endif\r\n#endif\r\n\r\n/* NEC LE-IT: Convenience functions for AO_double compare and swap which */\r\n/* types and reads easier in code                                        */\r\n#if defined(AO_HAVE_compare_double_and_swap_double_release) && \\\r\n    !defined(AO_HAVE_double_compare_and_swap_release)\r\nAO_INLINE int\r\nAO_double_compare_and_swap_release(volatile AO_double_t *addr,\r\n                                   AO_double_t old_val, AO_double_t new_val)\r\n{\r\n        return AO_compare_double_and_swap_double_release(addr,\r\n                                                         old_val.AO_val1, old_val.AO_val2,\r\n                                                         new_val.AO_val1, new_val.AO_val2);\r\n}\r\n#define AO_HAVE_double_compare_and_swap_release\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_double_and_swap_double_acquire) && \\\r\n    !defined(AO_HAVE_double_compare_and_swap_acquire)\r\nAO_INLINE int\r\nAO_double_compare_and_swap_acquire(volatile AO_double_t *addr,\r\n                                   AO_double_t old_val, AO_double_t new_val)\r\n{\r\n        return AO_compare_double_and_swap_double_acquire(addr,\r\n                                                         old_val.AO_val1, old_val.AO_val2,\r\n                                                         new_val.AO_val1, new_val.AO_val2);\r\n}\r\n#define AO_HAVE_double_compare_and_swap_acquire\r\n#endif\r\n\r\n#if defined(AO_HAVE_compare_double_and_swap_double_full) && \\\r\n    !defined(AO_HAVE_double_compare_and_swap_full)\r\nAO_INLINE int\r\nAO_double_compare_and_swap_full(volatile AO_double_t *addr,\r\n                                         AO_double_t old_val, AO_double_t new_val)\r\n{\r\n        return AO_compare_double_and_swap_double_full(addr,\r\n                                                      old_val.AO_val1, old_val.AO_val2,\r\n                                                      new_val.AO_val1, new_val.AO_val2);\r\n}\r\n#define AO_HAVE_double_compare_and_swap_full\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/README",
    "content": "There are two kinds of entities in this directory:\r\n\r\n- Subdirectories corresponding to specific compilers (or compiler/OS combinations).\r\n  Each of these includes one or more architecture-specific headers.\r\n\r\n- More generic header files corresponding to a particular ordering and/or\r\n  atomicity property that might be shared by multiple hardware platforms.\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/acquire_release_volatile.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * This file adds definitions appropriate for environments in which an AO_t\r\n * volatile load has acquire semantics, and an AO_t volatile store has release\r\n * semantics.  This is arguably supposed to be true with the standard Itanium\r\n * software conventions.\r\n */\r\n\r\n/*\r\n * Empirically gcc/ia64 does some reordering of ordinary operations around volatiles\r\n * even when we think it shouldn't.  Gcc 3.3 and earlier could reorder a volatile store\r\n * with another store.  As of March 2005, gcc pre-4 reused previously computed\r\n * common subexpressions across a volatile load.\r\n * Hence we now add compiler barriers for gcc.\r\n */\r\n#if !defined(AO_GCC_BARRIER)\r\n#  if defined(__GNUC__)\r\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\r\n#  else\r\n#    define AO_GCC_BARRIER()\r\n#  endif\r\n#endif\r\n\r\nAO_INLINE AO_t\r\nAO_load_acquire(const volatile AO_t *p)\r\n{\r\n  AO_t result = *p;\r\n  /* A normal volatile load generates an ld.acq         */\r\n  AO_GCC_BARRIER();\r\n  return result;\r\n}\r\n#define AO_HAVE_load_acquire\r\n\r\nAO_INLINE void\r\nAO_store_release(volatile AO_t *p, AO_t val)\r\n{\r\n  AO_GCC_BARRIER();\r\n  /* A normal volatile store generates an st.rel        */\r\n  *p = val;\r\n}\r\n#define AO_HAVE_store_release\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/aligned_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of AO_t are\r\n * atomic fo all legal alignments.\r\n */\r\n\r\nAO_INLINE AO_t\r\nAO_load(const volatile AO_t *addr)\r\n{\r\n  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);\r\n  /* Cast away the volatile for architectures where             */\r\n  /* volatile adds barrier semantics.                           */\r\n  return *(AO_t *)addr;\r\n}\r\n\r\n#define AO_HAVE_load\r\n\r\nAO_INLINE void\r\nAO_store(volatile AO_t *addr, AO_t new_val)\r\n{\r\n  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);\r\n  (*(AO_t *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/all_acquire_release_volatile.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n * \r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n * \r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n * \r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE. \r\n */\r\n\r\n/*\r\n * Describes architectures on which volatile AO_t, unsigned char, unsigned\r\n * short, and unsigned int loads and stores have acquire/release semantics for\r\n * all normally legal alignments.\r\n */\r\n#include \"acquire_release_volatile.h\"\r\n#include \"char_acquire_release_volatile.h\"\r\n#include \"short_acquire_release_volatile.h\"\r\n#include \"int_acquire_release_volatile.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/all_aligned_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Describes architectures on which AO_t, unsigned char, unsigned short,\r\n * and unsigned int loads and stores are atomic for all normally legal\r\n * alignments.\r\n */\r\n#include \"aligned_atomic_load_store.h\"\r\n#include \"char_atomic_load_store.h\"\r\n#include \"short_aligned_atomic_load_store.h\"\r\n#include \"int_aligned_atomic_load_store.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/all_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Describes architectures on which AO_t, unsigned char, unsigned short,\r\n * and unsigned int loads and stores are atomic for all normally legal\r\n * alignments.\r\n */\r\n#include \"atomic_load_store.h\"\r\n#include \"char_atomic_load_store.h\"\r\n#include \"short_atomic_load_store.h\"\r\n#include \"int_atomic_load_store.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/ao_t_is_int.h",
    "content": "/*\r\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Inclusion of this file signifies that AO_t is in fact int.  Hence\r\n * any AO_... operations can also server as AO_int_... operations.\r\n * We currently define only the more important ones here, and allow for\r\n * the normal generalization process to define the others.\r\n * We should probably add others in the future.\r\n */\r\n\r\n#if defined(AO_HAVE_compare_and_swap_full) && \\\r\n    !defined(AO_HAVE_int_compare_and_swap_full)\r\n#  define AO_int_compare_and_swap_full(addr, old, new_val) \\\r\n                AO_compare_and_swap_full((volatile AO_t *)(addr), \\\r\n                                        (AO_t)(old), (AO_t)(new_val))\r\n#  define AO_HAVE_int_compare_and_swap_full\r\n# endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_acquire) && \\\r\n    !defined(AO_HAVE_int_compare_and_swap_acquire)\r\n#  define AO_int_compare_and_swap_acquire(addr, old, new_val) \\\r\n                AO_compare_and_swap_acquire((volatile AO_t *)(addr), \\\r\n                                            (AO_t)(old), (AO_t)(new_val))\r\n#  define AO_HAVE_int_compare_and_swap_acquire\r\n# endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_release) && \\\r\n    !defined(AO_HAVE_int_compare_and_swap_release)\r\n#  define AO_int_compare_and_swap_release(addr, old, new_val) \\\r\n                AO_compare_and_swap_release((volatile AO_t *)(addr), \\\r\n                                         (AO_t)(old), (AO_t)(new_val))\r\n#  define AO_HAVE_int_compare_and_swap_release\r\n# endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_write) && \\\r\n    !defined(AO_HAVE_int_compare_and_swap_write)\r\n#  define AO_int_compare_and_swap_write(addr, old, new_val) \\\r\n                AO_compare_and_swap_write((volatile AO_t *)(addr), \\\r\n                                          (AO_t)(old), (AO_t)(new_val))\r\n#  define AO_HAVE_int_compare_and_swap_write\r\n# endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap_read) && \\\r\n    !defined(AO_HAVE_int_compare_and_swap_read)\r\n#  define AO_int_compare_and_swap_read(addr, old, new_val) \\\r\n                AO_compare_and_swap_read((volatile AO_t *)(addr), \\\r\n                                         (AO_t)(old), (AO_t)(new_val))\r\n#  define AO_HAVE_int_compare_and_swap_read\r\n# endif\r\n\r\n#if defined(AO_HAVE_compare_and_swap) && \\\r\n    !defined(AO_HAVE_int_compare_and_swap)\r\n#  define AO_int_compare_and_swap(addr, old, new_val) \\\r\n                AO_compare_and_swap((volatile AO_t *)(addr), \\\r\n                                    (AO_t)(old), (AO_t)(new_val))\r\n#  define AO_HAVE_int_compare_and_swap\r\n# endif\r\n\r\n#if defined(AO_HAVE_load_acquire) && \\\r\n    !defined(AO_HAVE_int_load_acquire)\r\n#  define AO_int_load_acquire(addr) \\\r\n        (int)AO_load_acquire((const volatile AO_t *)(addr))\r\n#  define AO_HAVE_int_load_acquire\r\n# endif\r\n\r\n#if defined(AO_HAVE_store_release) && \\\r\n    !defined(AO_HAVE_int_store_release)\r\n#  define AO_int_store_release(addr, val) \\\r\n        AO_store_release((volatile AO_t *)(addr), (AO_t)(val))\r\n#  define AO_HAVE_int_store_release\r\n# endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add_full) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add_full)\r\n#  define AO_int_fetch_and_add_full(addr, incr) \\\r\n        (int)AO_fetch_and_add_full((volatile AO_t *)(addr), (AO_t)(incr))\r\n#  define AO_HAVE_int_fetch_and_add_full\r\n# endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add1_acquire) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add1_acquire)\r\n#  define AO_int_fetch_and_add1_acquire(addr) \\\r\n        (int)AO_fetch_and_add1_acquire((volatile AO_t *)(addr))\r\n#  define AO_HAVE_int_fetch_and_add1_acquire\r\n# endif\r\n\r\n#if defined(AO_HAVE_fetch_and_add1_release) && \\\r\n    !defined(AO_HAVE_int_fetch_and_add1_release)\r\n#  define AO_int_fetch_and_add1_release(addr) \\\r\n        (int)AO_fetch_and_add1_release((volatile AO_t *)(addr))\r\n#  define AO_HAVE_int_fetch_and_add1_release\r\n# endif\r\n\r\n#if defined(AO_HAVE_fetch_and_sub1_acquire) && \\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire)\r\n#  define AO_int_fetch_and_sub1_acquire(addr) \\\r\n        (int)AO_fetch_and_sub1_acquire((volatile AO_t *)(addr))\r\n#  define AO_HAVE_int_fetch_and_sub1_acquire\r\n# endif\r\n\r\n#if defined(AO_HAVE_fetch_and_sub1_release) && \\\r\n    !defined(AO_HAVE_int_fetch_and_sub1_release)\r\n#  define AO_int_fetch_and_sub1_release(addr) \\\r\n        (int)AO_fetch_and_sub1_release((volatile AO_t *)(addr))\r\n#  define AO_HAVE_int_fetch_and_sub1_release\r\n# endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/armcc/arm_v6.h",
    "content": "/*\r\n * Copyright (c) 2007 by NEC LE-IT:               All rights reserved.\r\n * A transcription of ARMv6 atomic operations for the ARM Realview Toolchain.\r\n * This code works with armcc from RVDS 3.1\r\n * This is based on work in gcc/arm.h by\r\n *   Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n *   Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n *   Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n#include \"../read_ordered.h\"\r\n#include \"../test_and_set_t_is_ao_t.h\" /* Probably suboptimal */\r\n\r\n#if __TARGET_ARCH_ARM < 6\r\nDont use with ARM instruction sets lower than v6\r\n#else\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\n/* NEC LE-IT: ARMv6 is the first architecture providing support for simple LL/SC\r\n * A data memory barrier must be raised via CP15 command (see documentation).\r\n *\r\n * ARMv7 is compatible to ARMv6 but has a simpler command for issuing a\r\n * memory barrier (DMB). Raising it via CP15 should still work as told me by the\r\n * support engineers. If it turns out to be much quicker than we should implement\r\n * custom code for ARMv7 using the asm { dmb } command.\r\n *\r\n * If only a single processor is used, we can define AO_UNIPROCESSOR\r\n * and do not need to access CP15 for ensuring a DMB at all.\r\n*/\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n#ifndef AO_UNIPROCESSOR\r\n        unsigned int dest=0;\r\n        /* issue an data memory barrier (keeps ordering of memory transactions  */\r\n        /* before and after this operation)                                             */\r\n        __asm { mcr p15,0,dest,c7,c10,5 } ;\r\n#endif\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE AO_t\r\nAO_load(const volatile AO_t *addr)\r\n{\r\n        /* Cast away the volatile in case it adds fence semantics */\r\n        return (*(const AO_t *)addr);\r\n}\r\n#define AO_HAVE_load\r\n\r\n/* NEC LE-IT: atomic \"store\" - according to ARM documentation this is\r\n * the only safe way to set variables also used in LL/SC environment.\r\n * A direct write won't be recognized by the LL/SC construct in other CPUs.\r\n *\r\n * HB: Based on subsequent discussion, I think it would be OK to use an\r\n * ordinary store here if we knew that interrupt handlers always cleared\r\n * the reservation.  They should, but there is some doubt that this is\r\n * currently always the case for e.g. Linux.\r\n*/\r\nAO_INLINE void AO_store(volatile AO_t *addr, AO_t value)\r\n{\r\n        unsigned long tmp;\r\n\r\nretry:\r\n__asm {\r\n                ldrex   tmp, [addr]\r\n                strex   tmp, value, [addr]\r\n                teq     tmp, #0\r\n                bne     retry\r\n          };\r\n}\r\n#define AO_HAVE_store\r\n\r\n/* NEC LE-IT: replace the SWAP as recommended by ARM:\r\n\r\n   \"Applies to: ARM11 Cores\r\n        Though the SWP instruction will still work with ARM V6 cores, it is recommended\r\n        to use the new V6 synchronization instructions. The SWP instruction produces\r\n        locked read and write accesses which are atomic, i.e. another operation cannot\r\n        be done between these locked accesses which ties up external bus (AHB,AXI)\r\n        bandwidth and can increase worst case interrupt latencies. LDREX,STREX are\r\n        more flexible, other instructions can be done between the LDREX and STREX accesses.\r\n   \"\r\n*/\r\nAO_INLINE AO_TS_t\r\nAO_test_and_set(volatile AO_TS_t *addr) {\r\n\r\n        AO_TS_t oldval;\r\n        unsigned long tmp;\r\n        unsigned long one = 1;\r\nretry:\r\n__asm {\r\n                ldrex   oldval, [addr]\r\n                strex   tmp, one, [addr]\r\n                teq             tmp, #0\r\n                bne     retry\r\n          }\r\n\r\n        return oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set\r\n\r\n/* NEC LE-IT: fetch and add for ARMv6 */\r\nAO_INLINE AO_t\r\nAO_fetch_and_add(volatile AO_t *p, AO_t incr)\r\n{\r\n        unsigned long tmp,tmp2;\r\n        AO_t result;\r\n\r\nretry:\r\n__asm {\r\n        ldrex   result, [p]\r\n        add     tmp, incr, result\r\n        strex   tmp2, tmp, [p]\r\n        teq     tmp2, #0\r\n        bne     retry }\r\n\r\n        return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add\r\n\r\n/* NEC LE-IT: fetch and add1 for ARMv6 */\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1(volatile AO_t *p)\r\n{\r\n        unsigned long tmp,tmp2;\r\n        AO_t result;\r\n\r\nretry:\r\n__asm {\r\n        ldrex   result, [p]\r\n        add     tmp, result, #1\r\n        strex   tmp2, tmp, [p]\r\n        teq             tmp2, #0\r\n        bne     retry\r\n        }\r\n\r\n        return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1\r\n\r\n/* NEC LE-IT: fetch and sub for ARMv6 */\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1(volatile AO_t *p)\r\n{\r\n        unsigned long tmp,tmp2;\r\n        AO_t result;\r\n\r\nretry:\r\n__asm {\r\n        ldrex   result, [p]\r\n        sub     tmp, result, #1\r\n        strex   tmp2, tmp, [p]\r\n        teq             tmp2, #0\r\n        bne     retry\r\n        }\r\n\r\n        return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1\r\n\r\n/* NEC LE-IT: compare and swap */\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap(volatile AO_t *addr,\r\n                                AO_t old_val, AO_t new_val)\r\n{\r\n         AO_t result,tmp;\r\n\r\nretry:\r\n__asm__ {\r\n        mov             result, #2\r\n        ldrex   tmp, [addr]\r\n        teq             tmp, old_val\r\n        it              eq\r\n        strexeq result, new_val, [addr]\r\n        teq             result, #1\r\n        beq             retry\r\n        }\r\n\r\n        return !(result&2);\r\n}\r\n#define AO_HAVE_compare_and_swap\r\n\r\n/* helper functions for the Realview compiler: LDREXD is not usable\r\n * with inline assembler, so use the \"embedded\" assembler as\r\n * suggested by ARM Dev. support (June 2008). */\r\n__asm inline double_ptr_storage load_ex(volatile AO_double_t *addr) {\r\n        LDREXD r0,r1,[r0]\r\n}\r\n\r\n__asm inline int store_ex(AO_t val1, AO_t val2, volatile AO_double_t *addr) {\r\n        STREXD r3,r0,r1,[r2]\r\n        MOV        r0,r3\r\n}\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double(volatile AO_double_t *addr,\r\n                                                          AO_t old_val1, AO_t old_val2,\r\n                                                          AO_t new_val1, AO_t new_val2)\r\n{\r\n        double_ptr_storage old_val = ((double_ptr_storage)old_val2 << 32) | old_val1;\r\n\r\n    double_ptr_storage tmp;\r\n        int result;\r\n\r\n        while(1) {\r\n                tmp = load_ex(addr);\r\n                if(tmp != old_val)      return 0;\r\n                result = store_ex(new_val1, new_val2, addr);\r\n                if(!result)     return 1;\r\n        }\r\n}\r\n\r\n#define AO_HAVE_compare_double_and_swap_double\r\n\r\n\r\n#endif // __TARGET_ARCH_ARM\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of AO_t are\r\n * atomic for all legal alignments.\r\n */\r\n\r\nAO_INLINE AO_t\r\nAO_load(const volatile AO_t *addr)\r\n{\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(const AO_t *)addr);\r\n}\r\n\r\n#define AO_HAVE_load\r\n\r\nAO_INLINE void\r\nAO_store(volatile AO_t *addr, AO_t new_val)\r\n{\r\n  (*(AO_t *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/char_acquire_release_volatile.h",
    "content": "/*\r\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * This file adds definitions appropriate for environments in which an unsigned char\r\n * volatile load has acquire semantics, and an unsigned char volatile store has release\r\n * semantics.  This is true with the standard Itanium ABI.\r\n */\r\n#if !defined(AO_GCC_BARRIER)\r\n#  if defined(__GNUC__)\r\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\r\n#  else\r\n#    define AO_GCC_BARRIER()\r\n#  endif\r\n#endif\r\n\r\nAO_INLINE unsigned char\r\nAO_char_load_acquire(const volatile unsigned char *p)\r\n{\r\n  unsigned char result = *p;\r\n  /* A normal volatile load generates an ld.acq         */\r\n  AO_GCC_BARRIER();\r\n  return result;\r\n}\r\n#define AO_HAVE_char_load_acquire\r\n\r\nAO_INLINE void\r\nAO_char_store_release(volatile unsigned char *p, unsigned char val)\r\n{\r\n  AO_GCC_BARRIER();\r\n  /* A normal volatile store generates an st.rel        */\r\n  *p = val;\r\n}\r\n#define AO_HAVE_char_store_release\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/char_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of unsigned char are\r\n * atomic for all legal alignments.\r\n */\r\n\r\nAO_INLINE unsigned char\r\nAO_char_load(const volatile unsigned char *addr)\r\n{\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(const unsigned char *)addr);\r\n}\r\n\r\n#define AO_HAVE_char_load\r\n\r\nAO_INLINE void\r\nAO_char_store(volatile unsigned char *addr, unsigned char new_val)\r\n{\r\n  (*(unsigned char *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_char_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/emul_cas.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n * \r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n * \r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n * \r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE. \r\n */\r\n\r\n/*\r\n * Ensure, if at all possible, that AO_compare_and_swap_full() is\r\n * available.  The emulation should be brute-force signal-safe, even\r\n * though it actually blocks.\r\n * Including this file will generate an error if AO_compare_and_swap_full()\r\n * cannot be made available.\r\n * This will be included from platform-specific atomic_ops files\r\n * id appropriate, and if AO_FORCE_CAS is defined.  It should not be\r\n * included directly, especially since it affects the implementation\r\n * of other atomic update primitives.\r\n * The implementation assumes that only AO_store_XXX and AO_test_and_set_XXX\r\n * variants are defined, and that AO_test_and_set_XXX is not used to\r\n * operate on compare_and_swap locations.\r\n */\r\n\r\n#if !defined(ATOMIC_OPS_H)\r\n#  error This file should not be included directly.\r\n#endif\r\n\r\n#ifndef AO_HAVE_double_t\r\n# include \"standard_ao_double_t.h\"\r\n#endif\r\n\r\nint AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,\r\n\t\t\t\t  AO_t new_val);\r\n\r\nint AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,\r\n\t\t\t\t\t\tAO_t old_val1, AO_t old_val2,\r\n\t\t\t\t                AO_t new_val1, AO_t new_val2);\r\n\r\nvoid AO_store_full_emulation(volatile AO_t *addr, AO_t val);\r\n\r\n#define AO_compare_and_swap_full(addr, old, newval) \\\r\n\tAO_compare_and_swap_emulation(addr, old, newval)\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n#ifndef AO_HAVE_compare_double_and_swap_double\r\n# define AO_compare_double_and_swap_double_full(addr, old1, old2, \\\r\n\t\t\t\t\t\tnewval1, newval2) \\\r\n\t AO_compare_double_and_swap_double_emulation(addr, old1, old2, \\\r\n\t\t\t \t\t\t     newval1, newval2)\r\n# define AO_HAVE_compare_double_and_swap_double_full\r\n#endif\r\n\r\n#undef AO_store\r\n#undef AO_HAVE_store\r\n#undef AO_store_write\r\n#undef AO_HAVE_store_write\r\n#undef AO_store_release\r\n#undef AO_HAVE_store_release\r\n#undef AO_store_full\r\n#undef AO_HAVE_store_full\r\n#define AO_store_full(addr, val) AO_store_full_emulation(addr, val)\r\n#define AO_HAVE_store_full\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/alpha.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n\r\n#include \"../atomic_load_store.h\"\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n\r\n#define AO_NO_DD_ORDERING\r\n        /* Data dependence does not imply read ordering.        */\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm__ __volatile__(\"mb\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE void\r\nAO_nop_write(void)\r\n{\r\n  __asm__ __volatile__(\"wmb\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_write\r\n\r\n/* mb should be used for AO_nop_read().  That's the default.    */\r\n\r\n/* We believe that ldq_l ... stq_c does not imply any memory barrier.   */\r\n/* We should add an explicit fetch_and_add definition.                  */\r\nAO_INLINE int\r\nAO_compare_and_swap(volatile AO_t *addr,\r\n                    AO_t old, AO_t new_val)\r\n{\r\n  unsigned long was_equal;\r\n  unsigned long temp;\r\n\r\n  __asm__ __volatile__(\r\n                     \"1:     ldq_l %0,%1\\n\"\r\n                     \"       cmpeq %0,%4,%2\\n\"\r\n                     \"       mov %3,%0\\n\"\r\n                     \"       beq %2,2f\\n\"\r\n                     \"       stq_c %0,%1\\n\"\r\n                     \"       beq %0,1b\\n\"\r\n                     \"2:\\n\"\r\n                     :\"=&r\" (temp), \"=m\" (*addr), \"=&r\" (was_equal)\r\n                     : \"r\" (new_val), \"Ir\" (old)\r\n                     :\"memory\");\r\n  return was_equal;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/arm.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n\r\n#include \"../read_ordered.h\"\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\" /* Probably suboptimal */\r\n\r\n/* NEC LE-IT: ARMv6 is the first architecture providing support for simple LL/SC\r\n * A data memory barrier must be raised via CP15 command (see documentation).\r\n *\r\n * ARMv7 is compatible to ARMv6 but has a simpler command for issuing a\r\n * memory barrier (DMB). Raising it via CP15 should still work as told me by the\r\n * support engineers. If it turns out to be much quicker than we should implement\r\n * custom code for ARMv7 using the asm { dmb } command.\r\n *\r\n * If only a single processor is used, we can define AO_UNIPROCESSOR\r\n * and do not need to access CP15 for ensuring a DMB\r\n*/\r\n\r\n/* NEC LE-IT: gcc has no way to easily check the arm architecture\r\n * but defines only one of __ARM_ARCH_x__ to be true                    */\r\n#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \\\r\n        || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) \\\r\n        || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \\\r\n        || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__)\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n#ifndef AO_UNIPROCESSOR\r\n        /* issue an data memory barrier (keeps ordering of memory transactions  */\r\n        /* before and after this operation)                                     */\r\n        unsigned int arg=0;\r\n        __asm__ __volatile__(\"mcr p15,0,%0,c7,c10,5\" : : \"r\" (arg) : \"memory\");\r\n#endif\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n/* NEC LE-IT: AO_t load is simple reading */\r\nAO_INLINE AO_t\r\nAO_load(const volatile AO_t *addr)\r\n{\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(const AO_t *)addr);\r\n}\r\n#define AO_HAVE_load\r\n\r\n/* NEC LE-IT: atomic \"store\" - according to ARM documentation this is\r\n * the only safe way to set variables also used in LL/SC environment.\r\n * A direct write won't be recognized by the LL/SC construct on the _same_ CPU.\r\n * Support engineers response for behaviour of ARMv6:\r\n *\r\n   Core1        Core2          SUCCESS\r\n   ===================================\r\n   LDREX(x)\r\n   STREX(x)                    Yes\r\n   -----------------------------------\r\n   LDREX(x)\r\n                STR(x)\r\n   STREX(x)                    No\r\n   -----------------------------------\r\n   LDREX(x)\r\n   STR(x)\r\n   STREX(x)                    Yes\r\n   -----------------------------------\r\n\r\n * ARMv7 behaves similar, see documentation CortexA8 TRM, point 8.5\r\n *\r\n * HB: I think this is only a problem if interrupt handlers do not clear\r\n * the reservation, as they almost certainly should.  Probably change this back\r\n * in a while?\r\n*/\r\nAO_INLINE void AO_store(volatile AO_t *addr, AO_t value)\r\n{\r\n        AO_t    flag;\r\n\r\n        __asm__ __volatile__(\"@AO_store\\n\"\r\n\"1:     ldrex   %0, [%2]\\n\"\r\n\"       strex   %0, %3, [%2]\\n\"\r\n\"       teq     %0, #0\\n\"\r\n\"       bne     1b\"\r\n        : \"=&r\"(flag), \"+m\"(*addr)\r\n        : \"r\" (addr), \"r\"(value)\r\n        : \"cc\");\r\n}\r\n#define AO_HAVE_store\r\n\r\n/* NEC LE-IT: replace the SWAP as recommended by ARM:\r\n\r\n   \"Applies to: ARM11 Cores\r\n        Though the SWP instruction will still work with ARM V6 cores, it is\r\n        recommended     to use the new V6 synchronization instructions. The SWP\r\n        instruction produces 'locked' read and write accesses which are atomic,\r\n        i.e. another operation cannot be done between these locked accesses which\r\n        ties up external bus (AHB,AXI) bandwidth and can increase worst case\r\n        interrupt latencies. LDREX,STREX are more flexible, other instructions can\r\n        be done between the LDREX and STREX accesses.\r\n   \"\r\n*/\r\nAO_INLINE AO_TS_t\r\nAO_test_and_set(volatile AO_TS_t *addr)\r\n{\r\n\r\n        AO_TS_t oldval;\r\n        unsigned long flag;\r\n\r\n        __asm__ __volatile__(\"@AO_test_and_set\\n\"\r\n\"1:     ldrex   %0, [%3]\\n\"\r\n\"       strex   %1, %4, [%3]\\n\"\r\n\"       teq             %1, #0\\n\"\r\n\"       bne             1b\\n\"\r\n        : \"=&r\"(oldval),\"=&r\"(flag), \"+m\"(*addr)\r\n        : \"r\"(addr), \"r\"(1)\r\n        : \"cc\");\r\n\r\n        return oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set\r\n\r\n/* NEC LE-IT: fetch and add for ARMv6 */\r\nAO_INLINE AO_t\r\nAO_fetch_and_add(volatile AO_t *p, AO_t incr)\r\n{\r\n        unsigned long flag,tmp;\r\n        AO_t result;\r\n\r\n        __asm__ __volatile__(\"@AO_fetch_and_add\\n\"\r\n\"1:     ldrex   %0, [%5]\\n\"             /* get original         */\r\n\"       add     %2, %0, %4\\n\"           /* sum up in incr       */\r\n\"       strex   %1, %2, [%5]\\n\"         /* store them           */\r\n\"       teq             %1, #0\\n\"\r\n\"       bne             1b\\n\"\r\n        : \"=&r\"(result),\"=&r\"(flag),\"=&r\"(tmp),\"+m\"(*p) /* 0..3 */\r\n        : \"r\"(incr), \"r\"(p)                                                             /* 4..5 */\r\n        : \"cc\");\r\n\r\n        return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add\r\n\r\n/* NEC LE-IT: fetch and add1 for ARMv6 */\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1(volatile AO_t *p)\r\n{\r\n        unsigned long flag,tmp;\r\n        AO_t result;\r\n\r\n        __asm__ __volatile__(\"@AO_fetch_and_add1\\n\"\r\n\"1:     ldrex   %0, [%4]\\n\"             /* get original */\r\n\"       add     %1, %0, #1\\n\"           /* increment */\r\n\"       strex   %2, %1, [%4]\\n\"         /* store them */\r\n\"       teq             %2, #0\\n\"\r\n\"       bne             1b\\n\"\r\n        : \"=&r\"(result), \"=&r\"(tmp), \"=&r\"(flag), \"+m\"(*p)\r\n        : \"r\"(p)\r\n        : \"cc\");\r\n\r\n        return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1\r\n\r\n/* NEC LE-IT: fetch and sub for ARMv6 */\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1(volatile AO_t *p)\r\n{\r\n        unsigned long flag,tmp;\r\n        AO_t result;\r\n\r\n        __asm__ __volatile__(\"@AO_fetch_and_sub1\\n\"\r\n\"1:     ldrex   %0, [%4]\\n\"             /* get original */\r\n\"       sub     %1, %0, #1\\n\"           /* decrement */\r\n\"       strex   %2, %1, [%4]\\n\"         /* store them */\r\n\"       teq             %2, #0\\n\"\r\n\"       bne             1b\\n\"\r\n        : \"=&r\"(result), \"=&r\"(tmp), \"=&r\"(flag), \"+m\"(*p)\r\n        : \"r\"(p)\r\n        : \"cc\");\r\n\r\n        return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1\r\n\r\n/* NEC LE-IT: compare and swap */\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap(volatile AO_t *addr,\r\n                                AO_t old_val, AO_t new_val)\r\n{\r\n         AO_t result,tmp;\r\n\r\n        __asm__ __volatile__(\"@ AO_compare_and_swap\\n\"\r\n\"1:     mov             %0, #2\\n\"       /* store a flag */\r\n\"       ldrex   %1, [%3]\\n\"             /* get original */\r\n\"       teq             %1, %4\\n\"       /* see if match */\r\n\"       it              eq\\n\"\r\n\"       strexeq %0, %5, [%3]\\n\"         /* store new one if matched */\r\n\"       teq             %0, #1\\n\"\r\n\"       beq             1b\\n\"           /* if update failed, repeat */\r\n        : \"=&r\"(result), \"=&r\"(tmp), \"+m\"(*addr)\r\n        : \"r\"(addr), \"r\"(old_val), \"r\"(new_val)\r\n        : \"cc\");\r\n\r\n        return !(result&2);             /* if succeded, return 1, else 0 */\r\n}\r\n#define AO_HAVE_compare_and_swap\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double(volatile AO_double_t *addr,\r\n                                  AO_t old_val1, AO_t old_val2,\r\n                                  AO_t new_val1, AO_t new_val2)\r\n{\r\n        double_ptr_storage old_val = ((double_ptr_storage)old_val2 << 32) | old_val1;\r\n        double_ptr_storage new_val = ((double_ptr_storage)new_val2 << 32) | new_val1;\r\n\r\n    double_ptr_storage tmp;\r\n        int result;\r\n\r\n        while(1) {\r\n                __asm__ __volatile__(\"@ AO_compare_and_swap_double\\n\"\r\n                \"       ldrexd  %0, [%1]\\n\" /* get original to r1 & r2 */\r\n                        : \"=&r\"(tmp)\r\n                        : \"r\"(addr)\r\n                        : \"cc\");\r\n                if(tmp != old_val)      return 0;\r\n                __asm__ __volatile__(\r\n                \"       strexd  %0, %2, [%3]\\n\" /* store new one if matched */\r\n                        : \"=&r\"(result),\"+m\"(*addr)\r\n                        : \"r\"(new_val), \"r\"(addr)\r\n                        : \"cc\");\r\n                if(!result)     return 1;\r\n        }\r\n}\r\n\r\n#define AO_HAVE_compare_double_and_swap_double\r\n\r\n#else\r\n/* pre ARMv6 architectures ... */\r\n\r\n/* I found a slide set that, if I read it correctly, claims that        */\r\n/* Loads followed by either a Load or Store are ordered, but nothing    */\r\n/* else is.                                                             */\r\n/* It appears that SWP is the only simple memory barrier.               */\r\n#include \"../all_atomic_load_store.h\"\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  AO_TS_VAL_t oldval;\r\n  /* SWP on ARM is very similar to XCHG on x86.                 */\r\n  /* The first operand is the result, the second the value      */\r\n  /* to be stored.  Both registers must be different from addr. */\r\n  /* Make the address operand an early clobber output so it     */\r\n  /* doesn't overlap with the other operands.  The early clobber*/\r\n  /* on oldval is necessary to prevent the compiler allocating  */\r\n  /* them to the same register if they are both unused.         */\r\n  __asm__ __volatile__(\"swp %0, %2, [%3]\"\r\n                        : \"=&r\"(oldval), \"=&r\"(addr)\r\n                        : \"r\"(1), \"1\"(addr)\r\n                        : \"memory\");\r\n  return oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n#endif /* __ARM_ARCH_x */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/avr32.h",
    "content": "/*\r\n * Copyright (C) 2009 Bradley Smith <brad@brad-smith.co.uk>\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a\r\n * copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n *\r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n#include \"../ordered.h\" /* There are no multiprocessor implementations. */\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n        register long ret;\r\n\r\n        __asm__ __volatile__(\r\n                \"xchg %[oldval], %[mem], %[newval]\"\r\n                : [oldval] \"=&r\"(ret)\r\n                : [mem] \"r\"(addr), [newval] \"r\"(1)\r\n                : \"memory\");\r\n\r\n        return (AO_TS_VAL_t)ret;\r\n}\r\n#define AO_HAVE_test_and_set_full\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\r\n{\r\n       register long ret;\r\n\r\n       __asm__ __volatile__(\r\n               \"1: ssrf    5\\n\"\r\n               \"   ld.w    %[res], %[mem]\\n\"\r\n               \"   eor     %[res], %[oldval]\\n\"\r\n               \"   brne    2f\\n\"\r\n               \"   stcond  %[mem], %[newval]\\n\"\r\n               \"   brne    1b\\n\"\r\n               \"2:\\n\"\r\n               : [res] \"=&r\"(ret), [mem] \"=m\"(*addr)\r\n               : \"m\"(*addr), [newval] \"r\"(new_val), [oldval] \"r\"(old)\r\n               : \"cc\", \"memory\");\r\n\r\n       return (int)ret;\r\n}\r\n#define AO_HAVE_compare_and_swap_full\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/cris.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n * \r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n * \r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n * \r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE. \r\n *\r\n * Most of this code originally comes from Hans-Peter Nilsson.  It is included\r\n * here with his permission.\r\n *\r\n * This version has not been tested.  It was coped here from a GC\r\n * patch so that we wouldn't lose the code in the upgrade to gc7.\r\n */ \r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n#include \"../ordered.h\"  /* There are no multiprocessor implementations. */\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n\r\n/*\r\n * The architecture apparently supports an \"f\" flag which is\r\n * set on preemption.  This essentially gives us load-locked,\r\n * store-conditional primitives, though I'm not quite sure how\r\n * this would work on a hypothetical multiprocessor.  -HB\r\n *\r\n * For details, see\r\n * http://developer.axis.com/doc/hardware/etrax100lx/prog_man/\r\n *      1_architectural_description.pdf\r\n *\r\n * Presumably many other primitives (notably CAS, including the double-\r\n * width versions) could be implemented in this manner, if someone got\r\n * around to it.\r\n */\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr) {\r\n    /* Ripped from linuxthreads/sysdeps/cris/pt-machine.h */\r\n    register unsigned long int ret;\r\n\r\n    /* Note the use of a dummy output of *addr to expose the write.  The\r\n       memory barrier is to stop *other* writes being moved past this code.  */\r\n      __asm__ __volatile__(\"clearf\\n\"\r\n        \t\t   \"0:\\n\\t\"\r\n                    \t   \"movu.b [%2],%0\\n\\t\"\r\n                    \t   \"ax\\n\\t\"\r\n                    \t   \"move.b %3,[%2]\\n\\t\"\r\n                    \t   \"bwf 0b\\n\\t\"\r\n                    \t   \"clearf\"\r\n                    \t   : \"=&r\" (ret), \"=m\" (*addr)\r\n                    \t   : \"r\" (addr), \"r\" ((int) 1), \"m\" (*addr)\r\n                    \t   : \"memory\");\r\n    return ret;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/hppa.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n *\r\n * Modified by Carlos O'Donell <carlos@baldric.uwo.ca>, 2003\r\n *      - Added self-aligning lock.\r\n *\r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n/* Some architecture set descriptions include special \"ordered\" memory  */\r\n/* operations.  As far as we can tell, no existing processors actually  */\r\n/* require those.  Nor does it appear likely that future processors     */\r\n/* will.                                                                */\r\n#include \"../ordered.h\"\r\n\r\n/* GCC will not guarantee the alignment we need, use four lock words    */\r\n/* and select the correctly aligned datum. See the glibc 2.3.2          */\r\n/* linuxthread port for the original implementation.                    */\r\nstruct AO_pa_clearable_loc {\r\n  int data[4];\r\n};\r\n\r\n#undef AO_TS_INITIALIZER\r\n#define AO_TS_t struct AO_pa_clearable_loc\r\n#define AO_TS_INITIALIZER {1,1,1,1}\r\n/* Switch meaning of set and clear, since we only have an atomic clear  */\r\n/* instruction.                                                         */\r\ntypedef enum {AO_PA_TS_set = 0, AO_PA_TS_clear = 1} AO_PA_TS_val;\r\n#define AO_TS_VAL_t AO_PA_TS_val\r\n#define AO_TS_CLEAR AO_PA_TS_clear\r\n#define AO_TS_SET AO_PA_TS_set\r\n\r\n/* The hppa only has one atomic read and modify memory operation,       */\r\n/* load and clear, so hppa spinlocks must use zero to signify that      */\r\n/* someone is holding the lock.  The address used for the ldcw          */\r\n/* semaphore must be 16-byte aligned.                                   */\r\n\r\n#define __ldcw(a) ({ \\\r\n  volatile unsigned int __ret;                                  \\\r\n  __asm__ __volatile__(\"ldcw 0(%2),%0\"                          \\\r\n                      : \"=r\" (__ret), \"=m\" (*(a)) : \"r\" (a));   \\\r\n  __ret;                                                        \\\r\n})\r\n\r\n/* Because malloc only guarantees 8-byte alignment for malloc'd data,   */\r\n/* and GCC only guarantees 8-byte alignment for stack locals, we can't  */\r\n/* be assured of 16-byte alignment for atomic lock data even if we      */\r\n/* specify \"__attribute ((aligned(16)))\" in the type declaration.  So,  */\r\n/* we use a struct containing an array of four ints for the atomic lock */\r\n/* type and dynamically select the 16-byte aligned int from the array   */\r\n/* for the semaphore.                                                   */\r\n#define __PA_LDCW_ALIGNMENT 16\r\n#define __ldcw_align(a) ({ \\\r\n  unsigned long __ret = (unsigned long) a;                      \\\r\n  __ret += __PA_LDCW_ALIGNMENT - 1;                                     \\\r\n  __ret &= ~(__PA_LDCW_ALIGNMENT - 1);                                  \\\r\n  (volatile unsigned int *) __ret;                                      \\\r\n})\r\n\r\n/* Works on PA 1.1 and PA 2.0 systems */\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t * addr)\r\n{\r\n  volatile unsigned int *a = __ldcw_align (addr);\r\n  return (AO_TS_VAL_t) __ldcw (a);\r\n}\r\n\r\nAO_INLINE void\r\nAO_pa_clear(volatile AO_TS_t * addr)\r\n{\r\n  volatile unsigned int *a = __ldcw_align (addr);\r\n  AO_compiler_barrier();\r\n  *a = 1;\r\n}\r\n#define AO_CLEAR(addr) AO_pa_clear(addr)\r\n\r\n#define AO_HAVE_test_and_set_full\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/ia64.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n#include \"../all_acquire_release_volatile.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#ifdef _ILP32\r\n  /* 32-bit HP/UX code. */\r\n  /* This requires pointer \"swizzling\".  Pointers need to be expanded   */\r\n  /* to 64 bits using the addp4 instruction before use.  This makes it  */\r\n  /* hard to share code, but we try anyway.                             */\r\n# define AO_LEN \"4\"\r\n  /* We assume that addr always appears in argument position 1 in asm   */\r\n  /* code.  If it is clobbered due to swizzling, we also need it in     */\r\n  /* second position.  Any later arguments are referenced symbolically, */\r\n  /* so that we don't have to worry about their position.  This requires*/\r\n  /* gcc 3.1, but you shouldn't be using anything older than that on    */\r\n  /* IA64 anyway.                                                       */\r\n  /* The AO_MASK macro is a workaround for the fact that HP/UX gcc      */\r\n  /* appears to otherwise store 64-bit pointers in ar.ccv, i.e. it      */\r\n  /* doesn't appear to clear high bits in a pointer value we pass into  */\r\n  /* assembly code, even if it is supposedly of type AO_t.              */\r\n# define AO_IN_ADDR \"1\"(addr)\r\n# define AO_OUT_ADDR , \"=r\"(addr)\r\n# define AO_SWIZZLE \"addp4 %1=0,%1;;\\n\"\r\n# define AO_MASK(ptr) __asm__(\"zxt4 %1=%1\": \"=r\"(ptr) : \"0\"(ptr));\r\n#else\r\n# define AO_LEN \"8\"\r\n# define AO_IN_ADDR \"r\"(addr)\r\n# define AO_OUT_ADDR\r\n# define AO_SWIZZLE\r\n# define AO_MASK(ptr)\r\n#endif\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm__ __volatile__(\"mf\" : : : \"memory\");\r\n}\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_acquire (volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (AO_SWIZZLE\r\n                        \"fetchadd\" AO_LEN \".acq %0=[%1],1\":\r\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n#define AO_HAVE_fetch_and_add1_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_release (volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (AO_SWIZZLE\r\n                        \"fetchadd\" AO_LEN \".rel %0=[%1],1\":\r\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1_release\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_acquire (volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (AO_SWIZZLE\r\n                        \"fetchadd\" AO_LEN \".acq %0=[%1],-1\":\r\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_release (volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (AO_SWIZZLE\r\n                        \"fetchadd\" AO_LEN \".rel %0=[%1],-1\":\r\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_release\r\n\r\n#ifndef _ILP32\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_add1_acquire (volatile unsigned int *addr)\r\n{\r\n  unsigned int result;\r\n\r\n  __asm__ __volatile__ (\"fetchadd4.acq %0=[%1],1\":\r\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n#define AO_HAVE_int_fetch_and_add1_acquire\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_add1_release (volatile unsigned int *addr)\r\n{\r\n  unsigned int result;\r\n\r\n  __asm__ __volatile__ (\"fetchadd4.rel %0=[%1],1\":\r\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_int_fetch_and_add1_release\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_sub1_acquire (volatile unsigned int *addr)\r\n{\r\n  unsigned int result;\r\n\r\n  __asm__ __volatile__ (\"fetchadd4.acq %0=[%1],-1\":\r\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_int_fetch_and_sub1_acquire\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_sub1_release (volatile unsigned int *addr)\r\n{\r\n  unsigned int result;\r\n\r\n  __asm__ __volatile__ (\"fetchadd4.rel %0=[%1],-1\":\r\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_int_fetch_and_sub1_release\r\n\r\n#endif /* !_ILP32 */\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_acquire(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  AO_t oldval;\r\n  AO_MASK(old);\r\n  __asm__ __volatile__(AO_SWIZZLE\r\n                       \"mov ar.ccv=%[old] ;; cmpxchg\" AO_LEN\r\n                       \".acq %0=[%1],%[new_val],ar.ccv\"\r\n                       : \"=r\"(oldval) AO_OUT_ADDR\r\n                       : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"(old)\r\n                       : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_release(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  AO_t oldval;\r\n  AO_MASK(old);\r\n  __asm__ __volatile__(AO_SWIZZLE\r\n                       \"mov ar.ccv=%[old] ;; cmpxchg\" AO_LEN\r\n                       \".rel %0=[%1],%[new_val],ar.ccv\"\r\n                       : \"=r\"(oldval) AO_OUT_ADDR\r\n                       : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"(old)\r\n                       : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_char_compare_and_swap_acquire(volatile unsigned char *addr,\r\n                                 unsigned char old, unsigned char new_val)\r\n{\r\n  unsigned char oldval;\r\n  __asm__ __volatile__(AO_SWIZZLE\r\n               \"mov ar.ccv=%[old] ;; cmpxchg1.acq %0=[%1],%[new_val],ar.ccv\"\r\n               : \"=r\"(oldval) AO_OUT_ADDR\r\n               : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\r\n               : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_char_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_char_compare_and_swap_release(volatile unsigned char *addr,\r\n                                 unsigned char old, unsigned char new_val)\r\n{\r\n  unsigned char oldval;\r\n  __asm__ __volatile__(AO_SWIZZLE\r\n                \"mov ar.ccv=%[old] ;; cmpxchg1.rel %0=[%1],%[new_val],ar.ccv\"\r\n                : \"=r\"(oldval) AO_OUT_ADDR\r\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\r\n                : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_char_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_short_compare_and_swap_acquire(volatile unsigned short *addr,\r\n                                  unsigned short old, unsigned short new_val)\r\n{\r\n  unsigned short oldval;\r\n  __asm__ __volatile__(AO_SWIZZLE\r\n                \"mov ar.ccv=%[old] ;; cmpxchg2.acq %0=[%1],%[new_val],ar.ccv\"\r\n                : \"=r\"(oldval) AO_OUT_ADDR\r\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\r\n                : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_short_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_short_compare_and_swap_release(volatile unsigned short *addr,\r\n                                  unsigned short old, unsigned short new_val)\r\n{\r\n  unsigned short oldval;\r\n  __asm__ __volatile__(AO_SWIZZLE\r\n                \"mov ar.ccv=%[old] ;; cmpxchg2.rel %0=[%1],%[new_val],ar.ccv\"\r\n                : \"=r\"(oldval) AO_OUT_ADDR\r\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\r\n                : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_short_compare_and_swap_release\r\n\r\n#ifndef _ILP32\r\n\r\nAO_INLINE int\r\nAO_int_compare_and_swap_acquire(volatile unsigned int *addr,\r\n                                unsigned int old, unsigned int new_val)\r\n{\r\n  unsigned int oldval;\r\n  __asm__ __volatile__(\"mov ar.ccv=%3 ;; cmpxchg4.acq %0=[%1],%2,ar.ccv\"\r\n                       : \"=r\"(oldval)\r\n                       : AO_IN_ADDR, \"r\"(new_val), \"r\"((AO_t)old) : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_int_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_int_compare_and_swap_release(volatile unsigned int *addr,\r\n                                unsigned int old, unsigned int new_val)\r\n{\r\n  unsigned int oldval;\r\n  __asm__ __volatile__(\"mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%1],%2,ar.ccv\"\r\n                       : \"=r\"(oldval)\r\n                       : AO_IN_ADDR, \"r\"(new_val), \"r\"((AO_t)old) : \"memory\");\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_int_compare_and_swap_release\r\n\r\n#endif /* !_ILP32 */\r\n\r\n/* FIXME: Add compare_and_swap_double as soon as there is widely        */\r\n/* available hardware that implements it.                               */\r\n\r\n/* FIXME: Add compare_double_and_swap_double for the _ILP32 case.       */\r\n\r\n#ifdef _ILP32\r\n# include \"../ao_t_is_int.h\"\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/m68k.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n\r\n/* The cas instruction causes an emulation trap for the */\r\n/* 060 with a misaligned pointer, so let's avoid this.  */\r\n#undef AO_t\r\ntypedef unsigned long AO_t __attribute__ ((aligned (4)));\r\n\r\n/* FIXME.  Very incomplete.  */\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Are there any m68k multiprocessors still around?     */\r\n/* AFAIK, Alliants were sequentially consistent.        */\r\n#include \"../ordered.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n/* Contributed by Tony Mantler or new.  Should be changed to MIT license? */\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr) {\r\n  AO_TS_t oldval;\r\n\r\n  /* The value at addr is semi-phony.   */\r\n  /* 'tas' sets bit 7 while the return  */\r\n  /* value pretends all bits were set,  */\r\n  /* which at least matches AO_TS_SET.  */\r\n  __asm__ __volatile__(\r\n                \"tas %1; sne %0\"\r\n                : \"=d\" (oldval), \"=m\" (*addr)\r\n                : \"m\" (*addr)\r\n                : \"memory\");\r\n   return oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr,\r\n                         AO_t old, AO_t new_val)\r\n{\r\n  char result;\r\n\r\n  __asm__ __volatile__(\r\n                \"cas.l %3,%4,%1; seq %0\"\r\n                : \"=d\" (result), \"=m\" (*addr)\r\n                : \"m\" (*addr), \"d\" (old), \"d\" (new_val)\r\n                : \"memory\");\r\n  return -result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n\r\n#include \"../ao_t_is_int.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/mips.h",
    "content": "/*\r\n * Copyright (c) 2005,2007  Thiemo Seufer <ths@networkno.de>\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n */\r\n\r\n/*\r\n * FIXME:  This should probably make finer distinctions.  SGI MIPS is\r\n * much more strongly ordered, and in fact closer to sequentially\r\n * consistent.  This is really aimed at modern embedded implementations.\r\n * It looks to me like this assumes a 32-bit ABI.  -HB\r\n */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n#include \"../acquire_release_volatile.h\"\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n#include \"../standard_ao_double_t.h\"\r\n\r\n/* Data dependence does not imply read ordering.  */\r\n#define AO_NO_DD_ORDERING\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm__ __volatile__(\r\n      \"       .set push           \\n\"\r\n      \"       .set mips2          \\n\"\r\n      \"       .set noreorder      \\n\"\r\n      \"       .set nomacro        \\n\"\r\n      \"       sync                \\n\"\r\n      \"       .set pop              \"\r\n      : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)\r\n{\r\n  register int was_equal = 0;\r\n  register int temp;\r\n\r\n  __asm__ __volatile__(\r\n      \"       .set push           \\n\"\r\n      \"       .set mips2          \\n\"\r\n      \"       .set noreorder      \\n\"\r\n      \"       .set nomacro        \\n\"\r\n      \"1:     ll      %0, %1      \\n\"\r\n      \"       bne     %0, %4, 2f  \\n\"\r\n      \"        move   %0, %3      \\n\"\r\n      \"       sc      %0, %1      \\n\"\r\n      \"       .set pop            \\n\"\r\n      \"       beqz    %0, 1b      \\n\"\r\n      \"       li      %2, 1       \\n\"\r\n      \"2:                           \"\r\n      : \"=&r\" (temp), \"+R\" (*addr), \"+r\" (was_equal)\r\n      : \"r\" (new_val), \"r\" (old)\r\n      : \"memory\");\r\n  return was_equal;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap\r\n\r\n/* FIXME: I think the implementations below should be automatically     */\r\n/* generated if we omit them.  - HB                                     */\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  int result = AO_compare_and_swap(addr, old, new_val);\r\n  AO_nop_full();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_nop_full();\r\n  return AO_compare_and_swap(addr, old, new_val);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_t result;\r\n  AO_nop_full();\r\n  result = AO_compare_and_swap(addr, old, new_val);\r\n  AO_nop_full();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n/*\r\n * FIXME: We should also implement fetch_and_add and or primitives\r\n * directly.\r\n */\r\n\r\n#include \"../ao_t_is_int.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/powerpc.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n\r\n/* Memory model documented at http://www-106.ibm.com/developerworks/    */\r\n/* eserver/articles/archguide.html and (clearer)                        */\r\n/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */\r\n/* There appears to be no implicit ordering between any kind of         */\r\n/* independent memory references.                                       */\r\n/* Architecture enforces some ordering based on control dependence.     */\r\n/* I don't know if that could help.                                     */\r\n/* Data-dependent loads are always ordered.                             */\r\n/* Based on the above references, eieio is intended for use on          */\r\n/* uncached memory, which we don't support.  It does not order loads    */\r\n/* from cached memory.                                                  */\r\n/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to   */\r\n/* track some of this down and correcting my misunderstandings. -HB     */\r\n/* Earl Chew subsequently contributed further fixes & additions.        */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n        /* There seems to be no byte equivalent of lwarx, so this       */\r\n        /* may really be what we want, at least in the 32-bit case.     */\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm__ __volatile__(\"sync\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n/* lwsync apparently works for everything but a StoreLoad barrier.      */\r\nAO_INLINE void\r\nAO_lwsync(void)\r\n{\r\n#ifdef __NO_LWSYNC__\r\n  __asm__ __volatile__(\"sync\" : : : \"memory\");\r\n#else\r\n  __asm__ __volatile__(\"lwsync\" : : : \"memory\");\r\n#endif\r\n}\r\n\r\n#define AO_nop_write() AO_lwsync()\r\n#define AO_HAVE_nop_write\r\n\r\n#define AO_nop_read() AO_lwsync()\r\n#define AO_HAVE_nop_read\r\n\r\n/* We explicitly specify load_acquire, since it is important, and can   */\r\n/* be implemented relatively cheaply.  It could be implemented          */\r\n/* with an ordinary load followed by a lwsync.  But the general wisdom  */\r\n/* seems to be that a data dependent branch followed by an isync is     */\r\n/* cheaper.  And the documentation is fairly explicit that this also    */\r\n/* has acquire semantics.                                               */\r\n/* ppc64 uses ld not lwz */\r\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\r\nAO_INLINE AO_t\r\nAO_load_acquire(const volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n\r\n   __asm__ __volatile__ (\r\n    \"ld%U1%X1 %0,%1\\n\"\r\n    \"cmpw %0,%0\\n\"\r\n    \"bne- 1f\\n\"\r\n    \"1: isync\\n\"\r\n    : \"=r\" (result)\r\n    : \"m\"(*addr) : \"memory\", \"cr0\");\r\n  return result;\r\n}\r\n#else\r\nAO_INLINE AO_t\r\nAO_load_acquire(const volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n\r\n  /* FIXME: We should get gcc to allocate one of the condition  */\r\n  /* registers.  I always got \"impossible constraint\" when I    */\r\n  /* tried the \"y\" constraint.                                  */\r\n  __asm__ __volatile__ (\r\n    \"lwz%U1%X1 %0,%1\\n\"\r\n    \"cmpw %0,%0\\n\"\r\n    \"bne- 1f\\n\"\r\n    \"1: isync\\n\"\r\n    : \"=r\" (result)\r\n    : \"m\"(*addr) : \"memory\", \"cc\");\r\n  return result;\r\n}\r\n#endif\r\n#define AO_HAVE_load_acquire\r\n\r\n/* We explicitly specify store_release, since it relies         */\r\n/* on the fact that lwsync is also a LoadStore barrier.         */\r\nAO_INLINE void\r\nAO_store_release(volatile AO_t *addr, AO_t value)\r\n{\r\n  AO_lwsync();\r\n  *addr = value;\r\n}\r\n\r\n#define AO_HAVE_load_acquire\r\n\r\n/* This is similar to the code in the garbage collector.  Deleting      */\r\n/* this and having it synthesized from compare_and_swap would probably  */\r\n/* only cost us a load immediate instruction.                           */\r\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\r\n/* Completely untested.  And we should be using smaller objects anyway. */\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set(volatile AO_TS_t *addr) {\r\n  unsigned long oldval;\r\n  unsigned long temp = 1; /* locked value */\r\n\r\n  __asm__ __volatile__(\r\n               \"1:ldarx %0,0,%1\\n\"   /* load and reserve               */\r\n               \"cmpdi %0, 0\\n\"       /* if load is                     */\r\n               \"bne 2f\\n\"            /*   non-zero, return already set */\r\n               \"stdcx. %2,0,%1\\n\"    /* else store conditional         */\r\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\r\n               \"2:\\n\"                /* oldval is zero if we set       */\r\n              : \"=&r\"(oldval)\r\n              : \"r\"(addr), \"r\"(temp)\r\n              : \"memory\", \"cr0\");\r\n\r\n  return (AO_TS_VAL_t)oldval;\r\n}\r\n\r\n#else\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set(volatile AO_TS_t *addr) {\r\n  int oldval;\r\n  int temp = 1; /* locked value */\r\n\r\n  __asm__ __volatile__(\r\n               \"1:lwarx %0,0,%1\\n\"   /* load and reserve               */\r\n               \"cmpwi %0, 0\\n\"       /* if load is                     */\r\n               \"bne 2f\\n\"            /*   non-zero, return already set */\r\n               \"stwcx. %2,0,%1\\n\"    /* else store conditional         */\r\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\r\n               \"2:\\n\"                /* oldval is zero if we set       */\r\n              : \"=&r\"(oldval)\r\n              : \"r\"(addr), \"r\"(temp)\r\n              : \"memory\", \"cr0\");\r\n\r\n  return (AO_TS_VAL_t)oldval;\r\n}\r\n\r\n#endif\r\n\r\n#define AO_HAVE_test_and_set\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_acquire(volatile AO_TS_t *addr) {\r\n  AO_TS_VAL_t result = AO_test_and_set(addr);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_acquire\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_release(volatile AO_TS_t *addr) {\r\n  AO_lwsync();\r\n  return AO_test_and_set(addr);\r\n}\r\n\r\n#define AO_HAVE_test_and_set_release\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr) {\r\n  AO_TS_VAL_t result;\r\n  AO_lwsync();\r\n  result = AO_test_and_set(addr);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\r\n/* FIXME: Completely untested.  */\r\nAO_INLINE int\r\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_t oldval;\r\n  int result = 0;\r\n\r\n  __asm__ __volatile__(\r\n               \"1:ldarx %0,0,%2\\n\"   /* load and reserve              */\r\n               \"cmpd %0, %4\\n\"      /* if load is not equal to  */\r\n               \"bne 2f\\n\"            /*   old, fail                     */\r\n               \"stdcx. %3,0,%2\\n\"    /* else store conditional         */\r\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\r\n               \"li %1,1\\n\"           /* result = 1;                     */\r\n               \"2:\\n\"\r\n              : \"=&r\"(oldval), \"=&r\"(result)\r\n              : \"r\"(addr), \"r\"(new_val), \"r\"(old), \"1\"(result)\r\n              : \"memory\", \"cr0\");\r\n\r\n  return result;\r\n}\r\n\r\n#else\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_t oldval;\r\n  int result = 0;\r\n\r\n  __asm__ __volatile__(\r\n               \"1:lwarx %0,0,%2\\n\"   /* load and reserve              */\r\n               \"cmpw %0, %4\\n\"      /* if load is not equal to  */\r\n               \"bne 2f\\n\"            /*   old, fail                     */\r\n               \"stwcx. %3,0,%2\\n\"    /* else store conditional         */\r\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\r\n               \"li %1,1\\n\"           /* result = 1;                     */\r\n               \"2:\\n\"\r\n              : \"=&r\"(oldval), \"=&r\"(result)\r\n              : \"r\"(addr), \"r\"(new_val), \"r\"(old), \"1\"(result)\r\n              : \"memory\", \"cr0\");\r\n\r\n  return result;\r\n}\r\n#endif\r\n\r\n#define AO_HAVE_compare_and_swap\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  int result = AO_compare_and_swap(addr, old, new_val);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_lwsync();\r\n  return AO_compare_and_swap(addr, old, new_val);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_t result;\r\n  AO_lwsync();\r\n  result = AO_compare_and_swap(addr, old, new_val);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\r\n/* FIXME: Completely untested.                                          */\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add(volatile AO_t *addr, AO_t incr) {\r\n  AO_t oldval;\r\n  AO_t newval;\r\n\r\n  __asm__ __volatile__(\r\n               \"1:ldarx %0,0,%2\\n\"   /* load and reserve                */\r\n               \"add %1,%0,%3\\n\"      /* increment                       */\r\n               \"stdcx. %1,0,%2\\n\"    /* store conditional               */\r\n               \"bne- 1b\\n\"           /* retry if lost reservation       */\r\n              : \"=&r\"(oldval), \"=&r\"(newval)\r\n               : \"r\"(addr), \"r\"(incr)\r\n              : \"memory\", \"cr0\");\r\n\r\n  return oldval;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add\r\n\r\n#else\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add(volatile AO_t *addr, AO_t incr) {\r\n  AO_t oldval;\r\n  AO_t newval;\r\n\r\n  __asm__ __volatile__(\r\n               \"1:lwarx %0,0,%2\\n\"   /* load and reserve                */\r\n               \"add %1,%0,%3\\n\"      /* increment                       */\r\n               \"stwcx. %1,0,%2\\n\"    /* store conditional               */\r\n               \"bne- 1b\\n\"           /* retry if lost reservation       */\r\n              : \"=&r\"(oldval), \"=&r\"(newval)\r\n               : \"r\"(addr), \"r\"(incr)\r\n              : \"memory\", \"cr0\");\r\n\r\n  return oldval;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add\r\n\r\n#endif\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr) {\r\n  AO_t result = AO_fetch_and_add(addr, incr);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_release(volatile AO_t *addr, AO_t incr) {\r\n  AO_lwsync();\r\n  return AO_fetch_and_add(addr, incr);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_release\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full(volatile AO_t *addr, AO_t incr) {\r\n  AO_t result;\r\n  AO_lwsync();\r\n  result = AO_fetch_and_add(addr, incr);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\r\n#else\r\n# include \"../ao_t_is_int.h\"\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/s390.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n\r\n/* FIXME: untested.                                             */\r\n/* The relevant documentation appears to be at                  */\r\n/* http://publibz.boulder.ibm.com/epubs/pdf/dz9zr003.pdf        */\r\n/* around page 5-96.  Apparently:                               */\r\n/* - Memory references in general are atomic only for a single  */\r\n/*   byte.  But it appears that the most common load/store      */\r\n/*   instructions also guarantee atomicity for aligned          */\r\n/*   operands of standard types.  WE FOOLISHLY ASSUME that      */\r\n/*   compilers only generate those.  If that turns out to be    */\r\n/*   wrong, we need inline assembly code for AO_load and        */\r\n/*   AO_store.                                                  */\r\n/* - A store followed by a load is unordered since the store    */\r\n/*   may be delayed.  Otherwise everything is ordered.          */\r\n/* - There is a hardware compare-and-swap (CS) instruction.     */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n/* FIXME: Is there a way to do byte-sized test-and-set? */\r\n\r\n/* FIXME: AO_nop_full should probably be implemented directly.  */\r\n/* It appears that certain BCR instructions have that effect.   */\r\n/* Presumably they're cheaper than CS?                          */\r\n\r\nAO_INLINE AO_t AO_compare_and_swap_full(volatile AO_t *addr,\r\n                                               AO_t old, AO_t new_val)\r\n{\r\n  int retval;\r\n  __asm__ __volatile__ (\r\n# ifndef __s390x__\r\n    \"     cs  %1,%2,0(%3)\\n\"\r\n# else\r\n    \"     csg %1,%2,0(%3)\\n\"\r\n# endif\r\n  \"     ipm %0\\n\"\r\n  \"     srl %0,28\\n\"\r\n  : \"=&d\" (retval), \"+d\" (old)\r\n  : \"d\" (new_val), \"a\" (addr)\r\n  : \"cc\", \"memory\");\r\n  return retval == 0;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n/* FIXME: Add double-wide compare-and-swap for 32-bit executables.      */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/sh.h",
    "content": "/*\r\n * Copyright (c) 2009 by Takashi YOSHII. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n#include \"../ordered.h\"\r\n\r\n/* sh has tas.b(byte) only */\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  int oldval;\r\n  __asm__ __volatile__(\r\n        \"tas.b @%1; movt %0\"\r\n        : \"=r\" (oldval)\r\n        : \"r\" (addr)\r\n        : \"t\", \"memory\");\r\n  return oldval? AO_TS_CLEAR : AO_TS_SET;\r\n}\r\n#define AO_HAVE_test_and_set_full\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/sparc.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n */\r\n\r\n/* FIXME.  Very incomplete.  No support for sparc64.    */\r\n/* Non-ancient SPARCs provide compare-and-swap (casa).  */\r\n/* We should make that available.                       */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n/* Real SPARC code uses TSO:                            */\r\n#include \"../ordered_except_wr.h\"\r\n\r\n/* Test_and_set location is just a byte.                */\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr) {\r\n   AO_TS_VAL_t oldval;\r\n\r\n   __asm__ __volatile__(\"ldstub %1,%0\"\r\n                        : \"=r\"(oldval), \"=m\"(*addr)\r\n                        : \"m\"(*addr) : \"memory\");\r\n   return oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n#ifndef AO_NO_SPARC_V9\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  char ret;\r\n  __asm__ __volatile__ (\"membar #StoreLoad | #LoadLoad\\n\\t\"\r\n#                       if defined(__arch64__)\r\n                          \"casx [%2],%0,%1\\n\\t\"\r\n#                       else\r\n                          \"cas [%2],%0,%1\\n\\t\" /* 32-bit version */\r\n#                       endif\r\n                        \"membar #StoreLoad | #StoreStore\\n\\t\"\r\n                        \"cmp %0,%1\\n\\t\"\r\n                        \"be,a 0f\\n\\t\"\r\n                        \"mov 1,%0\\n\\t\"/* one insn after branch always executed */\r\n                        \"clr %0\\n\\t\"\r\n                        \"0:\\n\\t\"\r\n                        : \"=r\" (ret), \"+r\" (new_val)\r\n                        : \"r\" (addr), \"0\" (old)\r\n                        : \"memory\", \"cc\");\r\n  return (int)ret;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n#endif /* AO_NO_SPARC_V9 */\r\n\r\n/* FIXME: This needs to be extended for SPARC v8 and v9.        */\r\n/* SPARC V8 also has swap.  V9 has CAS.                         */\r\n/* There are barriers like membar #LoadStore.                   */\r\n/* CASA (32-bit) and CASXA(64-bit) instructions were            */\r\n/* added in V9.                                                 */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/x86.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n * Some of the machine specific code was borrowed from our GC distribution.\r\n */\r\n\r\n/* The following really assume we have a 486 or better.  Unfortunately  */\r\n/* gcc doesn't define a suitable feature test macro based on command    */\r\n/* line options.                                                        */\r\n/* We should perhaps test dynamically.                                  */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Real X86 implementations, except for some old WinChips, appear       */\r\n/* to enforce ordering between memory operations, EXCEPT that a later   */\r\n/* read can pass earlier writes, presumably due to the visible          */\r\n/* presence of store buffers.                                           */\r\n/* We ignore both the WinChips, and the fact that the official specs    */\r\n/* seem to be much weaker (and arguably too weak to be usable).         */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\n#if defined(AO_USE_PENTIUM4_INSTRS)\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n#else\r\n\r\n/* We could use the cpuid instruction.  But that seems to be slower     */\r\n/* than the default implementation based on test_and_set_full.  Thus    */\r\n/* we omit that bit of misinformation here.                             */\r\n\r\n#endif\r\n\r\n/* As far as we can tell, the lfence and sfence instructions are not    */\r\n/* currently needed or useful for cached memory accesses.               */\r\n\r\n/* Really only works for 486 and later */\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE unsigned char\r\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\r\n{\r\n  unsigned char result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\r\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_char_fetch_and_add_full\r\n\r\nAO_INLINE unsigned short\r\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\r\n{\r\n  unsigned short result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_short_fetch_and_add_full\r\n\r\n/* Really only works for 486 and later */\r\nAO_INLINE void\r\nAO_or_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  __asm__ __volatile__ (\"lock; orl %1, %0\" :\r\n                        \"=m\" (*p) : \"r\" (incr), \"m\" (*p) : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_or_full\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  unsigned char oldval;\r\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\r\n  __asm__ __volatile__(\"xchgb %0, %1\"\r\n                : \"=q\"(oldval), \"=m\"(*addr)\r\n                : \"0\"(0xff), \"m\"(*addr) : \"memory\");\r\n  return (AO_TS_VAL_t)oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\r\n{\r\n# ifdef AO_USE_SYNC_CAS_BUILTIN\r\n    return (int)__sync_bool_compare_and_swap(addr, old, new_val);\r\n# else\r\n    char result;\r\n    __asm__ __volatile__(\"lock; cmpxchgl %3, %0; setz %1\"\r\n                         : \"=m\" (*addr), \"=a\" (result)\r\n                         : \"m\" (*addr), \"r\" (new_val), \"a\" (old) : \"memory\");\r\n    return (int)result;\r\n# endif\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n/* Returns nonzero if the comparison succeeded. */\r\n/* Really requires at least a Pentium.          */\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n  char result;\r\n#if __PIC__\r\n  /* If PIC is turned on, we can't use %ebx as it is reserved for the\r\n     GOT pointer.  We can save and restore %ebx because GCC won't be\r\n     using it for anything else (such as any of the m operands) */\r\n  __asm__ __volatile__(\"pushl %%ebx;\"   /* save ebx used for PIC GOT ptr */\r\n                       \"movl %6,%%ebx;\" /* move new_val2 to %ebx */\r\n                       \"lock; cmpxchg8b %0; setz %1;\"\r\n                       \"pop %%ebx;\"     /* restore %ebx */\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\r\n                         \"c\" (new_val2), \"m\" (new_val1) : \"memory\");\r\n#else\r\n  /* We can't just do the same thing in non-PIC mode, because GCC\r\n   * might be using %ebx as the memory operand.  We could have ifdef'd\r\n   * in a clobber, but there's no point doing the push/pop if we don't\r\n   * have to. */\r\n  __asm__ __volatile__(\"lock; cmpxchg8b %0; setz %1;\"\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\r\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\r\n#endif\r\n  return (int) result;\r\n}\r\n\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n\r\n#include \"../ao_t_is_int.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/gcc/x86_64.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n * Some of the machine specific code was borrowed from our GC distribution.\r\n */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Real X86 implementations appear                                      */\r\n/* to enforce ordering between memory operations, EXCEPT that a later   */\r\n/* read can pass earlier writes, presumably due to the visible          */\r\n/* presence of store buffers.                                           */\r\n/* We ignore the fact that the official specs                           */\r\n/* seem to be much weaker (and arguably too weak to be usable).         */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  /* Note: \"mfence\" (SSE2) is supported on all x86_64/amd64 chips.      */\r\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n/* As far as we can tell, the lfence and sfence instructions are not    */\r\n/* currently needed or useful for cached memory accesses.               */\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddq %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE unsigned char\r\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\r\n{\r\n  unsigned char result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\r\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_char_fetch_and_add_full\r\n\r\nAO_INLINE unsigned short\r\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\r\n{\r\n  unsigned short result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_short_fetch_and_add_full\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)\r\n{\r\n  unsigned int result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_int_fetch_and_add_full\r\n\r\nAO_INLINE void\r\nAO_or_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  __asm__ __volatile__ (\"lock; orq %1, %0\" :\r\n                        \"=m\" (*p) : \"r\" (incr), \"m\" (*p) : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_or_full\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  unsigned char oldval;\r\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\r\n  __asm__ __volatile__(\"xchgb %0, %1\"\r\n                : \"=q\"(oldval), \"=m\"(*addr)\r\n                : \"0\"(0xff), \"m\"(*addr) : \"memory\");\r\n  return (AO_TS_VAL_t)oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\r\n{\r\n# ifdef AO_USE_SYNC_CAS_BUILTIN\r\n    return (int)__sync_bool_compare_and_swap(addr, old, new_val);\r\n# else\r\n    char result;\r\n    __asm__ __volatile__(\"lock; cmpxchgq %3, %0; setz %1\"\r\n                         : \"=m\" (*addr), \"=a\" (result)\r\n                         : \"m\" (*addr), \"r\" (new_val), \"a\" (old) : \"memory\");\r\n    return (int) result;\r\n# endif\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n#ifdef AO_CMPXCHG16B_AVAILABLE\r\n/* NEC LE-IT: older AMD Opterons are missing this instruction.\r\n * On these machines SIGILL will be thrown.\r\n * Define AO_WEAK_DOUBLE_CAS_EMULATION to have an emulated\r\n * (lock based) version available */\r\n/* HB: Changed this to not define either by default.  There are\r\n * enough machines and tool chains around on which cmpxchg16b\r\n * doesn't work.  And the emulation is unsafe by our usual rules.\r\n * Hoewever both are clearly useful in certain cases.\r\n */\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n  char result;\r\n  __asm__ __volatile__(\"lock; cmpxchg16b %0; setz %1\"\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\r\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\r\n  return (int) result;\r\n}\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n#else\r\n/* this one provides spinlock based emulation of CAS implemented in     */\r\n/* atomic_ops.c.  We probably do not want to do this here, since it is  */\r\n/* not atomic with respect to other kinds of updates of *addr.  On the  */\r\n/* other hand, this may be a useful facility on occasion.               */\r\n#ifdef AO_WEAK_DOUBLE_CAS_EMULATION\r\nint AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,\r\n                                                AO_t old_val1, AO_t old_val2,\r\n                                                AO_t new_val1, AO_t new_val2);\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n        return AO_compare_double_and_swap_double_emulation(addr,\r\n                                                           old_val1, old_val2,\r\n                                                           new_val1, new_val2);\r\n}\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n#endif /* AO_WEAK_DOUBLE_CAS_EMULATION */\r\n#endif /* AO_CMPXCHG16B_AVAILABLE */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/generic_pthread.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/* The following is useful primarily for debugging and documentation.   */\r\n/* We define various atomic operations by acquiring a global pthread    */\r\n/* lock.  The resulting implementation will perform poorly, but should  */\r\n/* be correct unless it is used from signal handlers.                   */\r\n/* We assume that all pthread operations act like full memory barriers. */\r\n/* (We believe that is the intent of the specification.)                */\r\n\r\n#include <pthread.h>\r\n\r\n#include \"test_and_set_t_is_ao_t.h\"\r\n        /* This is not necessarily compatible with the native           */\r\n        /* implementation.  But those can't be safely mixed anyway.     */\r\n\r\n/* We define only the full barrier variants, and count on the           */\r\n/* generalization section below to fill in the rest.                    */\r\nextern pthread_mutex_t AO_pt_lock;\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE AO_t\r\nAO_load_full(const volatile AO_t *addr)\r\n{\r\n  AO_t result;\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  result = *addr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_load_full\r\n\r\nAO_INLINE void\r\nAO_store_full(volatile AO_t *addr, AO_t val)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  *addr = val;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n}\r\n\r\n#define AO_HAVE_store_full\r\n\r\nAO_INLINE unsigned char\r\nAO_char_load_full(const volatile unsigned char *addr)\r\n{\r\n  unsigned char result;\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  result = *addr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_char_load_full\r\n\r\nAO_INLINE void\r\nAO_char_store_full(volatile unsigned char *addr, unsigned char val)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  *addr = val;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n}\r\n\r\n#define AO_HAVE_char_store_full\r\n\r\nAO_INLINE unsigned short\r\nAO_short_load_full(const volatile unsigned short *addr)\r\n{\r\n  unsigned short result;\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  result = *addr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_short_load_full\r\n\r\nAO_INLINE void\r\nAO_short_store_full(volatile unsigned short *addr, unsigned short val)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  *addr = val;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n}\r\n\r\n#define AO_HAVE_short_store_full\r\n\r\nAO_INLINE unsigned int\r\nAO_int_load_full(const volatile unsigned int *addr)\r\n{\r\n  unsigned int result;\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  result = *addr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_int_load_full\r\n\r\nAO_INLINE void\r\nAO_int_store_full(volatile unsigned int *addr, unsigned int val)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  *addr = val;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n}\r\n\r\n#define AO_HAVE_int_store_full\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  AO_TS_VAL_t result;\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  result = (AO_TS_VAL_t)(*addr);\r\n  *addr = AO_TS_SET;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  assert(result == AO_TS_SET || result == AO_TS_CLEAR);\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full(volatile AO_t *p, AO_t incr)\r\n{\r\n  AO_t tmp;\r\n\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  tmp = *p;\r\n  *p = tmp + incr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return tmp;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE unsigned char\r\nAO_char_fetch_and_add_full(volatile unsigned char *p, unsigned char incr)\r\n{\r\n  unsigned char tmp;\r\n\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  tmp = *p;\r\n  *p = tmp + incr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return tmp;\r\n}\r\n\r\n#define AO_HAVE_char_fetch_and_add_full\r\n\r\nAO_INLINE unsigned short\r\nAO_short_fetch_and_add_full(volatile unsigned short *p, unsigned short incr)\r\n{\r\n  unsigned short tmp;\r\n\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  tmp = *p;\r\n  *p = tmp + incr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return tmp;\r\n}\r\n\r\n#define AO_HAVE_short_fetch_and_add_full\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_add_full(volatile unsigned int *p, unsigned int incr)\r\n{\r\n  unsigned int tmp;\r\n\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  tmp = *p;\r\n  *p = tmp + incr;\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n  return tmp;\r\n}\r\n\r\n#define AO_HAVE_int_fetch_and_add_full\r\n\r\nAO_INLINE void\r\nAO_or_full(volatile AO_t *p, AO_t incr)\r\n{\r\n  AO_t tmp;\r\n\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  tmp = *p;\r\n  *p = (tmp | incr);\r\n  pthread_mutex_unlock(&AO_pt_lock);\r\n}\r\n\r\n#define AO_HAVE_or_full\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  if (*addr == old)\r\n    {\r\n      *addr = new_val;\r\n      pthread_mutex_unlock(&AO_pt_lock);\r\n      return 1;\r\n    }\r\n  else\r\n    pthread_mutex_unlock(&AO_pt_lock);\r\n    return 0;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n/* Unlike real architectures, we define both double-width CAS variants. */\r\n\r\ntypedef struct {\r\n        AO_t AO_val1;\r\n        AO_t AO_val2;\r\n} AO_double_t;\r\n\r\n#define AO_HAVE_double_t\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old1, AO_t old2,\r\n                                       AO_t new1, AO_t new2)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  if (addr -> AO_val1 == old1 && addr -> AO_val2 == old2)\r\n    {\r\n      addr -> AO_val1 = new1;\r\n      addr -> AO_val2 = new2;\r\n      pthread_mutex_unlock(&AO_pt_lock);\r\n      return 1;\r\n    }\r\n  else\r\n    pthread_mutex_unlock(&AO_pt_lock);\r\n    return 0;\r\n}\r\n\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_double_full(volatile AO_double_t *addr,\r\n                                AO_t old1,\r\n                                AO_t new1, AO_t new2)\r\n{\r\n  pthread_mutex_lock(&AO_pt_lock);\r\n  if (addr -> AO_val1 == old1)\r\n    {\r\n      addr -> AO_val1 = new1;\r\n      addr -> AO_val2 = new2;\r\n      pthread_mutex_unlock(&AO_pt_lock);\r\n      return 1;\r\n    }\r\n  else\r\n    pthread_mutex_unlock(&AO_pt_lock);\r\n    return 0;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_double_full\r\n\r\n/* We can't use hardware loads and stores, since they don't     */\r\n/* interact correctly with atomic updates.                      */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/hpc/hppa.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n *\r\n * Derived from the corresponding header file for gcc.\r\n *\r\n */\r\n\r\n#include \"../atomic_load_store.h\"\r\n\r\n/* Some architecture set descriptions include special \"ordered\" memory  */\r\n/* operations.  As far as we can tell, no existing processors actually  */\r\n/* require those.  Nor does it appear likely that future processors     */\r\n/* will.                                                                */\r\n/* FIXME:                                                               */\r\n/* The PA emulator on Itanium may obey weaker restrictions.             */\r\n/* There should be a mode in which we don't assume sequential           */\r\n/* consistency here.                                                    */\r\n#include \"../ordered.h\"\r\n\r\n#include <machine/inline.h>\r\n\r\n/* GCC will not guarantee the alignment we need, use four lock words    */\r\n/* and select the correctly aligned datum. See the glibc 2.3.2          */\r\n/* linuxthread port for the original implementation.                    */\r\nstruct AO_pa_clearable_loc {\r\n  int data[4];\r\n};\r\n\r\n#undef AO_TS_INITIALIZER\r\n#define AO_TS_t struct AO_pa_clearable_loc\r\n#define AO_TS_INITIALIZER {1,1,1,1}\r\n/* Switch meaning of set and clear, since we only have an atomic clear  */\r\n/* instruction.                                                         */\r\ntypedef enum {AO_PA_TS_set = 0, AO_PA_TS_clear = 1} AO_PA_TS_val;\r\n#define AO_TS_VAL_t AO_PA_TS_val\r\n#define AO_TS_CLEAR AO_PA_TS_clear\r\n#define AO_TS_SET AO_PA_TS_set\r\n\r\n/* The hppa only has one atomic read and modify memory operation,       */\r\n/* load and clear, so hppa spinlocks must use zero to signify that      */\r\n/* someone is holding the lock.  The address used for the ldcw          */\r\n/* semaphore must be 16-byte aligned.                                   */\r\n\r\n#define __ldcw(a, ret)  \\\r\n  _LDCWX(0 /* index */, 0 /* s */, a /* base */, ret);\r\n\r\n/* Because malloc only guarantees 8-byte alignment for malloc'd data,   */\r\n/* and GCC only guarantees 8-byte alignment for stack locals, we can't  */\r\n/* be assured of 16-byte alignment for atomic lock data even if we      */\r\n/* specify \"__attribute ((aligned(16)))\" in the type declaration.  So,  */\r\n/* we use a struct containing an array of four ints for the atomic lock */\r\n/* type and dynamically select the 16-byte aligned int from the array   */\r\n/* for the semaphore.                                                   */\r\n#define __PA_LDCW_ALIGNMENT 16\r\n\r\n#define __ldcw_align(a, ret) { \\\r\n  ret = (unsigned long) a;                      \\\r\n  ret += __PA_LDCW_ALIGNMENT - 1;                                       \\\r\n  ret &= ~(__PA_LDCW_ALIGNMENT - 1);                                    \\\r\n}\r\n\r\n/* Works on PA 1.1 and PA 2.0 systems */\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t * addr)\r\n{\r\n  register unsigned int ret;\r\n  register unsigned long a;\r\n  __ldcw_align (addr, a);\r\n  __ldcw (a, ret);\r\n  return ret;\r\n}\r\n\r\nAO_INLINE void\r\nAO_pa_clear(volatile AO_TS_t * addr)\r\n{\r\n  unsigned long a;\r\n  __ldcw_align (addr,a);\r\n  AO_compiler_barrier();\r\n  *(volatile unsigned int *)a = 1;\r\n}\r\n#define AO_CLEAR(addr) AO_pa_clear(addr)\r\n\r\n#define AO_HAVE_test_and_set_full\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/hpc/ia64.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * This file specifies Itanimum primitives for use with the HP compiler\r\n * under HP/UX.  We use intrinsics instead of the inline assembly code in the\r\n * gcc file.\r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n#include \"../all_acquire_release_volatile.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#include <machine/sys/inline.h>\r\n\r\n#ifdef __LP64__\r\n# define AO_T_FASIZE _FASZ_D\r\n# define AO_T_SIZE _SZ_D\r\n#else\r\n# define AO_T_FASIZE _FASZ_W\r\n# define AO_T_SIZE _SZ_W\r\n#endif\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  _Asm_mf();\r\n}\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_acquire (volatile AO_t *p)\r\n{\r\n  return _Asm_fetchadd(AO_T_FASIZE, _SEM_ACQ, p, 1,\r\n                       _LDHINT_NONE, _DOWN_MEM_FENCE);\r\n}\r\n#define AO_HAVE_fetch_and_add1_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_release (volatile AO_t *p)\r\n{\r\n  return _Asm_fetchadd(AO_T_FASIZE, _SEM_REL, p, 1,\r\n                       _LDHINT_NONE, _UP_MEM_FENCE);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1_release\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_acquire (volatile AO_t *p)\r\n{\r\n  return _Asm_fetchadd(AO_T_FASIZE, _SEM_ACQ, p, -1,\r\n                       _LDHINT_NONE, _DOWN_MEM_FENCE);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_release (volatile AO_t *p)\r\n{\r\n  return _Asm_fetchadd(AO_T_FASIZE, _SEM_REL, p, -1,\r\n                       _LDHINT_NONE, _UP_MEM_FENCE);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_release\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_acquire(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  AO_t oldval;\r\n\r\n  _Asm_mov_to_ar(_AREG_CCV, old, _DOWN_MEM_FENCE);\r\n  oldval = _Asm_cmpxchg(AO_T_SIZE, _SEM_ACQ, addr,\r\n                        new_val, _LDHINT_NONE, _DOWN_MEM_FENCE);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_release(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  AO_t oldval;\r\n  _Asm_mov_to_ar(_AREG_CCV, old, _UP_MEM_FENCE);\r\n  oldval = _Asm_cmpxchg(AO_T_SIZE, _SEM_REL, addr,\r\n                        new_val, _LDHINT_NONE, _UP_MEM_FENCE);\r\n  /* Hopefully the compiler knows not to reorder the above two? */\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_char_compare_and_swap_acquire(volatile unsigned char *addr,\r\n                                 unsigned char old, unsigned char new_val)\r\n{\r\n  unsigned char oldval;\r\n\r\n  _Asm_mov_to_ar(_AREG_CCV, old, _DOWN_MEM_FENCE);\r\n  oldval = _Asm_cmpxchg(_SZ_B, _SEM_ACQ, addr,\r\n                        new_val, _LDHINT_NONE, _DOWN_MEM_FENCE);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_char_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_char_compare_and_swap_release(volatile unsigned char *addr,\r\n                                 unsigned char old, unsigned char new_val)\r\n{\r\n  unsigned char oldval;\r\n  _Asm_mov_to_ar(_AREG_CCV, old, _UP_MEM_FENCE);\r\n  oldval = _Asm_cmpxchg(_SZ_B, _SEM_REL, addr,\r\n                        new_val, _LDHINT_NONE, _UP_MEM_FENCE);\r\n  /* Hopefully the compiler knows not to reorder the above two? */\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_char_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_short_compare_and_swap_acquire(volatile unsigned short *addr,\r\n                                 unsigned short old, unsigned short new_val)\r\n{\r\n  unsigned short oldval;\r\n\r\n  _Asm_mov_to_ar(_AREG_CCV, old, _DOWN_MEM_FENCE);\r\n  oldval = _Asm_cmpxchg(_SZ_B, _SEM_ACQ, addr,\r\n                        new_val, _LDHINT_NONE, _DOWN_MEM_FENCE);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_short_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_short_compare_and_swap_release(volatile unsigned short *addr,\r\n                                 unsigned short old, unsigned short new_val)\r\n{\r\n  unsigned short oldval;\r\n  _Asm_mov_to_ar(_AREG_CCV, old, _UP_MEM_FENCE);\r\n  oldval = _Asm_cmpxchg(_SZ_B, _SEM_REL, addr,\r\n                        new_val, _LDHINT_NONE, _UP_MEM_FENCE);\r\n  /* Hopefully the compiler knows not to reorder the above two? */\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_short_compare_and_swap_release\r\n\r\n#ifndef __LP64__\r\n# include \"../ao_t_is_int.h\"\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/ibmc/powerpc.h",
    "content": "/* FIXME.  This is only a placeholder for the AIX compiler.             */\r\n/* It doesn't work.  Please send a patch.                               */\r\n/* Memory model documented at http://www-106.ibm.com/developerworks/    */\r\n/* eserver/articles/archguide.html and (clearer)                        */\r\n/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */\r\n/* There appears to be no implicit ordering between any kind of         */\r\n/* independent memory references.                                       */\r\n/* Architecture enforces some ordering based on control dependence.     */\r\n/* I don't know if that could help.                                     */\r\n/* Data-dependent loads are always ordered.                             */\r\n/* Based on the above references, eieio is intended for use on          */\r\n/* uncached memory, which we don't support.  It does not order loads    */\r\n/* from cached memory.                                                  */\r\n/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to   */\r\n/* track some of this down and correcting my misunderstandings. -HB     */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\nvoid AO_sync(void);\r\n#pragma mc_func AO_sync { \"7c0004ac\" }\r\n\r\n#ifdef __NO_LWSYNC__\r\n# define AO_lwsync AO_sync\r\n#else\r\n  void AO_lwsync(void);\r\n#pragma mc_func AO_lwsync { \"7c2004ac\" }\r\n#endif\r\n\r\n#define AO_nop_write() AO_lwsync()\r\n#define AO_HAVE_nop_write\r\n\r\n#define AO_nop_read() AO_lwsync()\r\n#define AO_HAVE_nop_read\r\n\r\n/* We explicitly specify load_acquire and store_release, since these    */\r\n/* rely on the fact that lwsync is also a LoadStore barrier.            */\r\nAO_INLINE AO_t\r\nAO_load_acquire(const volatile AO_t *addr)\r\n{\r\n  AO_t result = *addr;\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_load_acquire\r\n\r\nAO_INLINE void\r\nAO_store_release(volatile AO_t *addr, AO_t value)\r\n{\r\n  AO_lwsync();\r\n  *addr = value;\r\n}\r\n\r\n#define AO_HAVE_load_acquire\r\n\r\n/* This is similar to the code in the garbage collector.  Deleting      */\r\n/* this and having it synthesized from compare_and_swap would probably  */\r\n/* only cost us a load immediate instruction.                           */\r\n/*AO_INLINE AO_TS_VAL_t\r\nAO_test_and_set(volatile AO_TS_t *addr) {\r\n# error FIXME Implement me\r\n}\r\n\r\n#define AO_HAVE_test_and_set*/\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_acquire(volatile AO_TS_t *addr) {\r\n  AO_TS_VAL_t result = AO_test_and_set(addr);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_acquire\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_release(volatile AO_TS_t *addr) {\r\n  AO_lwsync();\r\n  return AO_test_and_set(addr);\r\n}\r\n\r\n#define AO_HAVE_test_and_set_release\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr) {\r\n  AO_TS_VAL_t result;\r\n  AO_lwsync();\r\n  result = AO_test_and_set(addr);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/*AO_INLINE AO_t\r\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n# error FIXME Implement me\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap*/\r\n\r\nAO_INLINE AO_t\r\nAO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_t result = AO_compare_and_swap(addr, old, new_val);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_lwsync();\r\n  return AO_compare_and_swap(addr, old, new_val);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_release\r\n\r\nAO_INLINE AO_t\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\r\n  AO_t result;\r\n  AO_lwsync();\r\n  result = AO_compare_and_swap(addr, old, new_val);\r\n  AO_lwsync();\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n/* FIXME: We should also implement fetch_and_add and or primitives      */\r\n/* directly.                                                            */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/icc/ia64.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * This file specifies Itanimum primitives for use with the Intel (ecc)\r\n * compiler.  We use intrinsics instead of the inline assembly code in the\r\n * gcc file.\r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#include <ia64intrin.h>\r\n\r\n/* The acquire release semantics of volatile can be turned off.  And volatile   */\r\n/* operations in icc9 don't imply ordering with respect to other nonvolatile    */\r\n/* operations.                                                                  */\r\n\r\n#define AO_INTEL_PTR_t void *\r\n\r\nAO_INLINE AO_t\r\nAO_load_acquire(const volatile AO_t *p)\r\n{\r\n  return (AO_t)(__ld8_acq((AO_INTEL_PTR_t)p));\r\n}\r\n#define AO_HAVE_load_acquire\r\n\r\nAO_INLINE void\r\nAO_store_release(volatile AO_t *p, AO_t val)\r\n{\r\n  __st8_rel((AO_INTEL_PTR_t)p, (__int64)val);\r\n}\r\n#define AO_HAVE_store_release\r\n\r\nAO_INLINE unsigned char\r\nAO_char_load_acquire(const volatile unsigned char *p)\r\n{\r\n  /* A normal volatile load generates an ld.acq         */\r\n  return (__ld1_acq((AO_INTEL_PTR_t)p));\r\n}\r\n#define AO_HAVE_char_load_acquire\r\n\r\nAO_INLINE void\r\nAO_char_store_release(volatile unsigned char *p, unsigned char val)\r\n{\r\n  __st1_rel((AO_INTEL_PTR_t)p, val);\r\n}\r\n#define AO_HAVE_char_store_release\r\n\r\nAO_INLINE unsigned short\r\nAO_short_load_acquire(const volatile unsigned short *p)\r\n{\r\n  /* A normal volatile load generates an ld.acq         */\r\n  return (__ld2_acq((AO_INTEL_PTR_t)p));\r\n}\r\n#define AO_HAVE_short_load_acquire\r\n\r\nAO_INLINE void\r\nAO_short_store_release(volatile unsigned short *p, unsigned short val)\r\n{\r\n  __st2_rel((AO_INTEL_PTR_t)p, val);\r\n}\r\n#define AO_HAVE_short_store_release\r\n\r\nAO_INLINE unsigned int\r\nAO_int_load_acquire(const volatile unsigned int *p)\r\n{\r\n  /* A normal volatile load generates an ld.acq         */\r\n  return (__ld4_acq((AO_INTEL_PTR_t)p));\r\n}\r\n#define AO_HAVE_int_load_acquire\r\n\r\nAO_INLINE void\r\nAO_int_store_release(volatile unsigned int *p, unsigned int val)\r\n{\r\n  __st4_rel((AO_INTEL_PTR_t)p, val);\r\n}\r\n#define AO_HAVE_int_store_release\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __mf();\r\n}\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_acquire (volatile AO_t *p)\r\n{\r\n  return __fetchadd8_acq((unsigned __int64 *)p, 1);\r\n}\r\n#define AO_HAVE_fetch_and_add1_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_release (volatile AO_t *p)\r\n{\r\n  return __fetchadd8_rel((unsigned __int64 *)p, 1);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1_release\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_acquire (volatile AO_t *p)\r\n{\r\n  return __fetchadd8_acq((unsigned __int64 *)p, -1);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_acquire\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_release (volatile AO_t *p)\r\n{\r\n  return __fetchadd8_rel((unsigned __int64 *)p, -1);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_release\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_acquire(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  AO_t oldval;\r\n  oldval = _InterlockedCompareExchange64_acq(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_release(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  AO_t oldval;\r\n  oldval = _InterlockedCompareExchange64_rel(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_char_compare_and_swap_acquire(volatile unsigned char *addr,\r\n                                 unsigned char old, unsigned char new_val)\r\n{\r\n  unsigned char oldval;\r\n  oldval = _InterlockedCompareExchange8_acq(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_char_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_char_compare_and_swap_release(volatile unsigned char *addr,\r\n                            unsigned char old, unsigned char new_val)\r\n{\r\n  unsigned char oldval;\r\n  oldval = _InterlockedCompareExchange8_rel(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_char_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_short_compare_and_swap_acquire(volatile unsigned short *addr,\r\n                                 unsigned short old, unsigned short new_val)\r\n{\r\n  unsigned short oldval;\r\n  oldval = _InterlockedCompareExchange16_acq(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_short_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_short_compare_and_swap_release(volatile unsigned short *addr,\r\n                            unsigned short old, unsigned short new_val)\r\n{\r\n  unsigned short oldval;\r\n  oldval = _InterlockedCompareExchange16_rel(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_short_compare_and_swap_release\r\n\r\nAO_INLINE int\r\nAO_int_compare_and_swap_acquire(volatile unsigned int *addr,\r\n                                 unsigned int old, unsigned int new_val)\r\n{\r\n  unsigned int oldval;\r\n  oldval = _InterlockedCompareExchange_acq(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_int_compare_and_swap_acquire\r\n\r\nAO_INLINE int\r\nAO_int_compare_and_swap_release(volatile unsigned int *addr,\r\n                            unsigned int old, unsigned int new_val)\r\n{\r\n  unsigned int oldval;\r\n  oldval = _InterlockedCompareExchange_rel(addr, new_val, old);\r\n  return (oldval == old);\r\n}\r\n\r\n#define AO_HAVE_int_compare_and_swap_release\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/int_acquire_release_volatile.h",
    "content": "/*\r\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * This file adds definitions appropriate for environments in which an unsigned\r\n * int volatile load has acquire semantics, and an unsigned short volatile\r\n * store has release semantics.  This is true with the standard Itanium ABI.\r\n */\r\n#if !defined(AO_GCC_BARRIER)\r\n#  if defined(__GNUC__)\r\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\r\n#  else\r\n#    define AO_GCC_BARRIER()\r\n#  endif\r\n#endif\r\n\r\nAO_INLINE unsigned int\r\nAO_int_load_acquire(const volatile unsigned int *p)\r\n{\r\n  unsigned int result = *p;\r\n  /* A normal volatile load generates an ld.acq         */\r\n  AO_GCC_BARRIER();\r\n  return result;\r\n}\r\n#define AO_HAVE_int_load_acquire\r\n\r\nAO_INLINE void\r\nAO_int_store_release(volatile unsigned int *p, unsigned int val)\r\n{\r\n  AO_GCC_BARRIER();\r\n  /* A normal volatile store generates an st.rel        */\r\n  *p = val;\r\n}\r\n#define AO_HAVE_int_store_release\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/int_aligned_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of unsigned int are\r\n * atomic for all legal alignments.\r\n */\r\n\r\nAO_INLINE unsigned int\r\nAO_int_load(const volatile unsigned int *addr)\r\n{\r\n  assert(((size_t)addr & (sizeof(unsigned int) - 1)) == 0);\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(unsigned int *)addr);\r\n}\r\n\r\n#define AO_HAVE_int_load\r\n\r\nAO_INLINE void\r\nAO_int_store(volatile unsigned int *addr, unsigned int new_val)\r\n{\r\n  assert(((size_t)addr & (sizeof(unsigned int) - 1)) == 0);\r\n  (*(unsigned int *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_int_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/int_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of unsigned int are\r\n * atomic for all legal alignments.\r\n */\r\n\r\nAO_INLINE unsigned int\r\nAO_int_load(const volatile unsigned int *addr)\r\n{\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(const unsigned int *)addr);\r\n}\r\n\r\n#define AO_HAVE_int_load\r\n\r\nAO_INLINE void\r\nAO_int_store(volatile unsigned int *addr, unsigned int new_val)\r\n{\r\n  (*(unsigned int *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_int_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/msftc/arm.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n#include \"../read_ordered.h\"\r\n\r\n#ifndef AO_ASSUME_WINDOWS98\r\n  /* CAS is always available */\r\n# define AO_ASSUME_WINDOWS98\r\n#endif\r\n#include \"common32_defs.h\"\r\n/* FIXME: Do _InterlockedOps really have a full memory barrier?         */\r\n/* (MSDN WinCE docs say nothing about it.)                              */\r\n\r\n#if _M_ARM >= 6\r\n/* ARMv6 is the first architecture providing support for simple LL/SC.  */\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\n/* If only a single processor is used, we can define AO_UNIPROCESSOR    */\r\n/* and do not need to access CP15 for ensuring a DMB at all.            */\r\n#ifdef AO_UNIPROCESSOR\r\n  AO_INLINE void AO_nop_full(void) {}\r\n# define AO_HAVE_nop_full\r\n#else\r\n/* AO_nop_full() is emulated using AO_test_and_set_full().              */\r\n#endif\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n/* AO_test_and_set() is emulated using CAS.                             */\r\n\r\nAO_INLINE AO_t\r\nAO_load(const volatile AO_t *addr)\r\n{\r\n  /* Cast away the volatile in case it adds fence semantics */\r\n  return (*(const AO_t *)addr);\r\n}\r\n#define AO_HAVE_load\r\n\r\nAO_INLINE void\r\nAO_store_full(volatile AO_t *addr, AO_t value)\r\n{\r\n  /* Emulate atomic store using CAS.    */\r\n  AO_t old = AO_load(addr);\r\n  AO_t current;\r\n# ifdef AO_OLD_STYLE_INTERLOCKED_COMPARE_EXCHANGE\r\n    while ((current = (AO_t)_InterlockedCompareExchange(\r\n                                (PVOID AO_INTERLOCKED_VOLATILE *)addr,\r\n                                (PVOID)value, (PVOID)old)) != old)\r\n      old = current;\r\n# else\r\n    while ((current = (AO_t)_InterlockedCompareExchange(\r\n                                (LONG AO_INTERLOCKED_VOLATILE *)addr,\r\n                                (LONG)value, (LONG)old)) != old)\r\n      old = current;\r\n# endif\r\n}\r\n#define AO_HAVE_store_full\r\n\r\n/* FIXME: implement AO_compare_double_and_swap_double() */\r\n\r\n#else /* _M_ARM < 6 */\r\n\r\n/* Some slide set, if it has been red correctly, claims that Loads      */\r\n/* followed by either a Load or a Store are ordered, but nothing        */\r\n/* else is. It appears that SWP is the only simple memory barrier.      */\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n#include \"../test_and_set_t_is_ao_t.h\"\r\n/* AO_test_and_set_full() is emulated using CAS.                        */\r\n\r\n#endif /* _M_ARM < 6 */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/msftc/common32_defs.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/* This file contains AO primitives based on VC++ built-in intrinsic    */\r\n/* functions commonly available across 32-bit architectures.            */\r\n\r\n/* This file should be included from arch-specific header files.        */\r\n/* Define AO_USE_INTERLOCKED_INTRINSICS if _Interlocked primitives      */\r\n/* (used below) are available as intrinsic ones for a target arch       */\r\n/* (otherwise \"Interlocked\" functions family is used instead).          */\r\n/* Define AO_ASSUME_WINDOWS98 if CAS is available.                      */\r\n\r\n#include <windows.h>\r\n        /* Seems like over-kill, but that's what MSDN recommends.       */\r\n        /* And apparently winbase.h is not always self-contained.       */\r\n\r\n#if _MSC_VER < 1310 || !defined(AO_USE_INTERLOCKED_INTRINSICS)\r\n\r\n# define _InterlockedIncrement       InterlockedIncrement\r\n# define _InterlockedDecrement       InterlockedDecrement\r\n# define _InterlockedExchange        InterlockedExchange\r\n# define _InterlockedExchangeAdd     InterlockedExchangeAdd\r\n# define _InterlockedCompareExchange InterlockedCompareExchange\r\n\r\n# define AO_INTERLOCKED_VOLATILE /**/\r\n\r\n#else /* elif _MSC_VER >= 1310 */\r\n\r\n# if _MSC_VER >= 1400\r\n#   ifndef _WIN32_WCE\r\n#     include <intrin.h>\r\n#   endif\r\n\r\n#   pragma intrinsic (_ReadWriteBarrier)\r\n\r\n# else /* elif _MSC_VER < 1400 */\r\n#  ifdef __cplusplus\r\n     extern \"C\" {\r\n#  endif\r\n   LONG __cdecl _InterlockedIncrement(LONG volatile *);\r\n   LONG __cdecl _InterlockedDecrement(LONG volatile *);\r\n   LONG __cdecl _InterlockedExchangeAdd(LONG volatile *, LONG);\r\n   LONG __cdecl _InterlockedExchange(LONG volatile *, LONG);\r\n   LONG __cdecl _InterlockedCompareExchange(LONG volatile *,\r\n                                        LONG /* Exchange */, LONG /* Comp */);\r\n#  ifdef __cplusplus\r\n     }\r\n#  endif\r\n# endif /* _MSC_VER < 1400 */\r\n\r\n# pragma intrinsic (_InterlockedIncrement)\r\n# pragma intrinsic (_InterlockedDecrement)\r\n# pragma intrinsic (_InterlockedExchange)\r\n# pragma intrinsic (_InterlockedExchangeAdd)\r\n# pragma intrinsic (_InterlockedCompareExchange)\r\n\r\n# define AO_INTERLOCKED_VOLATILE volatile\r\n\r\n#endif /* _MSC_VER >= 1310 */\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full(volatile AO_t *p, AO_t incr)\r\n{\r\n  return _InterlockedExchangeAdd((LONG AO_INTERLOCKED_VOLATILE *)p,\r\n                                 (LONG)incr);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_full(volatile AO_t *p)\r\n{\r\n  return _InterlockedIncrement((LONG AO_INTERLOCKED_VOLATILE *)p) - 1;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_full(volatile AO_t *p)\r\n{\r\n  return _InterlockedDecrement((LONG AO_INTERLOCKED_VOLATILE *)p) + 1;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_full\r\n\r\n#ifdef AO_ASSUME_WINDOWS98\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\r\n{\r\n# ifdef AO_OLD_STYLE_INTERLOCKED_COMPARE_EXCHANGE\r\n    return _InterlockedCompareExchange((PVOID AO_INTERLOCKED_VOLATILE *)addr,\r\n                                       (PVOID)new_val, (PVOID)old)\r\n           == (PVOID)old;\r\n# else\r\n    return _InterlockedCompareExchange((LONG AO_INTERLOCKED_VOLATILE *)addr,\r\n                                       (LONG)new_val, (LONG)old)\r\n           == (LONG)old;\r\n# endif\r\n}\r\n\r\n# define AO_HAVE_compare_and_swap_full\r\n#endif /* AO_ASSUME_WINDOWS98 */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/msftc/x86.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/* If AO_ASSUME_WINDOWS98 is defined, we assume Windows 98 or newer.    */\r\n/* If AO_ASSUME_VISTA is defined, we assume Windows Server 2003, Vista  */\r\n/* or later.                                                            */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Real X86 implementations, except for some old WinChips, appear       */\r\n/* to enforce ordering between memory operations, EXCEPT that a later   */\r\n/* read can pass earlier writes, presumably due to the visible          */\r\n/* presence of store buffers.                                           */\r\n/* We ignore both the WinChips, and the fact that the official specs    */\r\n/* seem to be much weaker (and arguably too weak to be usable).         */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#ifndef AO_USE_INTERLOCKED_INTRINSICS\r\n  /* _Interlocked primitives (Inc, Dec, Xchg, Add) are always available */\r\n# define AO_USE_INTERLOCKED_INTRINSICS\r\n#endif\r\n#include \"common32_defs.h\"\r\n\r\n/* As far as we can tell, the lfence and sfence instructions are not    */\r\n/* currently needed or useful for cached memory accesses.               */\r\n\r\n/* Unfortunately mfence doesn't exist everywhere.               */\r\n/* IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128) is         */\r\n/* probably a conservative test for it?                         */\r\n\r\n#if defined(AO_USE_PENTIUM4_INSTRS)\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm { mfence }\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n#else\r\n\r\n/* We could use the cpuid instruction.  But that seems to be slower     */\r\n/* than the default implementation based on test_and_set_full.  Thus    */\r\n/* we omit that bit of misinformation here.                             */\r\n\r\n#endif\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n    __asm\r\n    {\r\n        mov     eax,0xff                ; /* AO_TS_SET */\r\n        mov     ebx,addr                ;\r\n        xchg    byte ptr [ebx],al       ;\r\n    }\r\n    /* Ignore possible \"missing return value\" warning here. */\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n#ifdef _WIN64\r\n#  error wrong architecture\r\n#endif\r\n\r\n#ifdef AO_ASSUME_VISTA\r\n/* NEC LE-IT: whenever we run on a pentium class machine we have that\r\n * certain function */\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n#pragma intrinsic (_InterlockedCompareExchange64)\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n    __int64 oldv = (__int64)old_val1 | ((__int64)old_val2 << 32);\r\n    __int64 newv = (__int64)new_val1 | ((__int64)new_val2 << 32);\r\n    return _InterlockedCompareExchange64((__int64 volatile *)addr,\r\n                                       newv, oldv) == oldv;\r\n}\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n\r\n#ifdef __cplusplus\r\nAO_INLINE int\r\nAO_double_compare_and_swap_full(volatile AO_double_t *addr,\r\n                                AO_double_t old_val, AO_double_t new_val)\r\n{\r\n    return _InterlockedCompareExchange64((__int64 volatile *)addr,\r\n                new_val.AO_whole, old_val.AO_whole) == old_val.AO_whole;\r\n}\r\n#define AO_HAVE_double_compare_and_swap_full\r\n#endif /* __cplusplus */\r\n#endif /* AO_ASSUME_VISTA */\r\n\r\n#include \"../ao_t_is_int.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/msftc/x86_64.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Real X86 implementations appear                                      */\r\n/* to enforce ordering between memory operations, EXCEPT that a later   */\r\n/* read can pass earlier writes, presumably due to the visible          */\r\n/* presence of store buffers.                                           */\r\n/* We ignore the fact that the official specs                           */\r\n/* seem to be much weaker (and arguably too weak to be usable).         */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n\r\n#ifdef AO_ASM_X64_AVAILABLE\r\n# include \"../test_and_set_t_is_char.h\"\r\n#else\r\n# include \"../test_and_set_t_is_ao_t.h\"\r\n#endif\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\n#include <windows.h>\r\n        /* Seems like over-kill, but that's what MSDN recommends.       */\r\n        /* And apparently winbase.h is not always self-contained.       */\r\n\r\n/* Assume _MSC_VER >= 1400 */\r\n#include <intrin.h>\r\n\r\n#pragma intrinsic (_ReadWriteBarrier)\r\n\r\n#pragma intrinsic (_InterlockedIncrement64)\r\n#pragma intrinsic (_InterlockedDecrement64)\r\n#pragma intrinsic (_InterlockedExchange64)\r\n#pragma intrinsic (_InterlockedExchangeAdd64)\r\n#pragma intrinsic (_InterlockedCompareExchange64)\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  return _InterlockedExchangeAdd64((LONGLONG volatile *)p, (LONGLONG)incr);\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add1_full (volatile AO_t *p)\r\n{\r\n  return _InterlockedIncrement64((LONGLONG volatile *)p) - 1;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add1_full\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_sub1_full (volatile AO_t *p)\r\n{\r\n  return _InterlockedDecrement64((LONGLONG volatile *)p) + 1;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_sub1_full\r\n\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr,\r\n                         AO_t old, AO_t new_val)\r\n{\r\n    return _InterlockedCompareExchange64((LONGLONG volatile *)addr,\r\n                                         (LONGLONG)new_val, (LONGLONG)old)\r\n           == (LONGLONG)old;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n/* As far as we can tell, the lfence and sfence instructions are not    */\r\n/* currently needed or useful for cached memory accesses.               */\r\n\r\n#ifdef AO_ASM_X64_AVAILABLE\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  /* Note: \"mfence\" (SSE2) is supported on all x86_64/amd64 chips.      */\r\n  __asm { mfence }\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n    __asm\r\n    {\r\n        mov     rax,AO_TS_SET           ;\r\n        mov     rbx,addr                ;\r\n        xchg    byte ptr [rbx],al       ;\r\n    }\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n#endif /* AO_ASM_X64_AVAILABLE */\r\n\r\n#ifdef AO_CMPXCHG16B_AVAILABLE\r\n\r\n/* AO_compare_double_and_swap_double_full needs implementation for Win64.\r\n * Also see ../gcc/x86_64.h for partial old Opteron workaround.\r\n */\r\n\r\n# if _MSC_VER >= 1500\r\n\r\n#pragma intrinsic (_InterlockedCompareExchange128)\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n   __int64 comparandResult[2];\r\n   comparandResult[0] = old_val1; /* low */\r\n   comparandResult[1] = old_val2; /* high */\r\n   return _InterlockedCompareExchange128((volatile __int64 *)addr,\r\n                new_val2 /* high */, new_val1 /* low */, comparandResult);\r\n}\r\n\r\n#   define AO_HAVE_compare_double_and_swap_double_full\r\n\r\n# elif defined(AO_ASM_X64_AVAILABLE)\r\n\r\n /* If there is no intrinsic _InterlockedCompareExchange128 then we\r\n  * need basically what's given below.\r\n  */\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n        __asm\r\n        {\r\n                mov     rdx,QWORD PTR [old_val2]        ;\r\n                mov     rax,QWORD PTR [old_val1]        ;\r\n                mov     rcx,QWORD PTR [new_val2]        ;\r\n                mov     rbx,QWORD PTR [new_val1]        ;\r\n                lock cmpxchg16b [addr]                  ;\r\n                setz    rax                             ;\r\n        }\r\n}\r\n\r\n#   define AO_HAVE_compare_double_and_swap_double_full\r\n\r\n# endif /* _MSC_VER >= 1500 || AO_ASM_X64_AVAILABLE */\r\n\r\n#endif /* AO_CMPXCHG16B_AVAILABLE */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/ordered.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * These are common definitions for architectures that provide processor\r\n * ordered memory operations.\r\n */\r\n\r\n#include \"ordered_except_wr.h\"\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  AO_compiler_barrier();\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/ordered_except_wr.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * These are common definitions for architectures that provide processor\r\n * ordered memory operations except that a later read may pass an\r\n * earlier write.  Real x86 implementations seem to be in this category,\r\n * except apparently for some IDT WinChips, which we ignore.\r\n */\r\n\r\n#include \"read_ordered.h\"\r\n\r\nAO_INLINE void\r\nAO_nop_write(void)\r\n{\r\n  AO_compiler_barrier();\r\n  /* sfence according to Intel docs.  Pentium 3 and up. */\r\n  /* Unnecessary for cached accesses?                   */\r\n}\r\n\r\n#define AO_HAVE_NOP_WRITE\r\n\r\n#if defined(AO_HAVE_store)\r\n\r\nAO_INLINE void\r\nAO_store_write(volatile AO_t *addr, AO_t val)\r\n{\r\n  AO_compiler_barrier();\r\n  AO_store(addr, val);\r\n}\r\n# define AO_HAVE_store_write\r\n\r\n# define AO_store_release(addr, val) AO_store_write(addr, val)\r\n# define AO_HAVE_store_release\r\n\r\n#endif /* AO_HAVE_store */\r\n\r\n#if defined(AO_HAVE_char_store)\r\n\r\nAO_INLINE void\r\nAO_char_store_write(volatile unsigned char *addr, unsigned char val)\r\n{\r\n  AO_compiler_barrier();\r\n  AO_char_store(addr, val);\r\n}\r\n# define AO_HAVE_char_store_write\r\n\r\n# define AO_char_store_release(addr, val) AO_char_store_write(addr, val)\r\n# define AO_HAVE_char_store_release\r\n\r\n#endif /* AO_HAVE_char_store */\r\n\r\n#if defined(AO_HAVE_short_store)\r\n\r\nAO_INLINE void\r\nAO_short_store_write(volatile unsigned short *addr, unsigned short val)\r\n{\r\n  AO_compiler_barrier();\r\n  AO_short_store(addr, val);\r\n}\r\n# define AO_HAVE_short_store_write\r\n\r\n# define AO_short_store_release(addr, val) AO_short_store_write(addr, val)\r\n# define AO_HAVE_short_store_release\r\n\r\n#endif /* AO_HAVE_short_store */\r\n\r\n#if defined(AO_HAVE_int_store)\r\n\r\nAO_INLINE void\r\nAO_int_store_write(volatile unsigned int *addr, unsigned int val)\r\n{\r\n  AO_compiler_barrier();\r\n  AO_int_store(addr, val);\r\n}\r\n# define AO_HAVE_int_store_write\r\n\r\n# define AO_int_store_release(addr, val) AO_int_store_write(addr, val)\r\n# define AO_HAVE_int_store_release\r\n\r\n#endif /* AO_HAVE_int_store */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/read_ordered.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * These are common definitions for architectures that provide processor\r\n * ordered memory operations except that a later read may pass an\r\n * earlier write.  Real x86 implementations seem to be in this category,\r\n * except apparently for some IDT WinChips, which we ignore.\r\n */\r\n\r\nAO_INLINE void\r\nAO_nop_read(void)\r\n{\r\n  AO_compiler_barrier();\r\n}\r\n\r\n#define AO_HAVE_NOP_READ\r\n\r\n#ifdef AO_HAVE_load\r\n\r\nAO_INLINE AO_t\r\nAO_load_read(const volatile AO_t *addr)\r\n{\r\n  AO_t result = AO_load(addr);\r\n  AO_compiler_barrier();\r\n  return result;\r\n}\r\n#define AO_HAVE_load_read\r\n\r\n#define AO_load_acquire(addr) AO_load_read(addr)\r\n#define AO_HAVE_load_acquire\r\n\r\n#endif /* AO_HAVE_load */\r\n\r\n#ifdef AO_HAVE_char_load\r\n\r\nAO_INLINE AO_t\r\nAO_char_load_read(const volatile unsigned char *addr)\r\n{\r\n  AO_t result = AO_char_load(addr);\r\n  AO_compiler_barrier();\r\n  return result;\r\n}\r\n#define AO_HAVE_char_load_read\r\n\r\n#define AO_char_load_acquire(addr) AO_char_load_read(addr)\r\n#define AO_HAVE_char_load_acquire\r\n\r\n#endif /* AO_HAVE_char_load */\r\n\r\n#ifdef AO_HAVE_short_load\r\n\r\nAO_INLINE AO_t\r\nAO_short_load_read(const volatile unsigned short *addr)\r\n{\r\n  AO_t result = AO_short_load(addr);\r\n  AO_compiler_barrier();\r\n  return result;\r\n}\r\n#define AO_HAVE_short_load_read\r\n\r\n#define AO_short_load_acquire(addr) AO_short_load_read(addr)\r\n#define AO_HAVE_short_load_acquire\r\n\r\n#endif /* AO_HAVE_short_load */\r\n\r\n#ifdef AO_HAVE_int_load\r\n\r\nAO_INLINE AO_t\r\nAO_int_load_read(const volatile unsigned int *addr)\r\n{\r\n  AO_t result = AO_int_load(addr);\r\n  AO_compiler_barrier();\r\n  return result;\r\n}\r\n#define AO_HAVE_int_load_read\r\n\r\n#define AO_int_load_acquire(addr) AO_int_load_read(addr)\r\n#define AO_HAVE_int_load_acquire\r\n\r\n#endif /* AO_HAVE_int_load */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/short_acquire_release_volatile.h",
    "content": "/*\r\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * This file adds definitions appropriate for environments in which an unsigned short\r\n * volatile load has acquire semantics, and an unsigned short volatile store has release\r\n * semantics.  This is true with the standard Itanium ABI.\r\n */\r\n#if !defined(AO_GCC_BARRIER)\r\n#  if defined(__GNUC__)\r\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\r\n#  else\r\n#    define AO_GCC_BARRIER()\r\n#  endif\r\n#endif\r\n\r\nAO_INLINE unsigned short\r\nAO_short_load_acquire(const volatile unsigned short *p)\r\n{\r\n  unsigned short result = *p;\r\n  /* A normal volatile load generates an ld.acq         */\r\n  AO_GCC_BARRIER();\r\n  return result;\r\n}\r\n#define AO_HAVE_short_load_acquire\r\n\r\nAO_INLINE void\r\nAO_short_store_release(volatile unsigned short *p, unsigned short val)\r\n{\r\n  AO_GCC_BARRIER();\r\n  /* A normal volatile store generates an st.rel        */\r\n  *p = val;\r\n}\r\n#define AO_HAVE_short_store_release\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/short_aligned_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of unsigned short\r\n * are atomic for all legal alignments.\r\n */\r\n\r\nAO_INLINE unsigned short\r\nAO_short_load(const volatile unsigned short *addr)\r\n{\r\n  assert(((size_t)addr & (sizeof(unsigned short) - 1)) == 0);\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(unsigned short *)addr);\r\n}\r\n\r\n#define AO_HAVE_short_load\r\n\r\nAO_INLINE void\r\nAO_short_store(volatile unsigned short *addr, unsigned short new_val)\r\n{\r\n  assert(((size_t)addr & (sizeof(unsigned short) - 1)) == 0);\r\n  (*(unsigned short *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_short_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/short_atomic_load_store.h",
    "content": "/*\r\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * Definitions for architectures on which loads and stores of unsigned short\r\n * are atomic for all legal alignments.\r\n */\r\n\r\nAO_INLINE unsigned short\r\nAO_short_load(const volatile unsigned short *addr)\r\n{\r\n  /* Cast away the volatile for architectures like IA64 where   */\r\n  /* volatile adds barrier semantics.                           */\r\n  return (*(const unsigned short *)addr);\r\n}\r\n\r\n#define AO_HAVE_short_load\r\n\r\nAO_INLINE void\r\nAO_short_store(volatile unsigned short *addr, unsigned short new_val)\r\n{\r\n  (*(unsigned short *)addr) = new_val;\r\n}\r\n\r\n#define AO_HAVE_short_store\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/standard_ao_double_t.h",
    "content": "/* NEC LE-IT: For 64Bit OS we extend the double type to hold two int64's\r\n*\r\n*  x86-64: __m128 serves as placeholder which also requires the compiler\r\n*          to align     it on 16 byte boundary (as required by cmpxchg16.\r\n* Similar things could be done for PowerPC 64bit using a VMX data type...       */\r\n\r\n#if (defined(__x86_64__) && defined(__GNUC__)) || defined(_WIN64)\r\n# include <xmmintrin.h>\r\n  typedef __m128 double_ptr_storage;\r\n#elif defined(_WIN32) && !defined(__GNUC__)\r\n  typedef unsigned __int64 double_ptr_storage;\r\n#else\r\n  typedef unsigned long long double_ptr_storage;\r\n#endif\r\n\r\n# define AO_HAVE_DOUBLE_PTR_STORAGE\r\n\r\ntypedef union {\r\n    double_ptr_storage AO_whole;\r\n    struct {AO_t AO_v1; AO_t AO_v2;} AO_parts;\r\n} AO_double_t;\r\n\r\n#define AO_HAVE_double_t\r\n#define AO_val1 AO_parts.AO_v1\r\n#define AO_val2 AO_parts.AO_v2\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/sunc/sparc.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n * \r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n * \r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n * \r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE. \r\n */\r\n\r\n#include \"../all_atomic_load_store.h\"\r\n\r\n/* Real SPARC code uses TSO:                            */\r\n#include \"../ordered_except_wr.h\"\r\n\r\n/* Test_and_set location is just a byte.\t\t*/\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\nextern AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr);\r\n/* Implemented in separate .S file, for now.\t*/\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/* FIXME: Like the gcc version, this needs to be extended for V8 \t*/\r\n/* and V9.\t\t\t\t\t\t\t\t*/\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/sunc/x86.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n * Some of the machine specific code was borrowed from our GC distribution.\r\n */\r\n\r\n/* The following really assume we have a 486 or better.                 */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Real X86 implementations, except for some old WinChips, appear       */\r\n/* to enforce ordering between memory operations, EXCEPT that a later   */\r\n/* read can pass earlier writes, presumably due to the visible          */\r\n/* presence of store buffers.                                           */\r\n/* We ignore both the WinChips, and the fact that the official specs    */\r\n/* seem to be much weaker (and arguably too weak to be usable).         */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\n#if defined(AO_USE_PENTIUM4_INSTRS)\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n#else\r\n\r\n/* We could use the cpuid instruction.  But that seems to be slower     */\r\n/* than the default implementation based on test_and_set_full.  Thus    */\r\n/* we omit that bit of misinformation here.                             */\r\n\r\n#endif\r\n\r\n/* As far as we can tell, the lfence and sfence instructions are not    */\r\n/* currently needed or useful for cached memory accesses.               */\r\n\r\n/* Really only works for 486 and later */\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE unsigned char\r\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\r\n{\r\n  unsigned char result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\r\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_char_fetch_and_add_full\r\n\r\nAO_INLINE unsigned short\r\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\r\n{\r\n  unsigned short result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_short_fetch_and_add_full\r\n\r\n/* Really only works for 486 and later */\r\nAO_INLINE void\r\nAO_or_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  __asm__ __volatile__ (\"lock; orl %1, %0\" :\r\n                        \"=m\" (*p) : \"r\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_or_full\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  AO_TS_t oldval;\r\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\r\n  __asm__ __volatile__(\"xchg %0, %1\"\r\n                : \"=q\"(oldval), \"=m\"(*addr)\r\n                : \"0\"(0xff) /* , \"m\"(*addr) */\r\n                : \"memory\");\r\n  return (AO_TS_VAL_t)oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr,\r\n                             AO_t old, AO_t new_val)\r\n{\r\n  char result;\r\n  __asm__ __volatile__(\"lock; cmpxchgl %2, %0; setz %1\"\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"r\" (new_val), \"a\"(old) : \"memory\");\r\n  return (int) result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n#if 0\r\n/* FIXME: not tested (and probably wrong). Besides,     */\r\n/* it tickles a bug in Sun C 5.10 (when optimizing).    */\r\n/* Returns nonzero if the comparison succeeded. */\r\n/* Really requires at least a Pentium.          */\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n  char result;\r\n#if __PIC__\r\n  /* If PIC is turned on, we can't use %ebx as it is reserved for the\r\n     GOT pointer.  We can save and restore %ebx because GCC won't be\r\n     using it for anything else (such as any of the m operands) */\r\n  __asm__ __volatile__(\"pushl %%ebx;\"   /* save ebx used for PIC GOT ptr */\r\n                       \"movl %6,%%ebx;\" /* move new_val2 to %ebx */\r\n                       \"lock; cmpxchg8b %0; setz %1;\"\r\n                       \"pop %%ebx;\"     /* restore %ebx */\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\r\n                         \"c\" (new_val2), \"m\" (new_val1) : \"memory\");\r\n#else\r\n  /* We can't just do the same thing in non-PIC mode, because GCC\r\n   * might be using %ebx as the memory operand.  We could have ifdef'd\r\n   * in a clobber, but there's no point doing the push/pop if we don't\r\n   * have to. */\r\n  __asm__ __volatile__(\"lock; cmpxchg8b %0; setz %1;\"\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : /* \"m\"(*addr), */ \"d\" (old_val2), \"a\" (old_val1),\r\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\r\n#endif\r\n  return (int) result;\r\n}\r\n\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n#endif\r\n\r\n#include \"../ao_t_is_int.h\"\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/sunc/x86_64.h",
    "content": "/*\r\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\r\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\r\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\r\n *\r\n *\r\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\r\n *\r\n * Permission is hereby granted to use or copy this program\r\n * for any purpose,  provided the above notices are retained on all copies.\r\n * Permission to modify the code and to distribute modified code is granted,\r\n * provided the above notices are retained, and a notice that the code was\r\n * modified is included with the above copyright notice.\r\n *\r\n * Some of the machine specific code was borrowed from our GC distribution.\r\n */\r\n\r\n#include \"../all_aligned_atomic_load_store.h\"\r\n\r\n/* Real X86 implementations, appear                                     */\r\n/* to enforce ordering between memory operations, EXCEPT that a later   */\r\n/* read can pass earlier writes, presumably due to the visible          */\r\n/* presence of store buffers.                                           */\r\n/* We ignore the fact that the official specs                           */\r\n/* seem to be much weaker (and arguably too weak to be usable).         */\r\n\r\n#include \"../ordered_except_wr.h\"\r\n\r\n#include \"../test_and_set_t_is_char.h\"\r\n\r\n#include \"../standard_ao_double_t.h\"\r\n\r\nAO_INLINE void\r\nAO_nop_full(void)\r\n{\r\n  /* Note: \"mfence\" (SSE2) is supported on all x86_64/amd64 chips.      */\r\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_nop_full\r\n\r\n/* As far as we can tell, the lfence and sfence instructions are not    */\r\n/* currently needed or useful for cached memory accesses.               */\r\n\r\nAO_INLINE AO_t\r\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  AO_t result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddq %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_fetch_and_add_full\r\n\r\nAO_INLINE unsigned char\r\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\r\n{\r\n  unsigned char result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\r\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_char_fetch_and_add_full\r\n\r\nAO_INLINE unsigned short\r\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\r\n{\r\n  unsigned short result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_short_fetch_and_add_full\r\n\r\nAO_INLINE unsigned int\r\nAO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)\r\n{\r\n  unsigned int result;\r\n\r\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\r\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n  return result;\r\n}\r\n\r\n#define AO_HAVE_int_fetch_and_add_full\r\n\r\nAO_INLINE void\r\nAO_or_full (volatile AO_t *p, AO_t incr)\r\n{\r\n  __asm__ __volatile__ (\"lock; orq %1, %0\" :\r\n                        \"=m\" (*p) : \"r\" (incr) /* , \"m\" (*p) */\r\n                        : \"memory\");\r\n}\r\n\r\n#define AO_HAVE_or_full\r\n\r\nAO_INLINE AO_TS_VAL_t\r\nAO_test_and_set_full(volatile AO_TS_t *addr)\r\n{\r\n  AO_TS_t oldval;\r\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\r\n  __asm__ __volatile__(\"xchg %0, %1\"\r\n                : \"=q\"(oldval), \"=m\"(*addr)\r\n                : \"0\"(0xff) /* , \"m\"(*addr) */\r\n                : \"memory\");\r\n  return (AO_TS_VAL_t)oldval;\r\n}\r\n\r\n#define AO_HAVE_test_and_set_full\r\n\r\n/* Returns nonzero if the comparison succeeded. */\r\nAO_INLINE int\r\nAO_compare_and_swap_full(volatile AO_t *addr,\r\n                         AO_t old, AO_t new_val)\r\n{\r\n  char result;\r\n  __asm__ __volatile__(\"lock; cmpxchgq %2, %0; setz %1\"\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"r\" (new_val), \"a\"(old) : \"memory\");\r\n  return (int) result;\r\n}\r\n\r\n#define AO_HAVE_compare_and_swap_full\r\n\r\n#ifdef AO_CMPXCHG16B_AVAILABLE\r\n/* NEC LE-IT: older AMD Opterons are missing this instruction.\r\n * On these machines SIGILL will be thrown.\r\n * Define AO_WEAK_DOUBLE_CAS_EMULATION to have an emulated\r\n * (lock based) version available */\r\n/* HB: Changed this to not define either by default.  There are\r\n * enough machines and tool chains around on which cmpxchg16b\r\n * doesn't work.  And the emulation is unsafe by our usual rules.\r\n * Hoewever both are clearly useful in certain cases.\r\n */\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n  char result;\r\n  __asm__ __volatile__(\"lock; cmpxchg16b %0; setz %1\"\r\n                       : \"=m\"(*addr), \"=a\"(result)\r\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\r\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\r\n  return (int) result;\r\n}\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n#else\r\n/* this one provides spinlock based emulation of CAS implemented in     */\r\n/* atomic_ops.c.  We probably do not want to do this here, since it is  */\r\n/* not atomic with respect to other kinds of updates of *addr.  On the  */\r\n/* other hand, this may be a useful facility on occasion.               */\r\n#ifdef AO_WEAK_DOUBLE_CAS_EMULATION\r\nint AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,\r\n                                                AO_t old_val1, AO_t old_val2,\r\n                                                AO_t new_val1, AO_t new_val2);\r\n\r\nAO_INLINE int\r\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\r\n                                       AO_t old_val1, AO_t old_val2,\r\n                                       AO_t new_val1, AO_t new_val2)\r\n{\r\n        return AO_compare_double_and_swap_double_emulation(addr,\r\n                                                           old_val1, old_val2,\r\n                                                           new_val1, new_val2);\r\n}\r\n#define AO_HAVE_compare_double_and_swap_double_full\r\n#endif /* AO_WEAK_DOUBLE_CAS_EMULATION */\r\n#endif /* AO_CMPXCHG16B_AVAILABLE */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/test_and_set_t_is_ao_t.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n/*\r\n * These are common definitions for architectures on which test_and_set\r\n * operates on pointer-sized quantities, the \"clear\" value contains\r\n * all zeroes, and the \"set\" value contains only one lowest bit set.\r\n * This can be used if test_and_set is synthesized from compare_and_swap.\r\n */\r\ntypedef enum {AO_TS_clear = 0, AO_TS_set = 1} AO_TS_val;\r\n#define AO_TS_VAL_t AO_TS_val\r\n#define AO_TS_CLEAR AO_TS_clear\r\n#define AO_TS_SET AO_TS_set\r\n\r\n#define AO_TS_t AO_t\r\n\r\n#define AO_AO_TS_T 1\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops/sysdeps/test_and_set_t_is_char.h",
    "content": "/*\r\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\r\n * \r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n * \r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n * \r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE. \r\n */ \r\n\r\n/*\r\n * These are common definitions for architectures on which test_and_set\r\n * operates on byte sized quantities, the \"clear\" value contains\r\n * all zeroes, and the \"set\" value contains all ones.\r\n */\r\n\r\n#define AO_TS_t unsigned char\r\ntypedef enum {AO_BYTE_TS_clear = 0, AO_BYTE_TS_set = 0xff} AO_BYTE_TS_val;\r\n#define AO_TS_VAL_t AO_BYTE_TS_val\r\n#define AO_TS_CLEAR AO_BYTE_TS_clear\r\n#define AO_TS_SET AO_BYTE_TS_set\r\n\r\n#define AO_CHAR_TS_T 1\r\n\r\n\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/atomic_ops/atomic_ops.h",
    "content": "/*\r\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n\r\n#ifndef ATOMIC_OPS_H\r\n\r\n#define ATOMIC_OPS_H\r\n\r\n#include <assert.h>\r\n#include <stddef.h>\r\n\r\n/* We define various atomic operations on memory in a           */\r\n/* machine-specific way.  Unfortunately, this is complicated    */\r\n/* by the fact that these may or may not be combined with       */\r\n/* various memory barriers.  Thus the actual operations we      */\r\n/* define have the form AO_<atomic-op>_<barrier>, for all       */\r\n/* plausible combinations of <atomic-op> and <barrier>.         */\r\n/* This of course results in a mild combinatorial explosion.    */\r\n/* To deal with it, we try to generate derived                  */\r\n/* definitions for as many of the combinations as we can, as    */\r\n/* automatically as possible.                                   */\r\n/*                                                              */\r\n/* Our assumption throughout is that the programmer will        */\r\n/* specify the least demanding operation and memory barrier     */\r\n/* that will guarantee correctness for the implementation.      */\r\n/* Our job is to find the least expensive way to implement it   */\r\n/* on the applicable hardware.  In many cases that will         */\r\n/* involve, for example, a stronger memory barrier, or a        */\r\n/* combination of hardware primitives.                          */\r\n/*                                                              */\r\n/* Conventions:                                                 */\r\n/* \"plain\" atomic operations are not guaranteed to include      */\r\n/* a barrier.  The suffix in the name specifies the barrier     */\r\n/* type.  Suffixes are:                                         */\r\n/* _release: Earlier operations may not be delayed past it.     */\r\n/* _acquire: Later operations may not move ahead of it.         */\r\n/* _read: Subsequent reads must follow this operation and       */\r\n/*        preceding reads.                                      */\r\n/* _write: Earlier writes precede both this operation and       */\r\n/*        later writes.                                         */\r\n/* _full: Ordered with respect to both earlier and later memops.*/\r\n/* _release_write: Ordered with respect to earlier writes.      */\r\n/* _acquire_read: Ordered with respect to later reads.          */\r\n/*                                                              */\r\n/* Currently we try to define the following atomic memory       */\r\n/* operations, in combination with the above barriers:          */\r\n/* AO_nop                                                       */\r\n/* AO_load                                                      */\r\n/* AO_store                                                     */\r\n/* AO_test_and_set (binary)                                     */\r\n/* AO_fetch_and_add                                             */\r\n/* AO_fetch_and_add1                                            */\r\n/* AO_fetch_and_sub1                                            */\r\n/* AO_or                                                        */\r\n/* AO_compare_and_swap                                          */\r\n/*                                                              */\r\n/* Note that atomicity guarantees are valid only if both        */\r\n/* readers and writers use AO_ operations to access the         */\r\n/* shared value, while ordering constraints are intended to     */\r\n/* apply all memory operations.  If a location can potentially  */\r\n/* be accessed simultaneously from multiple threads, and one of */\r\n/* those accesses may be a write access, then all such          */\r\n/* accesses to that location should be through AO_ primitives.  */\r\n/* However if AO_ operations enforce sufficient ordering to     */\r\n/* ensure that a location x cannot be accessed concurrently,    */\r\n/* or can only be read concurrently, then x can be accessed     */\r\n/* via ordinary references and assignments.                     */\r\n/*                                                              */\r\n/* Compare_and_exchange takes an address and an expected old    */\r\n/* value and a new value, and returns an int.  Nonzero          */\r\n/* indicates that it succeeded.                                 */\r\n/* Test_and_set takes an address, atomically replaces it by     */\r\n/* AO_TS_SET, and returns the prior value.                      */\r\n/* An AO_TS_t location can be reset with the                    */\r\n/* AO_CLEAR macro, which normally uses AO_store_release.        */\r\n/* AO_fetch_and_add takes an address and an AO_t increment      */\r\n/* value.  The AO_fetch_and_add1 and AO_fetch_and_sub1 variants */\r\n/* are provided, since they allow faster implementations on     */\r\n/* some hardware. AO_or atomically ors an AO_t value into a     */\r\n/* memory location, but does not provide access to the original.*/\r\n/*                                                              */\r\n/* We expect this list to grow slowly over time.                */\r\n/*                                                              */\r\n/* Note that AO_nop_full is a full memory barrier.              */\r\n/*                                                              */\r\n/* Note that if some data is initialized with                   */\r\n/*      data.x = ...; data.y = ...; ...                         */\r\n/*      AO_store_release_write(&data_is_initialized, 1)         */\r\n/* then data is guaranteed to be initialized after the test     */\r\n/*      if (AO_load_release_read(&data_is_initialized)) ...     */\r\n/* succeeds.  Furthermore, this should generate near-optimal    */\r\n/* code on all common platforms.                                */\r\n/*                                                              */\r\n/* All operations operate on unsigned AO_t, which               */\r\n/* is the natural word size, and usually unsigned long.         */\r\n/* It is possible to check whether a particular operation op    */\r\n/* is available on a particular platform by checking whether    */\r\n/* AO_HAVE_op is defined.  We make heavy use of these macros    */\r\n/* internally.                                                  */\r\n\r\n/* The rest of this file basically has three sections:          */\r\n/*                                                              */\r\n/* Some utility and default definitions.                        */\r\n/*                                                              */\r\n/* The architecture dependent section:                          */\r\n/* This defines atomic operations that have direct hardware     */\r\n/* support on a particular platform, mostly by including the    */\r\n/* appropriate compiler- and hardware-dependent file.           */\r\n/*                                                              */\r\n/* The synthesis section:                                       */\r\n/* This tries to define other atomic operations in terms of     */\r\n/* those that are explicitly available on the platform.         */\r\n/* This section is hardware independent.                        */\r\n/* We make no attempt to synthesize operations in ways that     */\r\n/* effectively introduce locks, except for the debugging/demo   */\r\n/* pthread-based implementation at the beginning.  A more       */\r\n/* realistic implementation that falls back to locks could be   */\r\n/* added as a higher layer.  But that would sacrifice           */\r\n/* usability from signal handlers.                              */\r\n/* The synthesis section is implemented almost entirely in      */\r\n/* atomic_ops_generalize.h.                                     */\r\n\r\n/* Some common defaults.  Overridden for some architectures.    */\r\n#define AO_t size_t\r\n\r\n/* The test_and_set primitive returns an AO_TS_VAL_t value.     */\r\n/* AO_TS_t is the type of an in-memory test-and-set location.   */\r\n\r\n#define AO_TS_INITIALIZER (AO_t)AO_TS_CLEAR\r\n\r\n/* Platform-dependent stuff:                                    */\r\n#if defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER) \\\r\n        || defined(__DMC__) || defined(__WATCOMC__)\r\n# define AO_INLINE static __inline\r\n#elif defined(__sun)\r\n# define AO_INLINE static inline\r\n#else\r\n# define AO_INLINE static\r\n#endif\r\n\r\n#if defined(__GNUC__) && !defined(__INTEL_COMPILER)\r\n# define AO_compiler_barrier() __asm__ __volatile__(\"\" : : : \"memory\")\r\n#elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \\\r\n        || defined(__WATCOMC__)\r\n# if defined(_AMD64_) || defined(_M_X64) || _MSC_VER >= 1400\r\n#   if defined(_WIN32_WCE)\r\n/* #     include <cmnintrin.h> */\r\n#   elif defined(_MSC_VER)\r\n#     include <intrin.h>\r\n#   endif\r\n#   pragma intrinsic(_ReadWriteBarrier)\r\n#   define AO_compiler_barrier() _ReadWriteBarrier()\r\n        /* We assume this does not generate a fence instruction.        */\r\n        /* The documentation is a bit unclear.                          */\r\n# else\r\n#   define AO_compiler_barrier() __asm { }\r\n        /* The preceding implementation may be preferable here too.     */\r\n        /* But the documentation warns about VC++ 2003 and earlier.     */\r\n# endif\r\n#elif defined(__INTEL_COMPILER)\r\n# define AO_compiler_barrier() __memory_barrier() /* Too strong? IA64-only? */\r\n#elif defined(_HPUX_SOURCE)\r\n# if defined(__ia64)\r\n#   include <machine/sys/inline.h>\r\n#   define AO_compiler_barrier() _Asm_sched_fence()\r\n# else\r\n    /* FIXME - We dont know how to do this.  This is a guess.   */\r\n    /* And probably a bad one.                                  */\r\n    static volatile int AO_barrier_dummy;\r\n#   define AO_compiler_barrier() AO_barrier_dummy = AO_barrier_dummy\r\n# endif\r\n#else\r\n  /* We conjecture that the following usually gives us the right        */\r\n  /* semantics or an error.                                             */\r\n# define AO_compiler_barrier() asm(\"\")\r\n#endif\r\n\r\n#if defined(AO_USE_PTHREAD_DEFS)\r\n# include \"atomic_ops/sysdeps/generic_pthread.h\"\r\n#endif /* AO_USE_PTHREAD_DEFS */\r\n\r\n#if (defined(__CC_ARM) || defined(__ARMCC__)) && !defined(__GNUC__) \\\r\n    && !defined(AO_USE_PTHREAD_DEFS)\r\n# include \"atomic_ops/sysdeps/armcc/arm_v6.h\"\r\n# define AO_GENERALIZE_TWICE\r\n#endif\r\n\r\n#if defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS) \\\r\n    && !defined(__INTEL_COMPILER)\r\n# if defined(__i386__)\r\n    /* We don't define AO_USE_SYNC_CAS_BUILTIN for x86 here because     */\r\n    /* it might require specifying additional options (like -march)     */\r\n    /* or additional link libraries (if -march is not specified).       */\r\n#   include \"atomic_ops/sysdeps/gcc/x86.h\"\r\n# endif /* __i386__ */\r\n# if defined(__x86_64__)\r\n#   if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)\r\n      /* It is safe to use __sync CAS built-in on this architecture.    */\r\n#     define AO_USE_SYNC_CAS_BUILTIN\r\n#   endif\r\n#   include \"atomic_ops/sysdeps/gcc/x86_64.h\"\r\n# endif /* __x86_64__ */\r\n# if defined(__ia64__)\r\n#   include \"atomic_ops/sysdeps/gcc/ia64.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# endif /* __ia64__ */\r\n# if defined(__hppa__)\r\n#   include \"atomic_ops/sysdeps/gcc/hppa.h\"\r\n#   define AO_CAN_EMUL_CAS\r\n# endif /* __hppa__ */\r\n# if defined(__alpha__)\r\n#   include \"atomic_ops/sysdeps/gcc/alpha.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# endif /* __alpha__ */\r\n# if defined(__s390__)\r\n#   include \"atomic_ops/sysdeps/gcc/s390.h\"\r\n# endif /* __s390__ */\r\n# if defined(__sparc__)\r\n#   include \"atomic_ops/sysdeps/gcc/sparc.h\"\r\n#   define AO_CAN_EMUL_CAS\r\n# endif /* __sparc__ */\r\n# if defined(__m68k__)\r\n#   include \"atomic_ops/sysdeps/gcc/m68k.h\"\r\n# endif /* __m68k__ */\r\n# if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \\\r\n     || defined(__powerpc64__) || defined(__ppc64__)\r\n#   include \"atomic_ops/sysdeps/gcc/powerpc.h\"\r\n# endif /* __powerpc__ */\r\n# if defined(__arm__) && !defined(AO_USE_PTHREAD_DEFS)\r\n#   include \"atomic_ops/sysdeps/gcc/arm.h\"\r\n#   define AO_CAN_EMUL_CAS\r\n# endif /* __arm__ */\r\n# if defined(__cris__) || defined(CRIS)\r\n#   include \"atomic_ops/sysdeps/gcc/cris.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# endif\r\n# if defined(__mips__)\r\n#   include \"atomic_ops/sysdeps/gcc/mips.h\"\r\n# endif /* __mips__ */\r\n# if defined(__sh__) || defined(SH4)\r\n#   include \"atomic_ops/sysdeps/gcc/sh.h\"\r\n#   define AO_CAN_EMUL_CAS\r\n# endif /* __sh__ */\r\n# if defined(__avr32__)\r\n#   include \"atomic_ops/sysdeps/gcc/avr32.h\"\r\n# endif\r\n#endif /* __GNUC__ && !AO_USE_PTHREAD_DEFS */\r\n\r\n#if (defined(__IBMC__) || defined(__IBMCPP__)) && !defined(__GNUC__) \\\r\n    && !defined(AO_USE_PTHREAD_DEFS)\r\n# if defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) \\\r\n     || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) \\\r\n     || defined(_ARCH_PWR)\r\n#   include \"atomic_ops/sysdeps/ibmc/powerpc.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# endif\r\n#endif\r\n\r\n#if defined(__INTEL_COMPILER) && !defined(AO_USE_PTHREAD_DEFS)\r\n# if defined(__ia64__)\r\n#   include \"atomic_ops/sysdeps/icc/ia64.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# endif\r\n# if defined(__GNUC__)\r\n    /* Intel Compiler in GCC compatible mode */\r\n#   if defined(__i386__)\r\n#     include \"atomic_ops/sysdeps/gcc/x86.h\"\r\n#   endif /* __i386__ */\r\n#   if defined(__x86_64__)\r\n#     if __INTEL_COMPILER > 1110\r\n#       define AO_USE_SYNC_CAS_BUILTIN\r\n#     endif\r\n#     include \"atomic_ops/sysdeps/gcc/x86_64.h\"\r\n#   endif /* __x86_64__ */\r\n# endif\r\n#endif\r\n\r\n#if defined(_HPUX_SOURCE) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)\r\n# if defined(__ia64)\r\n#   include \"atomic_ops/sysdeps/hpc/ia64.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# else\r\n#   include \"atomic_ops/sysdeps/hpc/hppa.h\"\r\n#   define AO_CAN_EMUL_CAS\r\n# endif\r\n#endif\r\n\r\n#if defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \\\r\n        || (defined(__WATCOMC__) && defined(__NT__))\r\n# if defined(_AMD64_) || defined(_M_X64)\r\n#   include \"atomic_ops/sysdeps/msftc/x86_64.h\"\r\n# elif defined(_M_IX86) || defined(x86)\r\n#   include \"atomic_ops/sysdeps/msftc/x86.h\"\r\n# elif defined(_M_ARM) || defined(ARM) || defined(_ARM_)\r\n#   include \"atomic_ops/sysdeps/msftc/arm.h\"\r\n#   define AO_GENERALIZE_TWICE\r\n# endif\r\n#endif\r\n\r\n#if defined(__sun) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)\r\n  /* Note: use -DAO_USE_PTHREAD_DEFS if Sun CC does not handle inline asm. */\r\n# if defined(__i386)\r\n#   include \"atomic_ops/sysdeps/sunc/x86.h\"\r\n# endif /* __i386 */\r\n# if defined(__x86_64) || defined(__amd64)\r\n#   include \"atomic_ops/sysdeps/sunc/x86_64.h\"\r\n# endif /* __x86_64 */\r\n#endif\r\n\r\n#if !defined(__GNUC__) && (defined(sparc) || defined(__sparc)) \\\r\n    && !defined(AO_USE_PTHREAD_DEFS)\r\n# include \"atomic_ops/sysdeps/sunc/sparc.h\"\r\n# define AO_CAN_EMUL_CAS\r\n#endif\r\n\r\n#if defined(AO_REQUIRE_CAS) && !defined(AO_HAVE_compare_and_swap) \\\r\n    && !defined(AO_HAVE_compare_and_swap_full) \\\r\n    && !defined(AO_HAVE_compare_and_swap_acquire)\r\n# if defined(AO_CAN_EMUL_CAS)\r\n#   include \"atomic_ops/sysdeps/emul_cas.h\"\r\n# else\r\n#  error Cannot implement AO_compare_and_swap_full on this architecture.\r\n# endif\r\n#endif /* AO_REQUIRE_CAS && !AO_HAVE_compare_and_swap ... */\r\n\r\n/* The most common way to clear a test-and-set location         */\r\n/* at the end of a critical section.                            */\r\n#if AO_AO_TS_T && !defined(AO_CLEAR)\r\n# define AO_CLEAR(addr) AO_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)\r\n#endif\r\n#if AO_CHAR_TS_T && !defined(AO_CLEAR)\r\n# define AO_CLEAR(addr) AO_char_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)\r\n#endif\r\n\r\n/* The generalization section.  */\r\n#if !defined(AO_GENERALIZE_TWICE) && defined(AO_CAN_EMUL_CAS) \\\r\n    && !defined(AO_HAVE_compare_and_swap_full)\r\n# define AO_GENERALIZE_TWICE\r\n#endif\r\n\r\n/* Theoretically we should repeatedly include atomic_ops_generalize.h.  */\r\n/* In fact, we observe that this converges after a small fixed number   */\r\n/* of iterations, usually one.                                          */\r\n#include \"atomic_ops/generalize.h\"\r\n#ifdef AO_GENERALIZE_TWICE\r\n# include \"atomic_ops/generalize.h\"\r\n#endif\r\n\r\n/* For compatibility with version 0.4 and earlier       */\r\n#define AO_TS_T AO_TS_t\r\n#define AO_T AO_t\r\n#define AO_TS_VAL AO_TS_VAL_t\r\n\r\n#endif /* ATOMIC_OPS_H */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/dcss/dcss_plus.h",
    "content": "/* \r\n * File:   dcss_plus.h\r\n * Author: Maya Arbel-Raviv\r\n *\r\n * Created on May 1, 2017, 10:42 AM\r\n */\r\n\r\n#ifndef DCSS_PLUS_H\r\n#define DCSS_PLUS_H\r\n\r\n#include <cstdarg>\r\n#include <csignal>\r\n#include <string.h>\r\n#include \"descriptors.h\"\r\n\r\n#define dcssptagptr_t uintptr_t\r\n#define dcsspptr_t dcsspdesc_t<PAYLOAD_T> *\r\n#define casword_t intptr_t\r\n\r\n#define DCSSP_STATE_UNDECIDED 0\r\n#define DCSSP_STATE_SUCCEEDED 4\r\n#define DCSSP_STATE_FAILED 8\r\n\r\n#define DCSSP_LEFTSHIFT 1\r\n\r\n#define DCSSP_IGNORED_RETVAL -1\r\n#define DCSSP_SUCCESS 0\r\n#define DCSSP_FAILED_ADDR1 1 \r\n#define DCSSP_FAILED_ADDR2 2\r\n\r\n#define MAX_PAYLOAD_PTRS 6\r\n\r\nstruct dcsspresult_t {\r\n    int status;\r\n    casword_t failed_val;\r\n};\r\n\r\ntemplate <typename PAYLOAD_T>\r\nclass dcsspdesc_t {\r\npublic:\r\n    volatile mutables_t mutables;\r\n    casword_t volatile * volatile addr1;\r\n    casword_t volatile old1;\r\n    casword_t volatile * volatile addr2;\r\n    casword_t volatile old2;\r\n    casword_t volatile new2;\r\n    PAYLOAD_T volatile payload1[MAX_PAYLOAD_PTRS+1];\r\n    PAYLOAD_T volatile payload2[MAX_PAYLOAD_PTRS+1];\r\n    const static int size = sizeof(mutables)+sizeof(addr1)+sizeof(old1)+sizeof(addr2)+sizeof(old2)+sizeof(new2)+sizeof(PAYLOAD_T)*(MAX_PAYLOAD_PTRS+1)+sizeof(PAYLOAD_T)*(MAX_PAYLOAD_PTRS+1);\r\n    char padding[PREFETCH_SIZE_BYTES+(((64<<10)-size%64)%64)]; // add padding to prevent false sharing\r\n} __attribute__ ((aligned(64)));\r\n\r\ntemplate <typename PAYLOAD_T>\r\nclass dcsspProvider {\r\n    /**\r\n     * Data definitions\r\n     */\r\nprivate:\r\n    // descriptor reduction algorithm\r\n    #define DCSSP_MUTABLES_OFFSET_STATE 0\r\n    #define DCSSP_MUTABLES_MASK_STATE 0xf\r\n    #define DCSSP_MUTABLES_NEW(mutables) \\\r\n        ((((mutables)&MASK_SEQ)+(1<<OFFSET_SEQ)) \\\r\n        | (DCSSP_STATE_UNDECIDED<<DCSSP_MUTABLES_OFFSET_STATE))\r\n    #include \"descriptors_impl2.h\"\r\n    char __padding_desc[PREFETCH_SIZE_BYTES];\r\n    dcsspdesc_t<PAYLOAD_T> dcsspDescriptors[LAST_TID+1] __attribute__ ((aligned(64)));\r\n    char __padding_desc3[PREFETCH_SIZE_BYTES];\r\n\r\npublic:\r\n#ifdef USE_DEBUGCOUNTERS\r\n    debugCounter * dcsspHelpCounter;\r\n#endif\r\n    const int NUM_PROCESSES;\r\n    \r\n    /**\r\n     * Function declarations\r\n     */\r\n    dcsspProvider(const int numProcesses);\r\n    ~dcsspProvider();\r\n    void initThread(const int tid);\r\n    void deinitThread(const int tid);\r\n    void writePtr(casword_t volatile * addr, casword_t val);        // use for addresses that might have been modified by DCSSP (ONLY GOOD FOR INITIALIZING, CANNOT DEAL WITH CONCURRENT DCSSP OPERATIONS.)\r\n    void writeVal(casword_t volatile * addr, casword_t val);        // use for addresses that might have been modified by DCSSP (ONLY GOOD FOR INITIALIZING, CANNOT DEAL WITH CONCURRENT DCSSP OPERATIONS.)\r\n    casword_t readPtr(const int tid, casword_t volatile * addr);    // use for addresses that might have been modified by DCSSP\r\n    casword_t readVal(const int tid, casword_t volatile * addr);    // use for addresses that might have been modified by DCSSP\r\n    inline dcsspresult_t dcsspPtr(const int tid, casword_t * addr1, casword_t old1, casword_t * addr2, casword_t old2, casword_t new2, PAYLOAD_T * const payload1, PAYLOAD_T * const payload2); // use when addr2 is a pointer, or another type that does not use its least significant bit\r\n    inline dcsspresult_t dcsspVal(const int tid, casword_t * addr1, casword_t old1, casword_t * addr2, casword_t old2, casword_t new2, PAYLOAD_T * const payload1, PAYLOAD_T * const payload2); // use when addr2 uses its least significant bit, but does not use its most significant but\r\n    void discardPayloads(const int tid);\r\n    void debugPrint();\r\n    \r\n    tagptr_t getDescriptorTagptr(const int otherTid);\r\n    dcsspptr_t getDescriptorPtr(tagptr_t tagptr);\r\n    bool getDescriptorSnapshot(tagptr_t tagptr, dcsspptr_t const dest);\r\n    void helpProcess(const int tid, const int otherTid);\r\nprivate:\r\n    casword_t dcsspRead(const int tid, casword_t volatile * addr);\r\n    inline dcsspresult_t dcsspHelp(const int tid, dcssptagptr_t tagptr, dcsspptr_t snapshot, bool helpingOther);\r\n    void dcsspHelpOther(const int tid, dcssptagptr_t tagptr);\r\n};\r\n\r\n#endif /* DCSS_PLUS_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/dcss/dcss_plus_impl.h",
    "content": "/* \r\n * File:   dcss_plus_impl.h\r\n * Author: Maya Arbel-Raviv\r\n *\r\n * Created on May 1, 2017, 10:52 AM\r\n */\r\n\r\n#ifndef DCSS_PLUS_IMPL_H\r\n#define DCSS_PLUS_IMPL_H\r\n\r\n#include \"dcss_plus.h\"\r\n#include <cassert>\r\n#include <stdint.h>\r\n#include <sstream>\r\nusing namespace std;\r\n\r\n#define BOOL_CAS __sync_bool_compare_and_swap\r\n#define VAL_CAS __sync_val_compare_and_swap\r\n\r\n#define DCSSP_TAGBIT 0x1\r\n\r\nstatic bool isDcssp(casword_t val) {\r\n    return (val & DCSSP_TAGBIT);\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ndcsspresult_t dcsspProvider<PAYLOAD_T>::dcsspHelp(const int tid, dcssptagptr_t tagptr, dcsspptr_t snapshot, bool helpingOther) {\r\n    // figure out what the state should be\r\n    casword_t state = DCSSP_STATE_FAILED;\r\n\r\n    SOFTWARE_BARRIER;\r\n    casword_t val1 = *(snapshot->addr1);\r\n    SOFTWARE_BARRIER;\r\n    \r\n    //DELAY_UP_TO(1000);\r\n    if (val1 == snapshot->old1) { // linearize here(?)\r\n        state = DCSSP_STATE_SUCCEEDED;\r\n    }\r\n    \r\n    // try to cas the state to the appropriate value\r\n    dcsspptr_t ptr = TAGPTR_UNPACK_PTR(dcsspDescriptors,tagptr);\r\n    casword_t retval;\r\n    bool failedBit;\r\n    MUTABLES_VAL_CAS_FIELD(failedBit, retval, ptr->mutables, snapshot->mutables, DCSSP_STATE_UNDECIDED, state, DCSSP_MUTABLES_MASK_STATE, DCSSP_MUTABLES_OFFSET_STATE); \r\n    if (failedBit) return {DCSSP_IGNORED_RETVAL,0};                             // failed to access the descriptor: we must be helping another process complete its operation, so we will NOT use this return value!\r\n    \r\n    // TODO: do we do the announcement here? what will be announced exactly? do we let the user provide a pointer/value to announce as an argument to dcssp? do we need to provide an operation to retrieve the current announcement for a given process?\r\n    \r\n    // finish the operation based on the descriptor's state\r\n    if ((retval == DCSSP_STATE_UNDECIDED && state == DCSSP_STATE_SUCCEEDED)     // if we changed the state to succeeded OR\r\n      || retval == DCSSP_STATE_SUCCEEDED) {                                     // if someone else changed the state to succeeded\r\n//        if (state == DCSSP_STATE_FAILED) DELAY_UP_TO(1000);\r\n        assert(helpingOther || ((snapshot->mutables & DCSSP_MUTABLES_MASK_STATE) >> DCSSP_MUTABLES_OFFSET_STATE) == DCSSP_STATE_SUCCEEDED);\r\n        BOOL_CAS(snapshot->addr2, (casword_t) tagptr, snapshot->new2); \r\n        return {DCSSP_SUCCESS,0};\r\n    } else {                                                                    // either we or someone else changed the state to failed\r\n        assert((retval == DCSSP_STATE_UNDECIDED && state == DCSSP_STATE_FAILED)\r\n                || retval == DCSSP_STATE_FAILED);\r\n        assert(helpingOther || ((snapshot->mutables & DCSSP_MUTABLES_MASK_STATE) >> DCSSP_MUTABLES_OFFSET_STATE) == DCSSP_STATE_FAILED);\r\n        BOOL_CAS(snapshot->addr2, (casword_t) tagptr, snapshot->old2);\r\n//        if (state == DCSSP_STATE_FAILED) DELAY_UP_TO(1000);\r\n        return {DCSSP_FAILED_ADDR1,val1};\r\n    }\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::dcsspHelpOther(const int tid, dcssptagptr_t tagptr) {\r\n    const int otherTid = TAGPTR_UNPACK_TID(tagptr);\r\n    assert(otherTid >= 0 && otherTid < NUM_PROCESSES);\r\n    dcsspdesc_t<PAYLOAD_T> newSnapshot;\r\n    const int sz = dcsspdesc_t<PAYLOAD_T>::size;\r\n    assert((((tagptr & MASK_SEQ) >> OFFSET_SEQ) & 1) == 1);\r\n    if (DESC_SNAPSHOT(dcsspdesc_t<PAYLOAD_T>, dcsspDescriptors, &newSnapshot, tagptr, sz)) {\r\n        dcsspHelp(tid, tagptr, &newSnapshot, true);\r\n    } else {\r\n        //TRACE COUTATOMICTID(\"helpOther unable to get snapshot of \"<<tagptrToString(tagptr)<<endl);\r\n    }\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ninline\r\ntagptr_t dcsspProvider<PAYLOAD_T>::getDescriptorTagptr(const int otherTid) {\r\n    dcsspptr_t ptr = &dcsspDescriptors[otherTid];\r\n    tagptr_t tagptr = TAGPTR_NEW(otherTid, ptr->mutables, DCSSP_TAGBIT);\r\n    if ((UNPACK_SEQ(tagptr) & 1) == 0) {\r\n        // descriptor is being initialized! essentially,\r\n        // we can think of there being NO ongoing operation,\r\n        // so we can imagine we return NULL = no descriptor.\r\n        return (tagptr_t) NULL;\r\n    }\r\n    return tagptr;\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ninline\r\ndcsspptr_t dcsspProvider<PAYLOAD_T>::getDescriptorPtr(tagptr_t tagptr) {\r\n    return TAGPTR_UNPACK_PTR(dcsspDescriptors, tagptr);\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ninline\r\nbool dcsspProvider<PAYLOAD_T>::getDescriptorSnapshot(tagptr_t tagptr, dcsspptr_t const dest) {\r\n    if (tagptr == (tagptr_t) NULL) return false;\r\n    return DESC_SNAPSHOT(dcsspdesc_t<PAYLOAD_T>, dcsspDescriptors, dest, tagptr, dcsspdesc_t<PAYLOAD_T>::size);\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ninline\r\nvoid dcsspProvider<PAYLOAD_T>::helpProcess(const int tid, const int otherTid) {\r\n    tagptr_t tagptr = getDescriptorTagptr(otherTid);\r\n    if (tagptr != (tagptr_t) NULL) dcsspHelpOther(tid, tagptr);\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::discardPayloads(const int tid) {\r\n    SOFTWARE_BARRIER;\r\n    dcssptagptr_t tagptr = getDescriptorTagptr(tid);\r\n    dcsspptr_t ptr = getDescriptorPtr(tagptr);\r\n    ptr->payload1[0] = NULL;\r\n    ptr->payload2[0] = NULL;\r\n    SOFTWARE_BARRIER;\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ndcsspresult_t dcsspProvider<PAYLOAD_T>::dcsspVal(const int tid, casword_t * addr1, casword_t old1, casword_t * addr2, casword_t old2, casword_t new2, PAYLOAD_T * const payload1, PAYLOAD_T * const payload2) {\r\n    return dcsspPtr(tid, addr1, old1, addr2, old2 << DCSSP_LEFTSHIFT , new2 << DCSSP_LEFTSHIFT, payload1, payload2);\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ndcsspresult_t dcsspProvider<PAYLOAD_T>::dcsspPtr(const int tid, casword_t * addr1, casword_t old1, casword_t * addr2, casword_t old2, casword_t new2, PAYLOAD_T * const payload1, PAYLOAD_T * const payload2) {\r\n    // create dcssp descriptor\r\n    dcsspptr_t ptr = DESC_NEW(dcsspDescriptors, DCSSP_MUTABLES_NEW, tid);\r\n    assert((((dcsspDescriptors[tid].mutables & MASK_SEQ) >> OFFSET_SEQ) & 1) == 0);\r\n    ptr->addr1 = addr1;\r\n    ptr->old1 = old1;\r\n    ptr->addr2 = addr2;\r\n    ptr->old2 = old2;\r\n    ptr->new2 = new2;\r\n    \r\n    // add payload1 and payload2 to the dcssp descriptor\r\n    int i;\r\n    for (i=0;payload1[i];++i) {\r\n        ptr->payload1[i] = payload1[i];\r\n        assert(i < MAX_PAYLOAD_PTRS);\r\n    }\r\n    ptr->payload1[i] = NULL;\r\n    for (i=0;payload2[i];++i) {\r\n        ptr->payload2[i] = payload2[i];\r\n        assert(i < MAX_PAYLOAD_PTRS);\r\n    }\r\n    ptr->payload2[i] = NULL;\r\n    DESC_INITIALIZED(dcsspDescriptors, tid);\r\n    \r\n    // create tagptr\r\n    assert((((dcsspDescriptors[tid].mutables & MASK_SEQ) >> OFFSET_SEQ) & 1) == 1);\r\n    tagptr_t tagptr = TAGPTR_NEW(tid, ptr->mutables, DCSSP_TAGBIT);\r\n    \r\n    // perform the dcssp operation described by our descriptor\r\n    casword_t r;\r\n    do {\r\n        assert(!isDcssp(ptr->old2));\r\n        assert(isDcssp(tagptr));\r\n        r = VAL_CAS(ptr->addr2, ptr->old2, (casword_t) tagptr);\r\n        if (isDcssp(r)) {\r\n#ifdef USE_DEBUGCOUNTERS\r\n            this->dcsspHelpCounter->inc(tid);\r\n#endif\r\n            dcsspHelpOther(tid, (dcssptagptr_t) r);\r\n        }\r\n    } while (isDcssp(r));\r\n    if (r == ptr->old2){\r\n//        DELAY_UP_TO(1000);\r\n        return dcsspHelp(tid, tagptr, ptr, false); // finish our own operation      \r\n    } \r\n    return {DCSSP_FAILED_ADDR2,r};//DCSSP_FAILED_ADDR2;\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ncasword_t dcsspProvider<PAYLOAD_T>::dcsspRead(const int tid, casword_t volatile * addr) {\r\n    casword_t r;\r\n    while (1) {\r\n        r = *addr;\r\n        if (isDcssp(r)) {\r\n#ifdef USE_DEBUGCOUNTERS\r\n            this->dcsspHelpCounter->inc(tid);\r\n#endif\r\n            dcsspHelpOther(tid, (dcssptagptr_t) r);\r\n        } else {\r\n            return r;\r\n        }\r\n    }\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ndcsspProvider<PAYLOAD_T>::dcsspProvider(const int numProcesses) : NUM_PROCESSES(numProcesses) {\r\n#ifdef USE_DEBUGCOUNTERS\r\n    dcsspHelpCounter = new debugCounter(NUM_PROCESSES);\r\n#endif\r\n    DESC_INIT_ALL(dcsspDescriptors, DCSSP_MUTABLES_NEW, NUM_PROCESSES);\r\n    for (int tid=0;tid<numProcesses;++tid) {\r\n        dcsspDescriptors[tid].addr1 = 0;\r\n        dcsspDescriptors[tid].addr2 = 0;\r\n        dcsspDescriptors[tid].new2 = 0;\r\n        dcsspDescriptors[tid].old1 = 0;\r\n        dcsspDescriptors[tid].old2 = 0;\r\n        dcsspDescriptors[tid].payload1[0] = NULL;\r\n        dcsspDescriptors[tid].payload2[0] = NULL;\r\n    }\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ndcsspProvider<PAYLOAD_T>::~dcsspProvider() {\r\n#ifdef USE_DEBUGCOUNTERS\r\n    delete dcsspHelpCounter;\r\n#endif\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ncasword_t dcsspProvider<PAYLOAD_T>::readPtr(const int tid, casword_t volatile * addr) {\r\n    casword_t r;\r\n    r = dcsspRead(tid, addr);\r\n    return r;\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\ncasword_t dcsspProvider<PAYLOAD_T>::readVal(const int tid, casword_t volatile * addr) {\r\n    return ((casword_t) readPtr(tid, addr))>>DCSSP_LEFTSHIFT;\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::writePtr(casword_t volatile * addr, casword_t ptr) {\r\n    //assert((*addr & DCSSP_TAGBIT) == 0);\r\n    assert((ptr & DCSSP_TAGBIT) == 0);\r\n    *addr = ptr;\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::writeVal(casword_t volatile * addr, casword_t val) {\r\n    writePtr(addr, val<<DCSSP_LEFTSHIFT);\r\n}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::initThread(const int tid) {}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::deinitThread(const int tid) {}\r\n\r\ntemplate <typename PAYLOAD_T>\r\nvoid dcsspProvider<PAYLOAD_T>::debugPrint() {\r\n#ifdef USE_DEBUGCOUNTERS\r\n    cout<<\"dcssp helping : \"<<this->dcsspHelpCounter->getTotal()<<endl;\r\n#endif\r\n}\r\n\r\n#endif /* DCSS_PLUS_IMPL_H */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/dcss/testing.cpp",
    "content": "#include <cstdlib>\r\n#include <cmath>\r\n#include <iostream>\r\n#include \"dcss_plus_impl.h\"\r\n\r\nusing namespace std;\r\n\r\n#define NUM_OPS 10000000\r\n#define INCREMENT 1\r\n\r\n#define FALSE_SHARING_ULL_FACTOR 24\r\n#define FALSE_SHARING_PAD_BYTES 192\r\n\r\n#define COUNTER(tid) (counters[(tid)*FALSE_SHARING_ULL_FACTOR])\r\n\r\nint numProcesses = 0;\r\nvolatile unsigned long long counters[MAX_TID_POW2*FALSE_SHARING_ULL_FACTOR];\r\nvolatile char padding[FALSE_SHARING_PAD_BYTES];\r\nvolatile unsigned long long faa;\r\n\r\nvolatile bool start;\r\nvolatile int running; // number of threads that are running\r\ndcsspProvider * prov;\r\n\r\n#ifndef KERNEL\r\n#define KERNEL test_kernel1\r\n#endif\r\n\r\n#ifndef VALIDATE\r\n#define VALIDATE validate1\r\n#endif\r\n\r\n//#define GET_FAA_FOR_TID(tid) ((faa >> ((tid)*(62/numProcesses))) & (numProcesses == 1 ? 0xffffffffffffffffULL : ((1ULL<<(62/numProcesses))-1)))\r\n\r\nvoid * test_kernel1(void * arg) {\r\n    const int tid = *((int *) arg);\r\n    //const unsigned long long numOps = min(1ULL<<20, 1ULL<<(62/numProcesses)-1);\r\n    //const unsigned long long increment = 1ULL<<(tid*(62/numProcesses));\r\n    prov->initThread(tid);\r\n    __sync_fetch_and_add(&running, 1);\r\n    while (!start) { __sync_synchronize(); }\r\n    \r\n    //COUTATOMICTID(\"performing \"<<numOps<<\" operations\"<<endl);\r\n    int numSucc = 0;\r\n    while (numSucc < NUM_OPS) {\r\n#if 1\r\n        void * deletedNodes[] = {NULL};\r\n        casword_t oldval = (casword_t) prov->readVal(tid,(casword_t*)&(COUNTER(tid)));\r\n        casword_t newval = (casword_t) oldval+1;\r\n        if (DCSSP_SUCCESS == prov->dcsspVal(tid, (casword_t *) &faa, (casword_t) faa, (casword_t *) &COUNTER(tid), oldval, newval, deletedNodes)) {\r\n            ++numSucc;\r\n            __sync_fetch_and_add(&faa, INCREMENT);\r\n        }\r\n#else\r\n        ++numSucc;\r\n        ++COUNTER(tid);\r\n        __sync_fetch_and_add(&faa, INCREMENT);\r\n#endif\r\n    }\r\n    \r\n    prov->deinitThread(tid);\r\n}\r\n\r\nbool validate1() {\r\n    // compute checksum\r\n    bool good = true;\r\n    for (int i=0;i<numProcesses;++i) {\r\n        unsigned long long c = prov->readVal(i,(casword_t*)&(COUNTER(i)));\r\n        if (c != NUM_OPS) {\r\n            cout<<\"ERROR: counters[\"<<i<<\"]=\"<<c<<\" does not match NUM_OPS=\"<<NUM_OPS<<endl;\r\n            good = false;\r\n        } else {\r\n            cout<<\"thread \"<<i<<\": counter=\"<<c<<\" NUM_OPS=\"<<NUM_OPS<<endl;\r\n        }\r\n\r\n//        if (c != GET_FAA_FOR_TID(i)) {\r\n//            cout<<\"ERROR: counters[\"<<i<<\"]=\"<<c<<\" does not match FAA subword=\"<<(GET_FAA_FOR_TID(i))<<endl;\r\n//            good = false;\r\n//        }\r\n//        cout<<\"thread \"<<i<<\": counter=\"<<c<<\" faa=\"<<(GET_FAA_FOR_TID(i))<<endl;\r\n    }\r\n    \r\n    const unsigned long long f = faa;\r\n    if (f != NUM_OPS * numProcesses) {\r\n        cout<<\"ERROR: faa=\"<<f<<\" does not match NUM_OPS*numProcesses=\"<<(NUM_OPS*numProcesses)<<endl;\r\n        good = false;\r\n    } else {\r\n        cout<<\"faa=\"<<f<<\" and NUM_OPS*numProcesses=\"<<(NUM_OPS*numProcesses)<<endl;\r\n    }\r\n    return good;\r\n}\r\n\r\nvoid * test_kernel2(void * arg) {\r\n    const int tid = *((int *) arg);\r\n    prov->initThread(tid);\r\n    __sync_fetch_and_add(&running, 1);\r\n    while (!start) { __sync_synchronize(); }\r\n    \r\n    //COUTATOMICTID(\"performing \"<<numOps<<\" operations\"<<endl);\r\n    int numSucc = 0;\r\n    while (numSucc < NUM_OPS) {\r\n        void * deletedNodes[] = {NULL};\r\n        casword_t old1 = (casword_t) COUNTER((tid+1)%numProcesses);\r\n        casword_t old2 = (casword_t) prov->readVal(tid, (casword_t *) &faa);\r\n        casword_t new2 = (casword_t) old2+1;\r\n        if (DCSSP_SUCCESS == prov->dcsspVal(tid, (casword_t *) &COUNTER((tid+1)%numProcesses), old1, (casword_t *) &faa, old2, new2, deletedNodes)) {\r\n            ++numSucc;\r\n            ++COUNTER(tid);\r\n        }\r\n    }\r\n    prov->deinitThread(tid);\r\n}\r\n\r\nbool validate2() {\r\n    // compute checksum\r\n    bool good = true;\r\n    for (int i=0;i<numProcesses;++i) {\r\n        unsigned long long c = COUNTER(i);\r\n        if (c != NUM_OPS) {\r\n            cout<<\"ERROR: counters[\"<<i<<\"]=\"<<c<<\" does not match NUM_OPS=\"<<NUM_OPS<<endl;\r\n            good = false;\r\n        } else {\r\n            cout<<\"thread \"<<i<<\": counter=\"<<c<<\" NUM_OPS=\"<<NUM_OPS<<endl;\r\n        }\r\n    }\r\n    \r\n    const int tid = 0;\r\n    const unsigned long long f = prov->readVal(tid, (casword_t *) &faa);\r\n    if (f != NUM_OPS * numProcesses) {\r\n        cout<<\"ERROR: faa=\"<<f<<\" does not match NUM_OPS*numProcesses=\"<<(NUM_OPS*numProcesses)<<endl;\r\n        good = false;\r\n    } else {\r\n        cout<<\"faa=\"<<f<<\" and NUM_OPS*numProcesses=\"<<(NUM_OPS*numProcesses)<<endl;\r\n    }\r\n    return good;\r\n}\r\n\r\nint main(int argc, char** argv) {\r\n    if (argc != 2) {\r\n        cout<<\"Usage: \"<<argv[0]<<\" NUM_THREADS\"<<endl;\r\n        exit(-1);\r\n    }\r\n    numProcesses = atoi(argv[1]);\r\n    \r\n    // create threads\r\n    const int tid = 0; // dummy tid for main thread\r\n    pthread_t *threads[numProcesses];\r\n    int ids[numProcesses];\r\n    for (int i=0;i<numProcesses;++i) {\r\n        threads[i] = new pthread_t;\r\n        ids[i] = i;\r\n        COUNTER(i) = 0;\r\n    }\r\n    \r\n    // init data structure\r\n    faa = 0;\r\n    for (int i=0;i<numProcesses;++i) {\r\n        COUNTER(i) = 0;\r\n    }\r\n    prov = new dcsspProvider(numProcesses);\r\n\r\n    // start all threads\r\n    running = 0;\r\n    start = false;\r\n    __sync_synchronize();\r\n    for (int i=0;i<numProcesses;++i) {\r\n        if (pthread_create(threads[i], NULL, KERNEL, &ids[i])) {\r\n            cerr<<\"ERROR: could not create thread\"<<endl;\r\n            exit(-1);\r\n        }\r\n    }\r\n    while (running < numProcesses) {\r\n        TRACE COUTATOMIC(\"main thread: waiting for threads to START running=\"<<running<<endl);\r\n        __sync_synchronize();\r\n    } // wait for all threads to be ready\r\n    COUTATOMIC(\"main thread: starting trial...\"<<endl);\r\n    __sync_synchronize();\r\n    start = true;\r\n    __sync_synchronize();\r\n    \r\n    // join all threads\r\n    for (int i=0;i<numProcesses;++i) {\r\n//        COUTATOMIC(\"joining thread \"<<i<<endl);\r\n        if (pthread_join(*(threads[i]), NULL)) {\r\n            cerr<<\"ERROR: could not join thread\"<<endl;\r\n            exit(-1);\r\n        }\r\n    }\r\n    \r\n    if (VALIDATE()) {\r\n        COUTATOMIC(\"main thread: \"<<\"All tests passed.\"<<endl);\r\n    } else {\r\n        COUTATOMIC(\"main thread: \"<<\"ERROR occurred.\"<<endl);\r\n    }\r\n    \r\n    delete prov;\r\n    \r\n    return 0;\r\n}\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/descriptors/descriptors.h",
    "content": "/* \r\n * File:   descriptors.h\r\n * Author: tabrown\r\n *\r\n * Created on June 8, 2016, 6:18 PM\r\n */\r\n\r\n#ifndef DESCRIPTORS_H\r\n#define\tDESCRIPTORS_H\r\n\r\ntypedef intptr_t tagptr_t;\r\ntypedef intptr_t mutables_t;\r\n\r\n#endif\t/* DESCRIPTORS_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/descriptors/descriptors_impl.h",
    "content": "/* \r\n * File:   descriptors_impl.h\r\n * Author: tabrown\r\n *\r\n * Created on June 9, 2016, 4:04 PM\r\n */\r\n\r\n#ifndef DESCRIPTORS_IMPL_H\r\n#define\tDESCRIPTORS_IMPL_H\r\n\r\n#include \"descriptors.h\"\r\n\r\n#if !defined(DESC1_T) || !defined(DESC1_ARRAY) || !defined(MUTABLES1_NEW)\r\n#error \"Must define DESC1_T, DESC1_ARRAY, MUTABLES1_NEW before including descriptors_impl.h\"\r\n#endif\r\n\r\n#define DESC1_INIT_ALL(numProcesses) { \\\r\n    for (int i=0;i<(numProcesses);++i) { \\\r\n        DESC1_ARRAY[i].c.mutables = MUTABLES1_NEW(0); \\\r\n    } \\\r\n}\r\n\r\n/**\r\n * pointer to descriptor (listed least to most significant):\r\n * 1-bit: is descriptor\r\n * 10-bits: thread id\r\n * remaining bits: sequence number (for avoiding the ABA problem)\r\n */\r\n\r\n/**\r\n * mutables_t corresponds to the mutables field of the descriptor.\r\n * it contains the mutable fields of the descriptor and a sequence number.\r\n * the width, offset and mask for the sequence number is defined below.\r\n * this sequence number width, offset and mask are also shared by tagptr_t.\r\n *\r\n * in particular, for any tagptr_t x and mutables_t y, the sequence numbers\r\n * in x and y are equal iff x&MASK1_SEQ == y&MASK1_SEQ (despite the differing\r\n * types of x and y).\r\n * \r\n * tagptr_t consists of a triple <seq, tid, testbit>.\r\n * these three fields are defined by the TAGPTR_ macros below.\r\n */\r\n\r\n#ifndef WIDTH1_SEQ\r\n    #define WIDTH1_SEQ 48\r\n#endif\r\n#define OFFSET1_SEQ 11\r\n#define MASK1_SEQ ((uintptr_t)((1LL<<WIDTH1_SEQ)-1)<<OFFSET1_SEQ) /* cast to avoid signed bit shifting */\r\n#define UNPACK1_SEQ(tagptrOrMutables) (((uintptr_t)(tagptrOrMutables))>>OFFSET1_SEQ)\r\n\r\n#define TAGPTR1_OFFSET_STALE 0 /* UNUSED */\r\n#define TAGPTR1_OFFSET_TID 1\r\n#define TAGPTR1_MASK_STALE 0x1 /* UNUSED */\r\n#define TAGPTR1_MASK_TID (((1<<OFFSET1_SEQ)-1)&(~(TAGPTR1_MASK_STALE)))\r\n#define TAGPTR1_STALE(tagptr) (((tagptr_t) (tagptr)) & TAGPTR1_MASK_STALE) /* UNUSED */\r\n#define TAGPTR1_UNPACK_TID(tagptr) ((int) ((((tagptr_t) (tagptr))&TAGPTR1_MASK_TID)>>TAGPTR1_OFFSET_TID))\r\n#define TAGPTR1_UNPACK_PTR(tagptr) (&DESC1_ARRAY[TAGPTR1_UNPACK_TID((tagptr))])\r\n#define TAGPTR1_NEW(tid, mutables) ((tagptr_t) (((UNPACK1_SEQ(mutables))<<OFFSET1_SEQ) | ((tid)<<TAGPTR1_OFFSET_TID)))\r\n// assert: there is no thread with tid DUMMY_TID that ever calls TAGPTR1_NEW\r\n#define LAST_TID1 (TAGPTR1_MASK_TID>>TAGPTR1_OFFSET_TID)\r\n#define TAGPTR1_STATIC_DESC(id) ((tagptr_t) TAGPTR1_NEW(LAST_TID1-1-id, 0))\r\n#define TAGPTR1_DUMMY_DESC(id) ((tagptr_t) TAGPTR1_NEW(LAST_TID1, id<<OFFSET1_SEQ))\r\n\r\n#define comma1 ,\r\n\r\n#define MUTABLES1_UNPACK_FIELD(mutables, mask, offset) \\\r\n    ((((mutables_t) (mutables))&(mask))>>(offset))\r\n#define MUTABLES1_WRITE_FIELD(fldMutables, snapMutables, val, mask, offset) { \\\r\n    mutables_t __v = (fldMutables); \\\r\n    while (UNPACK1_SEQ(__v) == UNPACK1_SEQ((snapMutables)) \\\r\n            && MUTABLES1_UNPACK_FIELD(__v, (mask), (offset)) != (val) \\\r\n            && !__sync_bool_compare_and_swap(&(fldMutables), __v, \\\r\n                    (__v & ~(mask)) | ((val)<<(offset)))) { \\\r\n        __v = (fldMutables); \\\r\n    } \\\r\n}\r\n#define MUTABLES1_WRITE_BIT(fldMutables, snapMutables, mask) { \\\r\n    mutables_t __v = (fldMutables); \\\r\n    while (UNPACK1_SEQ(__v) == UNPACK1_SEQ((snapMutables)) \\\r\n            && !(__v&(mask)) \\\r\n            && !__sync_bool_compare_and_swap(&(fldMutables), __v, (__v|(mask)))) { \\\r\n        __v = (fldMutables); \\\r\n    } \\\r\n}\r\n\r\n// WARNING: uses a GCC extension \"({ })\". to get rid of this, use an inline function.\r\n#define DESC1_SNAPSHOT(descDest, tagptr, sz) ({ \\\r\n    DESC1_T *__src = TAGPTR1_UNPACK_PTR((tagptr)); \\\r\n    memcpy((descDest), __src, (sz)); \\\r\n    SOFTWARE_BARRIER; /* prevent compiler from reordering read of __src->mutables before (at least the reading portion of) the memcpy */ \\\r\n    (UNPACK1_SEQ(__src->c.mutables) == UNPACK1_SEQ((tagptr))); \\\r\n})\r\n#define DESC1_READ_FIELD(successBit, fldMutables, tagptr, mask, offset) ({ \\\r\n    mutables_t __mutables = (fldMutables); \\\r\n    successBit = (UNPACK1_SEQ(__mutables) == UNPACK1_SEQ(tagptr)); \\\r\n    MUTABLES1_UNPACK_FIELD(__mutables, (mask), (offset)); \\\r\n})\r\n#define DESC1_NEW(tid) &DESC1_ARRAY[(tid)]; { /* note: only the process invoking this following macro can change the sequence# */ \\\r\n    SOFTWARE_BARRIER; \\\r\n    uintptr_t __v = DESC1_ARRAY[(tid)].c.mutables; \\\r\n/*    while (!__sync_bool_compare_and_swap(&DESC1_ARRAY[(tid)].mutables, __v, MUTABLES1_NEW(__v))) { \\\r\n        __v = DESC1_ARRAY[(tid)].mutables; \\\r\n    } \\\r\n}*/ \\\r\n    DESC1_ARRAY[(tid)].c.mutables = MUTABLES1_NEW(__v); \\\r\n    /*__sync_synchronize();*/ \\\r\n    SOFTWARE_BARRIER; \\\r\n}\r\n#define DESC1_INITIALIZED(tid) \\\r\n    SOFTWARE_BARRIER; \\\r\n    DESC1_ARRAY[(tid)].c.mutables += (1<<OFFSET1_SEQ); /*DESC1_NEW((tid))*/ \\\r\n    SOFTWARE_BARRIER;\r\n\r\n#endif\t/* DESCRIPTORS_IMPL_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/descriptors/descriptors_impl2.h",
    "content": "/* \r\n * File:   descriptors_impl2.h\r\n * Author: tabrown\r\n *\r\n * Created on June 30, 2016, 11:53 AM\r\n */\r\n\r\n#ifndef DESCRIPTORS_IMPL2_H\r\n#define\tDESCRIPTORS_IMPL2_H\r\n\r\n#include \"descriptors.h\"\r\n\r\n#define DESC_INIT_ALL(descArray, macro_mutablesNew, numProcesses) { \\\r\n    for (int i=0;i<(numProcesses);++i) { \\\r\n        (descArray)[i].mutables = macro_mutablesNew(0); \\\r\n    } \\\r\n}\r\n\r\n/**\r\n * mutables_t corresponds to the mutables field of the descriptor.\r\n * it contains the mutable fields of the descriptor and a sequence number.\r\n * the width, offset and mask for the sequence number is defined below.\r\n * this sequence number width, offset and mask are also shared by tagptr_t.\r\n *\r\n * in particular, for any tagptr_t x and mutables_t y, the sequence numbers\r\n * in x and y are equal iff x&MASK_SEQ == y&MASK_SEQ (despite the differing\r\n * types of x and y).\r\n * \r\n * tagptr_t consists of a triple <seq, tid, testbit>.\r\n * these three fields are defined by the TAGPTR_ macros below.\r\n */\r\n\r\n#ifndef WIDTH_SEQ\r\n    #define WIDTH_SEQ 48\r\n#endif\r\n#define OFFSET_SEQ 14\r\n#define MASK_SEQ ((uintptr_t)((1LL<<WIDTH_SEQ)-1)<<OFFSET_SEQ) /* cast to avoid signed bit shifting */\r\n#define UNPACK_SEQ(tagptrOrMutables) (((uintptr_t)(tagptrOrMutables))>>OFFSET_SEQ)\r\n\r\n#define TAGPTR_OFFSET_USER 0\r\n#define TAGPTR_OFFSET_TID 3\r\n#define TAGPTR_MASK_USER ((1<<TAGPTR_OFFSET_TID)-1) /* assumes TID is next field after USER */\r\n#define TAGPTR_MASK_TID (((1<<OFFSET_SEQ)-1)&(~(TAGPTR_MASK_USER)))\r\n#define TAGPTR_UNPACK_TID(tagptr) ((int) ((((tagptr_t) (tagptr))&TAGPTR_MASK_TID)>>TAGPTR_OFFSET_TID))\r\n#define TAGPTR_UNPACK_PTR(descArray, tagptr) (&(descArray)[TAGPTR_UNPACK_TID((tagptr))])\r\n#define TAGPTR_NEW(tid, mutables, userBits) ((tagptr_t) (((UNPACK_SEQ(mutables))<<OFFSET_SEQ) | ((tid)<<TAGPTR_OFFSET_TID) | (tagptr_t) (userBits)<<TAGPTR_OFFSET_USER))\r\n// assert: there is no thread with tid DUMMY_TID that ever calls TAGPTR_NEW\r\n#define LAST_TID (TAGPTR_MASK_TID>>TAGPTR_OFFSET_TID)\r\n#define TAGPTR_STATIC_DESC(id) ((tagptr_t) TAGPTR_NEW(LAST_TID-1-id, 0))\r\n#define TAGPTR_DUMMY_DESC(id) ((tagptr_t) TAGPTR_NEW(LAST_TID, id<<OFFSET_SEQ))\r\n\r\n#define comma ,\r\n\r\n#define MUTABLES_UNPACK_FIELD(mutables, mask, offset) \\\r\n    ((((mutables_t) (mutables))&(mask))>>(offset))\r\n// TODO: make more efficient version \"MUTABLES_CAS_BIT\"\r\n// TODO: change sequence # unpacking to masking for quick comparison\r\n// note: if there is only one subfield besides seq#, then the third if-block is redundant, and you should just return false if the cas fails, since the only way the cas fails and the field being cas'd contains still old is if the sequence number has changed.\r\n#define MUTABLES_BOOL_CAS_FIELD(successBit, fldMutables, snapMutables, oldval, val, mask, offset) { \\\r\n    mutables_t __v = (fldMutables); \\\r\n    while (1) { \\\r\n        if (UNPACK_SEQ(__v) != UNPACK_SEQ((snapMutables))) { \\\r\n            (successBit) = false; \\\r\n            break; \\\r\n        } \\\r\n        if ((successBit) = __sync_bool_compare_and_swap(&(fldMutables), \\\r\n                (__v & ~(mask)) | ((oldval)<<(offset)), \\\r\n                (__v & ~(mask)) | ((val)<<(offset)))) { \\\r\n            break; \\\r\n        } \\\r\n        __v = (fldMutables); \\\r\n        if (MUTABLES_UNPACK_FIELD(__v, (mask), (offset)) != (oldval)) { \\\r\n            (successBit) = false; \\\r\n            break; \\\r\n        } \\\r\n    } \\\r\n}\r\n\r\n#define MUTABLES_VAL_CAS_FIELD(failedBit, retval, fldMutables, snapMutables, oldval, val, mask, offset) { \\\r\n    mutables_t __v = (fldMutables); \\\r\n    while (1) { \\\r\n        if (UNPACK_SEQ(__v) != UNPACK_SEQ((snapMutables))) { \\\r\n            (failedBit) = true; /* version number has changed, CAS cannot occur */ \\\r\n            break; \\\r\n        } \\\r\n        mutables_t __oldval = (__v & ~(mask)) | ((oldval)<<(offset)); \\\r\n        (retval) = __sync_val_compare_and_swap(&(fldMutables), \\\r\n                __oldval, \\\r\n                (__v & ~(mask)) | ((val)<<(offset))); \\\r\n        if ((retval) == __oldval) { /* CAS SUCCESS */ \\\r\n            (retval) = MUTABLES_UNPACK_FIELD((retval), (mask), (offset)); /* return contents of subfield */ \\\r\n            (failedBit) = false; \\\r\n            break; \\\r\n        } else { /* CAS FAILURE: should we retry? */ \\\r\n            __v = (retval); /* save the value that caused our CAS to fail, in case we need to retry */ \\\r\n            (retval) = MUTABLES_UNPACK_FIELD((retval), (mask), (offset)); /* return contents of subfield */ \\\r\n            if ((retval) != (oldval)) { /* check if we failed because the subfield's contents do not match oldval */ \\\r\n                (failedBit) = false; \\\r\n                break; \\\r\n            } \\\r\n            /* subfield's contents DO match oldval, so we need to try again */ \\\r\n        } \\\r\n    } \\\r\n}\r\n\r\n// TODO: change sequence # unpacking to masking for quick comparison\r\n// note: MUTABLES_FAA_FIELD would be very similar to MUTABLES_BOOL_CAS_FIELD; i think one would simply delete the last if block and change the new val from (val)<<offset to (val&mask)+1.\r\n#define MUTABLES_WRITE_FIELD(fldMutables, snapMutables, val, mask, offset) { \\\r\n    mutables_t __v = (fldMutables); \\\r\n    while (UNPACK_SEQ(__v) == UNPACK_SEQ((snapMutables)) \\\r\n            && MUTABLES_UNPACK_FIELD(__v, (mask), (offset)) != (val) \\\r\n            && !__sync_bool_compare_and_swap(&(fldMutables), __v, \\\r\n                    (__v & ~(mask)) | ((val)<<(offset)))) { \\\r\n        __v = (fldMutables); \\\r\n    } \\\r\n}\r\n#define MUTABLES_WRITE_BIT(fldMutables, snapMutables, mask) { \\\r\n    mutables_t __v = (fldMutables); \\\r\n    while (UNPACK_SEQ(__v) == UNPACK_SEQ((snapMutables)) \\\r\n            && !(__v&(mask)) \\\r\n            && !__sync_bool_compare_and_swap(&(fldMutables), __v, (__v|(mask)))) { \\\r\n        __v = (fldMutables); \\\r\n    } \\\r\n}\r\n\r\n// WARNING: uses a GCC extension \"({ })\". to get rid of this, use an inline function.\r\n#define DESC_SNAPSHOT(descType, descArray, descDest, tagptr, sz) ({ \\\r\n    descType *__src = TAGPTR_UNPACK_PTR((descArray), (tagptr)); \\\r\n    memcpy((descDest), __src, (sz)); \\\r\n    SOFTWARE_BARRIER; /* prevent compiler from reordering read of __src->mutables before (at least the reading portion of) the memcpy */ \\\r\n    (UNPACK_SEQ(__src->mutables) == UNPACK_SEQ((tagptr))); \\\r\n})\r\n#define DESC_READ_FIELD(successBit, fldMutables, tagptr, mask, offset) ({ \\\r\n    mutables_t __mutables = (fldMutables); \\\r\n    successBit = (__mutables & MASK_SEQ) == ((tagptr) & MASK_SEQ); \\\r\n    MUTABLES_UNPACK_FIELD(__mutables, (mask), (offset)); \\\r\n})\r\n#define DESC_NEW(descArray, macro_mutablesNew, tid) &(descArray)[(tid)]; { /* note: only the process invoking this following macro can change the sequence# */ \\\r\n    SOFTWARE_BARRIER; \\\r\n    mutables_t __v = (descArray)[(tid)].mutables; \\\r\n    (descArray)[(tid)].mutables = macro_mutablesNew(__v); \\\r\n    SOFTWARE_BARRIER; \\\r\n    /*__sync_synchronize();*/ \\\r\n}\r\n#define DESC_INITIALIZED(descArray, tid) \\\r\n    SOFTWARE_BARRIER; \\\r\n    (descArray)[(tid)].mutables += (1<<OFFSET_SEQ); \\\r\n    SOFTWARE_BARRIER;\r\n\r\n#endif\t/* DESCRIPTORS_IMPL2_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/errors.h",
    "content": "/* \r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n *\r\n * Created on April 20, 2017, 1:09 PM\r\n */\r\n\r\n#ifndef ERRORS_H\r\n#define\tERRORS_H\r\n\r\n#include <iostream>\r\n#include <string>\r\n#include <unistd.h>\r\n\r\n#ifndef error\r\n#define error(s) { \\\r\n    std::cout<<\"ERROR: \"<<s<<\" (at \"<<__FILE__<<\"::\"<<__FUNCTION__<<\":\"<<__LINE__<<\")\"<<std::endl; \\\r\n    exit(-1); \\\r\n}\r\n#endif\r\n\r\n//__attribute__((always_inline))\r\n//void error(std::string s) {\r\n//    std::cout<<\"ERROR: \"<<s<<\" (at \"<<__FILE__<<\"::\"<<__FUNCTION__<<\":\"<<__LINE__<<\")\"<<std::endl;\r\n//    exit(-1);\r\n//}\r\n\r\n#endif\t/* ERRORS_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/plaf.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef MACHINECONSTANTS_H\r\n#define\tMACHINECONSTANTS_H\r\n\r\n#ifndef MAX_TID_POW2\r\n    #define MAX_TID_POW2 128 // MUST BE A POWER OF TWO, since this is used for some bitwise operations\r\n#endif\r\n#ifndef PHYSICAL_PROCESSORS\r\n    #define PHYSICAL_PROCESSORS 128\r\n#endif\r\n\r\n// the following definition is only used to pad data to avoid false sharing.\r\n// although the number of words per cache line is actually 8, we inflate this\r\n// figure to counteract the effects of prefetching multiple adjacent cache lines.\r\n#define PREFETCH_SIZE_WORDS 24\r\n#define PREFETCH_SIZE_BYTES 192\r\n#define BYTES_IN_CACHE_LINE 64\r\n\r\n#endif\t/* MACHINECONSTANTS_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/allocator_bump.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef ALLOC_BUMP_H\r\n#define\tALLOC_BUMP_H\r\n\r\n#include \"plaf.h\"\r\n#include \"globals.h\"\r\n#include \"allocator_interface.h\"\r\n#include <cstdlib>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <vector>\r\nusing namespace std;\r\n\r\ntemplate<typename T = void>\r\nclass allocator_bump : public allocator_interface<T> {\r\n    private:\r\n        const int cachelines;    // # cachelines needed to store an object of type T\r\n        // for bump allocation from a contiguous chunk of memory\r\n        T ** mem;             // mem[tid*PREFETCH_SIZE_WORDS] = pointer to current array to perform bump allocation from\r\n        int * memBytes;       // memBytes[tid*PREFETCH_SIZE_WORDS] = size of mem in bytes\r\n        T ** current;         // current[tid*PREFETCH_SIZE_WORDS] = pointer to current position in array mem\r\n        vector<T*> ** toFree; // toFree[tid] = pointer to vector of bump allocation arrays to free when this allocator is destroyed\r\n\r\n        T* bump_memory_next(const int tid) {\r\n            T* result = current[tid*PREFETCH_SIZE_WORDS];\r\n            current[tid*PREFETCH_SIZE_WORDS] = (T*) (((char*) current[tid*PREFETCH_SIZE_WORDS]) + (cachelines*BYTES_IN_CACHE_LINE));\r\n            return result;\r\n        }\r\n        int bump_memory_bytes_remaining(const int tid) {\r\n            return (((char*) mem[tid*PREFETCH_SIZE_WORDS])+memBytes[tid*PREFETCH_SIZE_WORDS]) - ((char*) current[tid*PREFETCH_SIZE_WORDS]);\r\n        }\r\n        bool bump_memory_full(const int tid) {\r\n            return (((char*) current[tid*PREFETCH_SIZE_WORDS])+cachelines*BYTES_IN_CACHE_LINE > ((char*) mem[tid*PREFETCH_SIZE_WORDS])+memBytes[tid*PREFETCH_SIZE_WORDS]);\r\n        }\r\n        // call this when mem is null, or doesn't contain enough space to allocate an object\r\n        void bump_memory_allocate(const int tid) {\r\n            mem[tid*PREFETCH_SIZE_WORDS] = (T*) malloc(1<<24);\r\n            memBytes[tid*PREFETCH_SIZE_WORDS] = 1<<24;\r\n            current[tid*PREFETCH_SIZE_WORDS] = mem[tid*PREFETCH_SIZE_WORDS];\r\n            toFree[tid]->push_back(mem[tid*PREFETCH_SIZE_WORDS]); // remember we allocated this to free it later\r\n#ifdef HAS_FUNCTION_aligned_alloc\r\n#else\r\n            // align on cacheline boundary\r\n            int mod = (int) (((long) mem[tid*PREFETCH_SIZE_WORDS]) % BYTES_IN_CACHE_LINE);\r\n            if (mod > 0) {\r\n                // we are ignoring the first mod bytes of mem, because if we\r\n                // use them, we will not be aligning objects to cache lines.\r\n                current[tid*PREFETCH_SIZE_WORDS] = (T*) (((char*) mem[tid*PREFETCH_SIZE_WORDS]) + BYTES_IN_CACHE_LINE - mod);\r\n            } else {\r\n                current[tid*PREFETCH_SIZE_WORDS] = mem[tid*PREFETCH_SIZE_WORDS];\r\n            }\r\n#endif\r\n            assert((((long) current[tid*PREFETCH_SIZE_WORDS]) % BYTES_IN_CACHE_LINE) == 0);\r\n        }\r\n\r\n    public:\r\n        template<typename _Tp1>\r\n        struct rebind {\r\n            typedef allocator_bump<_Tp1> other;\r\n        };\r\n\r\n        // reserve space for ONE object of type T\r\n        T* allocate(const int tid) {\r\n            // bump-allocate from a contiguous chunk of memory\r\n            if (!mem[tid*PREFETCH_SIZE_WORDS] || bump_memory_full(tid)) {\r\n                bump_memory_allocate(tid);\r\n                MEMORY_STATS {\r\n                    this->debug->addAllocated(tid, memBytes[tid*PREFETCH_SIZE_WORDS] / cachelines / BYTES_IN_CACHE_LINE);\r\n                    VERBOSE DEBUG2 {\r\n//                        if ((this->debug->getAllocated(tid) % 2000) == 0) {\r\n//                            this->debugInterfaces->reclaim->debugPrintStatus(tid);\r\n//                            debugPrintStatus(tid);\r\n                            COUTATOMICTID(\"allocated \"<<(memBytes[tid*PREFETCH_SIZE_WORDS] / cachelines / BYTES_IN_CACHE_LINE)/*this->debug->getAllocated(tid)*/<<\" records of size \"<<sizeof(T)<<std::endl);\r\n//                            COUTATOMIC(\" \");\r\n//                            this->pool->debugPrintStatus(tid);\r\n//                            COUTATOMIC(endl);\r\n//                        }\r\n                    }\r\n                }\r\n            }\r\n            return bump_memory_next(tid);\r\n        }\r\n        void static deallocate(const int tid, T * const p) {\r\n            // no op for this allocator; memory is freed only by the destructor.\r\n            // however, we have to call the destructor for the object manually...\r\n            p->~T();\r\n        }\r\n        void deallocateAndClear(const int tid, blockbag<T> * const bag) {\r\n            // the bag is cleared, which makes it seem like we're leaking memory,\r\n            // but it will be freed in the destructor as we release the huge\r\n            // slabs of memory.\r\n            bag->clearWithoutFreeingElements();\r\n        }\r\n\r\n        void debugPrintStatus(const int tid) {}\r\n\r\n        void initThread(const int tid) {}\r\n        \r\n        allocator_bump(const int numProcesses, debugInfo * const _debug)\r\n                : allocator_interface<T>(numProcesses, _debug)\r\n                , cachelines((sizeof(T)+(BYTES_IN_CACHE_LINE-1))/BYTES_IN_CACHE_LINE){\r\n            VERBOSE DEBUG COUTATOMIC(\"constructor allocator_bump\"<<std::endl);\r\n            mem = new T*[numProcesses*PREFETCH_SIZE_WORDS];\r\n            memBytes = new int[numProcesses*PREFETCH_SIZE_WORDS];\r\n            current = new T*[numProcesses*PREFETCH_SIZE_WORDS];\r\n            toFree = new vector<T*>*[numProcesses];\r\n            for (int tid=0;tid<numProcesses;++tid) {\r\n                mem[tid*PREFETCH_SIZE_WORDS] = 0;\r\n                memBytes[tid*PREFETCH_SIZE_WORDS] = 0;\r\n                current[tid*PREFETCH_SIZE_WORDS] = 0;\r\n                toFree[tid] = new vector<T*>();\r\n            }\r\n        }\r\n        ~allocator_bump() {\r\n            VERBOSE COUTATOMIC(\"destructor allocator_bump\"<<std::endl);\r\n            // free all allocated blocks of memory\r\n            for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n                int n = toFree[tid]->size();\r\n                for (int i=0;i<n;++i) {\r\n                    free((*toFree[tid])[i]);\r\n                }\r\n                delete toFree[tid];\r\n            }\r\n            delete[] mem;\r\n            delete[] memBytes;\r\n            delete[] current;\r\n            delete[] toFree;\r\n        }\r\n    };\r\n\r\n#endif\t/* ALLOC_NEW_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/allocator_interface.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef ALLOC_INTERFACE_H\r\n#define\tALLOC_INTERFACE_H\r\n\r\n#include \"debug_info.h\"\r\n#include \"blockbag.h\"\r\n#include <iostream>\r\nusing namespace std;\r\n\r\ntemplate <typename T = void>\r\nclass allocator_interface {\r\npublic:\r\n    debugInfo * const debug;\r\n    \r\n    const int NUM_PROCESSES;\r\n    \r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef allocator_interface<_Tp1> other;\r\n    };\r\n    \r\n    // allocate space for one object of type T\r\n    T* allocate(const int tid);\r\n    void deallocate(const int tid, T * const p);\r\n    void deallocateAndClear(const int tid, blockbag<T> * const bag);\r\n    void initThread(const int tid);\r\n    \r\n    void debugPrintStatus(const int tid);\r\n\r\n    allocator_interface(const int numProcesses, debugInfo * const _debug)\r\n            : debug(_debug)\r\n            , NUM_PROCESSES(numProcesses){\r\n        VERBOSE DEBUG std::cout<<\"constructor allocator_interface\"<<std::endl;\r\n    }\r\n    ~allocator_interface() {\r\n        VERBOSE DEBUG std::cout<<\"destructor allocator_interface\"<<std::endl;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/allocator_new.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef ALLOC_NEW_H\r\n#define\tALLOC_NEW_H\r\n\r\n#include \"plaf.h\"\r\n#include \"pool_interface.h\"\r\n#include <cstdlib>\r\n#include <cassert>\r\n#include <iostream>\r\nusing namespace std;\r\n\r\n//__thread long long currentAllocatedBytes = 0;\r\n//__thread long long maxAllocatedBytes = 0;\r\n\r\ntemplate<typename T = void>\r\nclass allocator_new : public allocator_interface<T> {\r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef allocator_new<_Tp1> other;\r\n    };\r\n    \r\n    // reserve space for ONE object of type T\r\n    T* allocate(const int tid) {\r\n        // allocate a new object\r\n        MEMORY_STATS {\r\n            this->debug->addAllocated(tid, 1);\r\n            VERBOSE {\r\n                if ((this->debug->getAllocated(tid) % 2000) == 0) {\r\n                    debugPrintStatus(tid);\r\n                }\r\n            }\r\n//            currentAllocatedBytes += sizeof(T);\r\n//            if (currentAllocatedBytes > maxAllocatedBytes) {\r\n//                maxAllocatedBytes = currentAllocatedBytes;\r\n//            }\r\n        }\r\n        return new T; //(T*) malloc(sizeof(T));\r\n    }\r\n    void deallocate(const int tid, T * const p) {\r\n        // note: allocators perform the actual freeing/deleting, since\r\n        // only they know how memory was allocated.\r\n        // pools simply call deallocate() to request that it is freed.\r\n        // allocators do not invoke pool functions.\r\n        MEMORY_STATS {\r\n            this->debug->addDeallocated(tid, 1);\r\n//            currentAllocatedBytes -= sizeof(T);\r\n        }\r\n#if !defined NO_FREE\r\n        delete p;\r\n#endif\r\n    }\r\n    void deallocateAndClear(const int tid, blockbag<T> * const bag) {\r\n#ifdef NO_FREE\r\n        bag->clearWithoutFreeingElements();\r\n#else\r\n        while (!bag->isEmpty()) {\r\n            T* ptr = bag->remove();\r\n            deallocate(tid, ptr);\r\n        }\r\n#endif\r\n    }\r\n    \r\n    void debugPrintStatus(const int tid) {\r\n//        std::cout<</*\"thread \"<<tid<<\" \"<<*/\"allocated \"<<this->debug->getAllocated(tid)<<\" objects of size \"<<(sizeof(T));\r\n//        std::cout<<\" \";\r\n////        this->pool->debugPrintStatus(tid);\r\n//        std::cout<<std::endl;\r\n    }\r\n    \r\n    void initThread(const int tid) {}\r\n    \r\n    allocator_new(const int numProcesses, debugInfo * const _debug)\r\n            : allocator_interface<T>(numProcesses, _debug) {\r\n        VERBOSE DEBUG std::cout<<\"constructor allocator_new\"<<std::endl;\r\n    }\r\n    ~allocator_new() {\r\n        VERBOSE DEBUG std::cout<<\"destructor allocator_new\"<<std::endl;\r\n    }\r\n};\r\n\r\n#endif\t/* ALLOC_NEW_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/allocator_new_segregated.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef ALLOC_NEW_SEGREGATED_H\r\n#define\tALLOC_NEW_SEGREGATED_H\r\n\r\n#include \"plaf.h\"\r\n#include \"pool_interface.h\"\r\n#include <cstdlib>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <dlfcn.h>\r\n#include <pthread.h>\r\nusing namespace std;\r\n\r\n//__thread long long currentAllocatedBytes = 0;\r\n//__thread long long maxAllocatedBytes = 0;\r\n\r\ntemplate<typename T = void>\r\nclass allocator_new_segregated : public allocator_interface<T> {\r\nprivate:\r\n    void* (*allocfn)(size_t size);\r\n    void (*freefn)(void *ptr);\r\n    \r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef allocator_new_segregated<_Tp1> other;\r\n    };\r\n    \r\n    // reserve space for ONE object of type T\r\n    T* allocate(const int tid) {\r\n        // allocate a new object\r\n        MEMORY_STATS {\r\n            this->debug->addAllocated(tid, 1);\r\n            VERBOSE {\r\n                if ((this->debug->getAllocated(tid) % 2000) == 0) {\r\n                    debugPrintStatus(tid);\r\n                }\r\n            }\r\n//            currentAllocatedBytes += sizeof(T);\r\n//            if (currentAllocatedBytes > maxAllocatedBytes) {\r\n//                maxAllocatedBytes = currentAllocatedBytes;\r\n//            }\r\n        }\r\n        return (T*) allocfn(sizeof(T));\r\n    }\r\n    void deallocate(const int tid, T * const p) {\r\n        // note: allocators perform the actual freeing/deleting, since\r\n        // only they know how memory was allocated.\r\n        // pools simply call deallocate() to request that it is freed.\r\n        // allocators do not invoke pool functions.\r\n        MEMORY_STATS {\r\n            this->debug->addDeallocated(tid, 1);\r\n//            currentAllocatedBytes -= sizeof(T);\r\n        }\r\n#if !defined NO_FREE\r\n        p->~T(); // explicitly call destructor, since we lose automatic destructor calls when we bypass new/delete([])\r\n        freefn(p);\r\n#endif\r\n    }\r\n    void deallocateAndClear(const int tid, blockbag<T> * const bag) {\r\n#if defined NO_FREE\r\n        bag->clearWithoutFreeingElements();\r\n#else\r\n        while (!bag->isEmpty()) {\r\n            T* ptr = bag->remove();\r\n            deallocate(tid, ptr);\r\n        }\r\n#endif\r\n    }\r\n    \r\n    void debugPrintStatus(const int tid) {}\r\n    \r\n    void initThread(const int tid) {}\r\n    \r\n    static void* dummy_thr(void *p) { return 0; }\r\n    \r\n    allocator_new_segregated(const int numProcesses, debugInfo * const _debug)\r\n            : allocator_interface<T>(numProcesses, _debug) {\r\n        VERBOSE DEBUG std::cout<<\"constructor allocator_new_segregated\"<<std::endl;\r\n        \r\n\tchar *lib = getenv(\"TREE_MALLOC\");\r\n\tif (!lib) {\r\n\t\tprintf(\"no TREE_MALLOC defined: using default!\\n\");\r\n                allocfn = malloc;\r\n                freefn = free;\r\n\t\treturn;\r\n\t}\r\n\tvoid *h = dlopen(lib, RTLD_NOW | RTLD_LOCAL);\r\n\tif (!h) {\r\n\t\tfprintf(stderr, \"unable to load '%s': %s\\n\", lib, dlerror());\r\n\t\texit(1);\r\n\t}\r\n\r\n\t// If the allocator exports pthread_create(), we assume it does so to detect\r\n\t// multi-threading (through interposition on pthread_create()) and so call\r\n\t// this function (since it might not be called otherwise, if the standard\r\n\t// allocator does a similar trick).\r\n\tint (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);\r\n\tpthread_create = (__typeof(pthread_create)) dlsym(h, \"pthread_create\");\r\n\tif (pthread_create) {\r\n\t\tpthread_t thr;\r\n\t\tpthread_create(&thr, NULL, dummy_thr, NULL);\r\n\t\tpthread_join(thr, NULL);\r\n\t}\r\n\tallocfn = (__typeof(allocfn)) dlsym(h, \"malloc\");\r\n\tif (!allocfn) {\r\n\t\tfprintf(stderr, \"unable to resolve malloc\\n\");\r\n\t\texit(1);\r\n\t}\r\n\tfreefn = (__typeof(freefn)) dlsym(h, \"free\");\r\n\tif (!freefn) {\r\n\t\tfprintf(stderr, \"unable to resolve free\\n\");\r\n\t\texit(1);\r\n\t}\r\n    }\r\n    ~allocator_new_segregated() {\r\n        VERBOSE DEBUG std::cout<<\"destructor allocator_new_segregated\"<<std::endl;\r\n    }\r\n};\r\n\r\n#endif\t/* ALLOC_NEW_SEGREGATED_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/allocator_once.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef ALLOC_ONCE_H\r\n#define\tALLOC_ONCE_H\r\n\r\n#include \"plaf.h\"\r\n#include \"globals.h\"\r\n#include \"allocator_interface.h\"\r\n#include <cstdlib>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <vector>\r\nusing namespace std;\r\n\r\n// this allocator only performs allocation once, at the beginning of the program.\r\n// define the following to specify how much memory should be allocated.\r\n#ifndef ALLOC_ONCE_MEMORY\r\n    #define ALLOC_ONCE_MEMORY (1ULL<<32) /* default: 4 GB */\r\n#endif\r\n\r\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\r\n\r\ntemplate<typename T = void>\r\nclass allocator_once : public allocator_interface<T> {\r\nprivate:\r\n    const int cachelines;    // # cachelines needed to store an object of type T\r\n    // for bump allocation from a contiguous chunk of memory\r\n    T ** mem;             // mem[tid] = pointer to current array to perform bump allocation from\r\n    size_t * memBytes;       // memBytes[tid*PREFETCH_SIZE_WORDS] = size of mem in bytes\r\n    T ** current;         // current[tid*PREFETCH_SIZE_WORDS] = pointer to current position in array mem\r\n\r\n    T* bump_memory_next(const int tid) {\r\n        T* result = current[tid*PREFETCH_SIZE_WORDS];\r\n        current[tid*PREFETCH_SIZE_WORDS] = (T*) (((char*) current[tid*PREFETCH_SIZE_WORDS]) + (cachelines*BYTES_IN_CACHE_LINE));\r\n        return result;\r\n    }\r\n    int bump_memory_bytes_remaining(const int tid) {\r\n        return (((char*) mem[tid])+memBytes[tid*PREFETCH_SIZE_WORDS]) - ((char*) current[tid*PREFETCH_SIZE_WORDS]);\r\n    }\r\n    bool bump_memory_full(const int tid) {\r\n        return (((char*) current[tid*PREFETCH_SIZE_WORDS])+cachelines*BYTES_IN_CACHE_LINE > ((char*) mem[tid])+memBytes[tid*PREFETCH_SIZE_WORDS]);\r\n    }\r\n\r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef allocator_once<_Tp1> other;\r\n    };\r\n\r\n    // reserve space for ONE object of type T\r\n    T* allocate(const int tid) {\r\n        if (bump_memory_full(tid)) return NULL;\r\n        return bump_memory_next(tid);\r\n    }\r\n    void static deallocate(const int tid, T * const p) {\r\n        // no op for this allocator; memory is freed only by the destructor.\r\n        // however, we have to call the destructor for the object manually...\r\n        p->~T();\r\n    }\r\n    void deallocateAndClear(const int tid, blockbag<T> * const bag) {\r\n        // the bag is cleared, which makes it seem like we're leaking memory,\r\n        // but it will be freed in the destructor as we release the huge\r\n        // slabs of memory.\r\n        bag->clearWithoutFreeingElements();\r\n    }\r\n\r\n    void debugPrintStatus(const int tid) {}\r\n    \r\n    void initThread(const int tid) {\r\n//        // touch each page of memory before our trial starts\r\n//        long pagesize = sysconf(_SC_PAGE_SIZE);\r\n//        int last = (int) (memBytes[tid*PREFETCH_SIZE_WORDS]/pagesize);\r\n//        VERBOSE COUTATOMICTID(\"touching each page... memBytes=\"<<memBytes[tid*PREFETCH_SIZE_WORDS]<<\" pagesize=\"<<pagesize<<\" last=\"<<last<<std::endl);\r\n//        for (int i=0;i<last;++i) {\r\n//            TRACE COUTATOMICTID(\"    \"<<tid<<\" touching page \"<<i<<\" at address \"<<(long)((long*)(((char*) mem[tid])+i*pagesize))<<std::endl);\r\n//            *((long*)(((char*) mem[tid])+i*pagesize)) = 0;\r\n//        }\r\n//        VERBOSE COUTATOMICTID(\" finished touching each page.\"<<std::endl);\r\n    }\r\n\r\n    allocator_once(const int numProcesses, debugInfo * const _debug)\r\n            : allocator_interface<T>(numProcesses, _debug)\r\n            , cachelines((sizeof(T)+(BYTES_IN_CACHE_LINE-1))/BYTES_IN_CACHE_LINE) {\r\n        VERBOSE DEBUG COUTATOMIC(\"constructor allocator_once\"<<std::endl);\r\n        mem = new T*[numProcesses];\r\n        memBytes = new size_t[numProcesses*PREFETCH_SIZE_WORDS];\r\n        current = new T*[numProcesses*PREFETCH_SIZE_WORDS];\r\n        for (int tid=0;tid<numProcesses;++tid) {\r\n            long long newSizeBytes = ALLOC_ONCE_MEMORY / numProcesses; // divide several GB amongst all threads.\r\n            VERBOSE COUTATOMIC(\"newSizeBytes        = \"<<newSizeBytes<<std::endl);\r\n            assert((newSizeBytes % (cachelines*BYTES_IN_CACHE_LINE)) == 0);\r\n\r\n            mem[tid] = (T*) malloc((size_t) newSizeBytes);\r\n            if (mem[tid] == NULL) {\r\n                cerr<<\"could not allocate memory\"<<std::endl;\r\n                exit(-1);\r\n            }\r\n            //COUTATOMIC(\"successfully allocated\"<<std::endl);\r\n            memBytes[tid*PREFETCH_SIZE_WORDS] = (size_t) newSizeBytes;\r\n            current[tid*PREFETCH_SIZE_WORDS] = mem[tid];\r\n            // align on cacheline boundary\r\n            int mod = (int) (((long) mem[tid]) % BYTES_IN_CACHE_LINE);\r\n            if (mod > 0) {\r\n                // we are ignoring the first mod bytes of mem, because if we\r\n                // use them, we will not be aligning objects to cache lines.\r\n                current[tid*PREFETCH_SIZE_WORDS] = (T*) (((char*) mem[tid]) + BYTES_IN_CACHE_LINE - mod);\r\n            } else {\r\n                current[tid*PREFETCH_SIZE_WORDS] = mem[tid];\r\n            }\r\n            assert((((long) current[tid*PREFETCH_SIZE_WORDS]) % BYTES_IN_CACHE_LINE) == 0);\r\n        }\r\n    }\r\n    ~allocator_once() {\r\n        long allocated = 0;\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            allocated += (((char*) current[tid*PREFETCH_SIZE_WORDS]) - ((char*) mem[tid]));\r\n        }\r\n        VERBOSE COUTATOMIC(\"destructor allocator_once allocated=\"<<allocated<<\" bytes, or \"<<(allocated/(cachelines*BYTES_IN_CACHE_LINE))<<\" objects of size \"<<sizeof(T)<<\" occupying \"<<cachelines<<\" cache lines\"<<std::endl);\r\n        // free all allocated blocks of memory\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            delete mem[tid];\r\n        }\r\n        delete[] mem;\r\n        delete[] memBytes;\r\n        delete[] current;\r\n    }\r\n};\r\n#endif\t/* ALLOC_ONCE_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/arraylist.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef ARRAYLIST_H\r\n#define\tARRAYLIST_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include <atomic>\r\n#include \"plaf.h\"\r\n#include \"globals.h\"\r\nusing namespace std;\r\n\r\n// this list allows multiple readers, but only ONE writer.\r\n// i don't know if it is linearizable; maybe linearize at __size.load()/store()\r\ntemplate <typename T>\r\nclass AtomicArrayList {\r\nprivate:\r\n    atomic_int __size;\r\n    atomic_uintptr_t *data;\r\npublic:\r\n    const int capacity;\r\n    AtomicArrayList(const int _capacity) : capacity(_capacity) {\r\n        VERBOSE DEBUG COUTATOMIC(\"constructor AtomicArrayList capacity=\"<<capacity<<std::endl);\r\n        __size.store(0, memory_order_relaxed);\r\n        data = new atomic_uintptr_t[capacity];\r\n    }\r\n    ~AtomicArrayList() {\r\n        delete[] data;\r\n    }\r\n    inline T* get(const int ix) {\r\n        return (T*) data[ix].load(memory_order_relaxed);\r\n    }\r\n    inline int size() {\r\n        return __size.load(memory_order_relaxed); // note: this must be seq_cst if membars are not manually added\r\n    }\r\n    inline void add(T * const obj) {\r\n        int sz = __size.load(memory_order_relaxed);\r\n        assert(sz < capacity);\r\n        SOFTWARE_BARRIER;\r\n        data[sz].store((uintptr_t) obj, memory_order_relaxed);\r\n        SOFTWARE_BARRIER;\r\n        __size.store(sz+1, memory_order_relaxed); // note: this must be seq_cst if membars are not manually added\r\n    }\r\n    inline void erase(const int ix) {\r\n        int sz = __size.load(memory_order_relaxed);\r\n        assert(ix >= 0 && ix < sz);\r\n        if (ix != sz-1) data[ix].store(data[sz-1].load(memory_order_relaxed), memory_order_relaxed);\r\n        __size.store(sz-1, memory_order_relaxed); // note: this must be seq_cst if membars are not manually added\r\n    }\r\n    inline void erase(T * const obj) {\r\n        int ix = getIndex(obj);\r\n        if (ix != -1) erase(ix);\r\n    }\r\n    inline int getIndex(T * const obj) {\r\n        int sz = __size.load(memory_order_relaxed); // note: this must be seq_cst if membars are not manually added\r\n        for (int i=0;i<sz;++i) {\r\n            if (data[i].load(memory_order_relaxed) == (uintptr_t) obj) return i;\r\n        }\r\n        return -1;\r\n    }\r\n    inline bool contains(T * const obj) {\r\n        return (getIndex(obj) != -1);\r\n    }\r\n    inline void clear() {\r\n        SOFTWARE_BARRIER;\r\n        __size.store(0, memory_order_relaxed); // note: this must be seq_cst if membars are not manually added\r\n        SOFTWARE_BARRIER;\r\n    }\r\n    inline bool isFull() {\r\n        return __size.load(memory_order_relaxed) == capacity; // note: this must be seq_cst if membars are not manually added\r\n    }\r\n    inline bool isEmpty() {\r\n        return __size.load(memory_order_relaxed) == 0; // note: this must be seq_cst if membars are not manually added\r\n    }\r\n};\r\n\r\ntemplate <typename T>\r\nclass ArrayList {\r\nprivate:\r\n    int __size;\r\n    T **data;\r\npublic:\r\n    const int capacity;\r\n    ArrayList(const int _capacity) : capacity(_capacity) {\r\n        __size = 0;\r\n        data = new T*[capacity];\r\n    }\r\n    ~ArrayList() {\r\n        delete[] data;\r\n    }\r\n    inline T* get(const int ix) {\r\n        return data[ix];\r\n    }\r\n    inline int size() {\r\n        return __size;\r\n    }\r\n    inline void add(T * const obj) {\r\n        assert(__size < capacity);\r\n        data[__size++] = obj;\r\n    }\r\n    inline void erase(const int ix) {\r\n        assert(ix >= 0 && ix < __size);\r\n        data[ix] = data[--__size];\r\n    }\r\n    inline void erase(T * const obj) {\r\n        int ix = getIndex(obj);\r\n        if (ix != -1) erase(ix);\r\n    }\r\n    inline int getIndex(T * const obj) {\r\n        for (int i=0;i<__size;++i) {\r\n            if (data[i] == obj) return i;\r\n        }\r\n        return -1;\r\n    }\r\n    inline bool contains(T * const obj) {\r\n        return (getIndex(obj) != -1);\r\n    }\r\n    inline void clear() {\r\n        __size = 0;\r\n    }\r\n    inline bool isFull() {\r\n        return __size == capacity;\r\n    }\r\n    inline bool isEmpty() {\r\n        return __size == 0;\r\n    }\r\n};\r\n\r\n\r\n#endif\t/* ARRAYLIST_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/blockbag.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef BLOCKLIST_H\r\n#define\tBLOCKLIST_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include \"blockpool.h\"\r\n#include \"plaf.h\"\r\nusing namespace std;\r\n\r\ntemplate <typename T>\r\nclass blockpool;\r\n\r\ntemplate <typename T>\r\nclass blockbag;\r\n\r\ntemplate <typename T>\r\nclass block;\r\n\r\n#include \"lockfreeblockbag.h\"\r\n\r\n// BLOCK_SIZE must be a power of two, or else the bitwise math is invalid.\r\n#define BLOCK_SIZE (1<<8)\r\n    \r\n    template <typename T>\r\n    class block { // stack implemented as an array\r\n        private:\r\n            T * data[BLOCK_SIZE];\r\n            int size;\r\n        public:\r\n            block<T> *next;\r\n            \r\n            block(block<T> * const _next) : next(_next) {\r\n                size = 0;\r\n            }\r\n            ~block() {\r\n                assert(size == 0);\r\n            }\r\n            \r\n            bool isFull() {\r\n                return size == BLOCK_SIZE;\r\n            }\r\n            bool isEmpty() {\r\n                return size == 0;\r\n            }\r\n            // precondition: !isFull()\r\n            void push(T * const obj) {\r\n                assert(size < BLOCK_SIZE);\r\n                const int sz = size;\r\n                //assert(interruptible[((long) ((int *) pthread_getspecific(pthreadkey)))*PREFETCH_SIZE_WORDS] == false);\r\n                data[size] = obj;\r\n                SOFTWARE_BARRIER;\r\n                size = sz+1;\r\n            }\r\n            // precondition: !isEmpty()\r\n            T* pop() {\r\n                assert(size > 0);\r\n                const int sz = size-1;\r\n                size = sz;\r\n                return data[sz];\r\n            }\r\n            T* peek(const int ix) {\r\n                assert(ix >= 0);\r\n                //assert(ix < size);\r\n                return data[ix];\r\n            }\r\n            // warning: linear time\r\n            bool contains(T* const obj) {\r\n                for (int i=0;i<size;++i) {\r\n                    if (data[i] == obj) return true;\r\n                }\r\n                return false;\r\n            }\r\n            // warning: linear time\r\n            // however, it is constant time to erase the last thing you pushed.\r\n            void erase(T* const obj) {\r\n                if (size == 0) return; // empty\r\n                assert(size > 0);\r\n                if (data[size-1] == obj) {\r\n                    --size; // erase last pushed item\r\n                    return;\r\n                }\r\n                // the things we want to remove are probably the oldest,\r\n                // so we iterate forward (head of stack = data[size-1])\r\n                for (int i=0;i<size-1;++i) {\r\n                    if (data[i] == obj) {\r\n                        data[i] = data[size-1];\r\n                        SOFTWARE_BARRIER;\r\n                        --size;\r\n                        return;\r\n                    }\r\n                }\r\n            }\r\n            void erase(const int ix) {\r\n                if (size) {\r\n                    assert(size > 0);\r\n                    if (ix != size-1) {\r\n                        data[ix] = data[size-1];\r\n                    }\r\n                    SOFTWARE_BARRIER;\r\n                    --size; // erase last item\r\n                }\r\n            }\r\n            void replace(const int ix, T* const obj) {\r\n                assert(ix >= 0);\r\n                assert(ix < size);\r\n                assert(obj);\r\n                data[ix] = obj;\r\n            }\r\n            int computeSize() {\r\n                return size;\r\n            }\r\n            // this function is occasionally useful if, for instance,\r\n            // you use a bump allocator, which hands out objects from\r\n            // a huge slab of memory.\r\n            // then, in the destructor for a data structure, we can clear\r\n            // a block without worrying about leaking memory,\r\n            // since we will just free the whole slab at once.\r\n            void clearWithoutFreeingElements() {\r\n                SOFTWARE_BARRIER;\r\n                size = 0;\r\n                SOFTWARE_BARRIER;\r\n            }\r\n    };\r\n\r\n    template <typename T>\r\n    class blockbag_iterator {\r\n    private:\r\n        blockbag<T> * const bag;\r\n        block<T> * const head;\r\n        block<T> * curr;\r\n        int ix;\r\n//        long long reclaimCountStart;\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_BLOCKS_TRAVERSED\r\n        int sizeInBlocks;\r\n        int blocksTraversed;\r\n#endif\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_STEPS\r\n        int steps;\r\n#endif\r\n    public:\r\n        block<T> *getCurr() const { return curr; }\r\n        int getIndex() const { return ix; }\r\n        \r\n        blockbag_iterator(block<T> * const _head, blockbag<T> * const _bag) \r\n                : bag(_bag), head(_head) {\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_STEPS\r\n            steps = 0;\r\n#endif\r\n//            reclaimCountStart = bag->getReclaimCount();\r\n//            assert((reclaimCountStart % 1) == 0);\r\n//            if (reclaimCountStart % 1) {\r\n//                // bag is currently being reclaimed. we cannot traverse it.\r\n//                curr = NULL;\r\n//                ix = -1;\r\n//            } else {\r\n                curr = head;\r\n                ix = -1;\r\n                if (curr) {\r\n                    ix = curr->computeSize(); // \"linearize\" here\r\n                    (*this)++;\r\n                }\r\n//            }\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_BLOCKS_TRAVERSED\r\n                sizeInBlocks = bag->sizeInBlocks;\r\n                blocksTraversed = 0;\r\n#endif\r\n        }\r\n        inline T* operator*() const {\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_STEPS\r\n            if (ix < 0) std::cout<<\"bag=\"<<bag<<\" head=\"<<head<<\" curr=\"<<curr<<\" ix=\"<<ix<<\" steps=\"<<steps<<std::endl;\r\n#endif\r\n//            /****** start consistency check for concurrent iteration ******/\r\n//            assert(reclaimCountStart == bag->getReclaimCount());\r\n//            if (reclaimCountStart != bag->getReclaimCount()) {\r\n//                // bag is being/has been reclaimed, so we cannot iterate\r\n//                return NULL;\r\n//            }\r\n//            /******* end consistency check for concurrent iteration *******/\r\n            return curr->peek(ix);\r\n        }\r\n        inline blockbag_iterator<T>& operator++(int) {\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_STEPS\r\n            ++steps;\r\n#endif\r\n            --ix;\r\n            if (ix < 0) {\r\n#ifdef BLOCKBAG_ITERATOR_COUNT_BLOCKS_TRAVERSED\r\n                ++blocksTraversed;\r\n                if (blocksTraversed > sizeInBlocks + 1) {\r\n                    std::cout<<\"ERROR: too many blocks traversed! traversed \"<<blocksTraversed<<\" when we expected at most 1+\"<<sizeInBlocks<<std::endl;\r\n                    exit(-1);\r\n                }\r\n                assert(blocksTraversed <= sizeInBlocks + 1);\r\n#endif\r\n                curr = curr->next;                                              // race condition: if reclamation happens AND curr is freed along with too many other blocks to fit in the blockpool, then this access might fault\r\n//                /****** start consistency check for concurrent iteration ******/\r\n//                assert(reclaimCountStart == bag->getReclaimCount());\r\n//                if (reclaimCountStart != bag->getReclaimCount()) {\r\n//                    // bag is being/has been reclaimed, so we cannot iterate\r\n//                    curr = NULL;\r\n//                    ix = -1;\r\n//                    return *this;\r\n//                }\r\n//                /******* end consistency check for concurrent iteration *******/\r\n                ix = (curr ? curr->computeSize()-1 : -1);                       // race condition: if reclamation happens AND curr is freed along with too many other blocks to fit in the blockpool, then this access might fault\r\n//                /****** start consistency check for concurrent iteration ******/\r\n//                assert(reclaimCountStart == bag->getReclaimCount());\r\n//                if (reclaimCountStart != bag->getReclaimCount()) {\r\n//                    // bag is being/has been reclaimed, so we cannot iterate\r\n//                    curr = NULL;\r\n//                    ix = -1;\r\n//                    return *this;\r\n//                }\r\n//                /******* end consistency check for concurrent iteration *******/\r\n            }\r\n            return *this;\r\n        }\r\n        void swap(block<T> * const otherCurr, const int otherIx) {\r\n            T * const temp = otherCurr->peek(otherIx);\r\n            otherCurr->replace(otherIx, curr->peek(ix));\r\n            curr->replace(ix, temp);\r\n        }\r\n        // erases the current item\r\n        void erase() {\r\n            assert(curr);\r\n            assert(!curr->isEmpty());\r\n            bool result = bag->erase(curr, ix);\r\n            if (ix >= curr->computeSize()) {\r\n                (*this)++;\r\n            }\r\n            if (result) {\r\n                (*this)++;\r\n            }\r\n        }\r\n    };\r\n    template <typename T>\r\n    inline bool operator==(const blockbag_iterator<T>& a, const blockbag_iterator<T>& b) {\r\n        if (a.getCurr() != b.getCurr()) return false;\r\n        if (a.getIndex() != b.getIndex()) return false;\r\n        return true;\r\n    }\r\n    template <typename T>\r\n    inline bool operator!=(const blockbag_iterator<T>& a, const blockbag_iterator<T>& b) {\r\n        return !(a == b);\r\n    }\r\n    \r\n    // bag implemented with linked list whose nodes are blocks.\r\n    // invariant: head and tail are never NULL\r\n    // invariant: head is not full (computeSize() < BLOCK_SIZE)\r\n    // invariant: all blocks except for the head are full\r\n    // invariant: the bag is empty iff head is empty and head->next is null\r\n    template <typename T>\r\n    class blockbag {\r\n    private:\r\n        int owner;\r\n        volatile long long reclaimCount; // number of times this bag has been the oldest epoch bag and had its nodes reclaimed\r\n        long debugFreed;\r\n    public:\r\n        int sizeInBlocks;\r\n    private:\r\n        \r\n        block<T> *head;\r\n        block<T> *tail;\r\n        \r\n        void validate() {\r\n            // invariant: head and tail are never NULL\r\n            assert(head);\r\n            // invariant: head and tail are never NULL\r\n            assert(tail);\r\n            // invariant: head is not full (computeSize() < BLOCK_SIZE)\r\n            assert(!head->isFull());\r\n            // invariant: all blocks except for the head are full\r\n            block<T> *curr = head->next;\r\n            while (curr) {\r\n                assert(curr->isFull());\r\n                curr = curr->next;\r\n            }\r\n            // invariant: sizeInBlocks is correct\r\n            assert(sizeInBlocks == computeSizeInBlocks());\r\n        }\r\n        \r\n        blockpool<T> * const pool;\r\n        \r\n        void debugPrintBag() {\r\n            std::cout<<\"(\"<<computeSize()<<\",\"<<computeSizeInBlocks()<<\") =\";\r\n            block<T> * curr = head;\r\n            while (curr) {\r\n                std::cout<<\" \"<<curr->computeSize()<<\"[\"<<((long)curr)<<\"]\";\r\n                curr = curr->next;\r\n            }\r\n        }\r\n        int computeSizeInBlocks() {\r\n            int result = 0;\r\n            block<T> *curr = head;\r\n            while (curr) {\r\n                ++result;\r\n                curr = curr->next;\r\n            }\r\n            return result;\r\n        }\r\n        \r\n    public:\r\n        blockbag(const int tid, blockpool<T> * const _pool) : pool(_pool) {\r\n//            VERBOSE DEBUG std::cout<<\"constructor blockbag\"<<std::endl;\r\n            owner = tid;\r\n//            std::cout<<\"bag owner=\"<<owner<<std::endl;\r\n            reclaimCount = 0;\r\n            debugFreed = 0;\r\n            sizeInBlocks = 1;\r\n            head = pool->allocateBlock(NULL);\r\n            tail = head;\r\n            DEBUG2 assert(computeSizeInBlocks() == sizeInBlocks);\r\n            DEBUG2 assert(computeSize() == 0);\r\n            DEBUG2 validate();\r\n        }\r\n        ~blockbag() {\r\n//            VERBOSE DEBUG std::cout<<\"destructor blockbag;\";\r\n            assert(isEmpty());\r\n            // clear the bag AND FREE EVERY BLOCK IN IT\r\n            while (head) {\r\n                block<T> * const temp = head;\r\n                head = head->next;\r\n                //DEBUG ++debugFreed;\r\n                pool->deallocateBlock(temp);\r\n            }\r\n//            VERBOSE DEBUG std::cout<<\" freed \"<<debugFreed<<std::endl;\r\n        }\r\n        \r\n        int getOwner() {\r\n            return owner;\r\n        }\r\n        \r\n        inline void incrementReclaimCount() {\r\n            SOFTWARE_BARRIER;\r\n            ++reclaimCount;\r\n            SOFTWARE_BARRIER;\r\n        }\r\n        inline long long getReclaimCount() {\r\n            SOFTWARE_BARRIER;\r\n            return reclaimCount;\r\n        }\r\n        \r\n        blockbag_iterator<T> begin() {\r\n            return blockbag_iterator<T>(head, this);\r\n        }\r\n        blockbag_iterator<T> end() {\r\n            return blockbag_iterator<T>(NULL, this);\r\n        }\r\n\r\n        void add(T * const obj) {\r\n            DEBUG2 validate();\r\n            int oldsize; DEBUG2 oldsize = computeSize();\r\n            head->push(obj);\r\n            if (head->isFull()) {\r\n                int oldNumBlocks; DEBUG2 oldNumBlocks = computeSizeInBlocks();\r\n                block<T> *newblock = pool->allocateBlock(head);\r\n                ++sizeInBlocks;\r\n                //DEBUG2 std::cout<<\"(((\"<<((long)head)<<\" full. prepending \"<<((long)newblock)<<\")))\";\r\n                SOFTWARE_BARRIER;\r\n                head = newblock;\r\n                DEBUG2 assert(oldNumBlocks + 1 == computeSizeInBlocks());\r\n                DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n            }\r\n            DEBUG2 assert(oldsize + 1 == computeSize());\r\n            DEBUG2 validate();\r\n        }\r\n        \r\n        template <typename Alloc>\r\n        void add(const int tid, T * const obj, lockfreeblockbag<T> * const sharedBag, const int thresh, Alloc * const alloc) {\r\n            DEBUG2 validate();\r\n            int oldsize; DEBUG2 oldsize = computeSize();\r\n            head->push(obj);\r\n            if (head->isFull()) {\r\n                int oldNumBlocks; DEBUG2 oldNumBlocks = computeSizeInBlocks();\r\n                block<T> *newblock = pool->allocateBlock(head);\r\n                ++sizeInBlocks;\r\n                //DEBUG2 std::cout<<\"(((\"<<((long)head)<<\" full. prepending \"<<((long)newblock)<<\")))\";\r\n                head = newblock;\r\n                DEBUG2 assert(oldNumBlocks + 1 == computeSizeInBlocks());\r\n                DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n                DEBUG2 assert(oldsize + 1 == computeSize());\r\n                if (sizeInBlocks > thresh) {\r\n                    block<T> *b = removeFullBlock(); // returns NULL if freeBag has < 2 full blocks\r\n                    assert(b);\r\n                    sharedBag->addBlock(b);\r\n                    MEMORY_STATS alloc->debug->addGiven(tid, 1);\r\n                    //DEBUG2 COUTATOMIC(\"  thread \"<<this->tid<<\" sharedBag(\"<<(sizeof(T)==sizeof(Node<long,long>)?\"Node\":\"SCXRecord\")<<\") now contains \"<<sharedBag->size()<<\" blocks\"<<std::endl);\r\n                    DEBUG2 assert(oldsize + 1 - BLOCK_SIZE == computeSize());\r\n                }\r\n            }\r\n            DEBUG2 validate();\r\n        }\r\n        bool isEmpty() {\r\n            return head->next == NULL && head->isEmpty();\r\n        }\r\n        // precondition: !isEmpty, !curr->isEmpty()\r\n        // returns true if a subsequent invocation of curr->peek(ix) will return\r\n        //         an item that was previously EARLIER in iterator order, and false otherwise.\r\n        bool erase(block<T> * const curr, const int ix) {\r\n            assert(!isEmpty());\r\n            assert(!curr->isEmpty());\r\n            DEBUG2 validate();\r\n            if (head->isEmpty()) {\r\n                // current block cannot be head, since head is empty\r\n                assert(curr != head);\r\n                \r\n                // eliminate empty head block, since next block will now be non-full\r\n                block<T> * const temp = head;\r\n                head = head->next;\r\n                pool->deallocateBlock(temp);\r\n                --sizeInBlocks;\r\n            }\r\n            assert(!head->isEmpty());\r\n            \r\n            // case 1: curr is the new head\r\n            if (curr == head) {\r\n                // erase from head block\r\n                head->erase(ix);\r\n                DEBUG2 validate();\r\n                return false;\r\n            \r\n            // case 2: curr is not the head\r\n            } else {\r\n                assert(!head->isEmpty());\r\n                // we use head->pop() to retrieve\r\n                // some object from the head block.\r\n                // then, we replace the object to be erased\r\n                // with the object taken from the head block.\r\n                T* obj = head->pop();\r\n                curr->replace(ix, obj);\r\n                DEBUG2 validate();\r\n                return true;\r\n            }\r\n        }\r\n        // precondition: !isEmpty()\r\n        T* remove() {\r\n            assert(!isEmpty());\r\n            DEBUG2 validate();\r\n            int oldsize; DEBUG2 oldsize = computeSize();\r\n            T *result;\r\n            if (head->isEmpty()) {\r\n                result = head->next->pop();\r\n                int oldNumBlocks; DEBUG2 oldNumBlocks = computeSizeInBlocks();\r\n                block<T> * const temp = head;\r\n                head = head->next;\r\n                pool->deallocateBlock(temp);\r\n                --sizeInBlocks;\r\n                DEBUG2 assert(oldNumBlocks - 1 == computeSizeInBlocks());\r\n                DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n                DEBUG2 assert(oldsize - 1 == computeSize());\r\n                DEBUG2 validate();\r\n                return result;\r\n            } else {\r\n                result = head->pop();\r\n                DEBUG2 validate();\r\n                return result;\r\n            }\r\n        }\r\n        \r\n        \r\n        ////////// not anymore // precondition: !isEmpty()\r\n        template <typename Alloc>\r\n        T* remove(const int tid, lockfreeblockbag<T> * const sharedBag, Alloc * const alloc) {\r\n            //assert(!isEmpty());\r\n            DEBUG2 validate();\r\n            int oldsize; DEBUG2 oldsize = computeSize();\r\n            T *result;\r\n            if (head->isEmpty()) {\r\n                if (head->next) {\r\n                    result = head->next->pop();\r\n                    int oldNumBlocks; DEBUG2 oldNumBlocks = computeSizeInBlocks();\r\n                    block<T> * const temp = head;\r\n                    head = head->next;\r\n                    pool->deallocateBlock(temp);\r\n                    --sizeInBlocks;\r\n                    DEBUG2 assert(oldNumBlocks - 1 == computeSizeInBlocks());\r\n                    DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n                    DEBUG2 assert(oldsize - 1 == computeSize());\r\n//                    if (sizeInBlocks == 1) {\r\n//                        block<T> *b = sharedBag->getBlock();\r\n//                        if (b) {\r\n//                            addFullBlock(b);\r\n//                            //DEBUG this->debug->addTaken(tid, 1);\r\n//                            //DEBUG2 COUTATOMIC(\"  thread \"<<this->tid<<\" took \"<<b->computeSize()<<\" objects from sharedBag\"<<std::endl);\r\n//                        } else {\r\n//                            /** begin debug **/\r\n//                            for (int i=0;i<BLOCK_SIZE-1;++i) {\r\n//                                add(alloc->allocate(tid));\r\n//                            }\r\n//                            /** end debug **/\r\n//                        }\r\n//                    }\r\n//                    assert(sizeInBlocks > 1);\r\n                    DEBUG2 validate();\r\n//                    MEMORY_STATS2 alloc->debug->addFromPool(tid, 1);\r\n                    return result;\r\n                } else {\r\n                    block<T> *b = sharedBag->getBlock();\r\n                    if (b) {\r\n                        addFullBlock(b);\r\n                        MEMORY_STATS alloc->debug->addTaken(tid, 1);\r\n                        //DEBUG2 COUTATOMIC(\"  thread \"<<this->tid<<\" took \"<<b->computeSize()<<\" objects from sharedBag\"<<std::endl);\r\n                        return remove(/*tid, sharedBag, alloc*/);\r\n                    } else {\r\n//                        return alloc->allocate(tid);\r\n                        /** begin debug **/\r\n                        // allocate entire block worth of objects\r\n                        for (int i=0;i<BLOCK_SIZE;++i) {\r\n                            add(alloc->allocate(tid));\r\n                        }\r\n                        /** end debug **/\r\n                        assert(sizeInBlocks > 1);\r\n                        DEBUG2 validate();\r\n                        return remove(/*tid, sharedBag, alloc*/);\r\n                    }\r\n                }\r\n            } else {\r\n//                MEMORY_STATS2 alloc->debug->addFromPool(tid, 1);\r\n                result = head->pop();\r\n                DEBUG2 validate();\r\n                return result;\r\n            }\r\n        }\r\n        \r\n        // removes and returns a full block if the list contains\r\n        // at least two full blocks. otherwise, this returns NULL;\r\n        block<T>* removeFullBlock() {\r\n            DEBUG2 validate();\r\n            int oldsize; DEBUG2 oldsize = computeSize();\r\n            int oldNumBlocks; DEBUG2 oldNumBlocks = computeSizeInBlocks();\r\n            block<T> *second = head->next;\r\n            if (second != NULL) {\r\n                if (second->next != NULL) {\r\n                    assert(second->computeSize() == BLOCK_SIZE);\r\n                    head->next = second->next;\r\n                    second->next = NULL; // not technically necessary, but safer\r\n                    --sizeInBlocks;\r\n                    DEBUG2 assert(oldNumBlocks - 1 == computeSizeInBlocks());\r\n                    DEBUG2 assert(oldsize - BLOCK_SIZE == computeSize());\r\n                    DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n                    DEBUG2 validate();\r\n                    return second;\r\n                }\r\n            }\r\n            DEBUG2 assert(oldsize == computeSize());\r\n            DEBUG2 if (sizeInBlocks != computeSizeInBlocks()) { std::cout<<\"sizeInBlocks=\"<<sizeInBlocks<<\" compute=\"<<computeSizeInBlocks()<<std::endl; }\r\n            DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n            DEBUG2 validate();\r\n            return 0;\r\n        }\r\n        void addFullBlock(block<T> *b) {\r\n            DEBUG2 validate();\r\n            assert(b->computeSize() == BLOCK_SIZE);\r\n            assert(b->next == NULL);\r\n            int oldsize; DEBUG2 oldsize = computeSize();\r\n            int oldNumBlocks; DEBUG2 oldNumBlocks = computeSizeInBlocks();\r\n            tail->next = b;\r\n            tail = b;\r\n            ++sizeInBlocks;\r\n            DEBUG2 assert(oldNumBlocks + 1 == computeSizeInBlocks());\r\n            DEBUG2 assert(oldsize + BLOCK_SIZE == computeSize());\r\n            DEBUG2 assert(sizeInBlocks == computeSizeInBlocks());\r\n            DEBUG2 validate();\r\n        }\r\n//        void appendMoveFullBlocks(blockbag<T> * const other) {\r\n//            assert(other);\r\n//            assert(other->head);\r\n//            DEBUG2 validate();\r\n//            \r\n//            // other consists of one non-full block followed by\r\n//            // zero or more full blocks.\r\n//            // we want this list to contain only full blocks,\r\n//            // except for the head block, so we move any full blocks\r\n//            // from other to this list.\r\n//            // if the other blockbag has a non-empty first block, we simply\r\n//            // ignore it.\r\n//            // (it doesn't matter if we leave a small amount of objects in\r\n//            //  the other bag; they'll be appended to another list later,\r\n//            //  when more blocks become full.)\r\n//\r\n//            // if other contains any full blocks, we append them to this list.\r\n//            if (other->head->next != NULL) {\r\n//                DEBUG2 assert(other->head->next->computeSize() == BLOCK_SIZE);\r\n//                assert(other->head->next->isFull());\r\n//                // append all but the head of the other bag to the end of this bag\r\n//                sizeInBlocks += (other->getSizeInBlocks() - 1);\r\n//                tail->next = other->head->next;\r\n//                tail = other->tail;\r\n//                assert(head && tail);\r\n//                // remove all but the head of the other bag\r\n//                other->head->next = NULL;\r\n//                other->tail = other->head;\r\n//                other->sizeInBlocks = 1;\r\n//                assert(other->head && other->tail);\r\n//            }\r\n//            DEBUG2 other->validate();\r\n//            DEBUG2 validate();\r\n//        }\r\n//        block<T> * const getPredecessorBlock(block<T> * const curr) {\r\n//            block<T> * result = head;\r\n//            while (result && result != curr) {\r\n//                result = result->next;\r\n//            }\r\n//            return result;\r\n//        }\r\n        void appendMoveFullBlocks(blockbag<T> * const other, block<T> * predecessor) {\r\n            assert(other);\r\n            assert(other->head);\r\n            assert(predecessor);\r\n            DEBUG2 validate();\r\n            \r\n            // other consists of one maybe-full block followed by\r\n            // zero or more full blocks.\r\n            // our goal is to append all blocks in the other bag\r\n            // starting with predecessor->next to our own bag.\r\n            if (predecessor->next != NULL) {\r\n                DEBUG2 assert(predecessor->next->computeSize() == BLOCK_SIZE);\r\n                assert(predecessor->next->isFull());\r\n                tail->next = predecessor->next;\r\n                tail = other->tail;\r\n                assert(head && tail);\r\n                sizeInBlocks = computeSizeInBlocks();\r\n                // remove all blocks after predecessor in the other bag\r\n                predecessor->next = NULL;\r\n                other->tail = predecessor;\r\n                other->sizeInBlocks = other->computeSizeInBlocks();\r\n                assert(other->head && other->tail);\r\n            }\r\n            DEBUG2 other->validate();\r\n            DEBUG2 validate();\r\n        }\r\n        void appendMoveFullBlocks(blockbag<T> * const other) {\r\n            appendMoveFullBlocks(other, other->head);\r\n        }\r\n        void appendMoveAll(blockbag<T> * const other) {\r\n            assert(other);\r\n            DEBUG2 validate();\r\n            appendMoveFullBlocks(other);\r\n            while (!other->isEmpty()) {\r\n                add(other->remove());\r\n            }\r\n            sizeInBlocks = computeSizeInBlocks();\r\n            DEBUG2 validate();\r\n        }\r\n        int computeSize() {\r\n            int result = 0;\r\n            block<T> *curr = head;\r\n            while (curr) {\r\n                result += curr->computeSize();\r\n                curr = curr->next;\r\n            }\r\n            return result;\r\n        }\r\n        int getSizeInBlocks() {\r\n            return sizeInBlocks;\r\n        }\r\n        // this function is occasionally useful if, for instance,\r\n        // you use a bump allocator, which hands out objects from\r\n        // a huge slab of memory.\r\n        // then, in the destructor for a data structure, we can clear\r\n        // a blockbag without worrying about leaking memory,\r\n        // since we will just free the whole slab at once.\r\n        void clearWithoutFreeingElements() {\r\n            // free all blocks except for head.\r\n            // we still have to do this, even if we don't have to\r\n            // free elements of type T, since blocks are always\r\n            // allocated using a blockpool, and we will leak memory\r\n            // if we don't return blocks to the pool.\r\n            DEBUG2 validate();\r\n            block<T> * curr = head->next;\r\n            while (curr) {\r\n                block<T> * const temp = curr;\r\n                curr = curr->next;\r\n                temp->clearWithoutFreeingElements();\r\n                this->pool->deallocateBlock(temp);\r\n            }\r\n            // fix up the head/tail pointers\r\n            // and clear the remaining head block\r\n            head->next = NULL;\r\n            tail = head;\r\n            head->clearWithoutFreeingElements();\r\n            sizeInBlocks = 1;\r\n            DEBUG2 validate();\r\n        }\r\n    };\r\n\r\n#endif\t/* BLOCKBAG_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/blockpool.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef BLOCKPOOL_H\r\n#define\tBLOCKPOOL_H\r\n\r\n#include \"blockbag.h\"\r\n#include \"plaf.h\"\r\n#include <iostream>\r\nusing namespace std;\r\n\r\n#define MAX_BLOCK_POOL_SIZE 32\r\n\r\n#ifndef VERBOSE\r\n#define VERBOSE if(0)\r\n#endif\r\n\r\ntemplate <typename T>\r\nclass block;\r\n\r\ntemplate <typename T>\r\nclass blockpool {\r\nprivate:\r\n    block<T> *pool[MAX_BLOCK_POOL_SIZE];\r\n    int poolSize;\r\n\r\n    long debugAllocated;\r\n    long debugPoolDeallocated;\r\n    long debugPoolAllocated;\r\n    long debugFreed;\r\npublic:\r\n    blockpool() {\r\n        poolSize = 0;\r\n        debugAllocated = 0;\r\n        debugPoolAllocated = 0;\r\n        debugPoolDeallocated = 0;\r\n        debugFreed = 0;\r\n    }\r\n    ~blockpool() {\r\n        VERBOSE DEBUG std::cout<<\"destructor blockpool;\";\r\n        for (int i=0;i<poolSize;++i) {\r\n            //DEBUG ++debugFreed;\r\n            assert(pool[i]->isEmpty());\r\n            delete pool[i];                           // warning: uses locks (for some allocators)\r\n        }\r\n        VERBOSE DEBUG std::cout<<\" blocks allocated \"<<debugAllocated<<\" pool-allocated \"<<debugPoolAllocated<<\" freed \"<<debugFreed<<\" pool-deallocated \"<<debugPoolDeallocated<<std::endl;\r\n    }\r\n    block<T>* allocateBlock(block<T> * const next) {\r\n        if (poolSize) {\r\n            //DEBUG ++debugPoolAllocated;\r\n            block<T> *result = pool[--poolSize]; // pop a block off the stack\r\n            *result = block<T>(next);\r\n            assert(result->next == next);\r\n            assert(result->computeSize() == 0);\r\n            assert(result->isEmpty());\r\n            return result;\r\n        } else {\r\n            //DEBUG ++debugAllocated;\r\n            return new block<T>(next);                // warning: uses locks (for some allocators)\r\n        }\r\n    }\r\n    void deallocateBlock(block<T> * const b) {\r\n        assert(b->isEmpty());\r\n        if (poolSize == MAX_BLOCK_POOL_SIZE) {\r\n            //DEBUG ++debugFreed;\r\n//            assert(poolSize < MAX_BLOCK_POOL_SIZE); // for the RQ benchmarks, we want to assert that we never free a block\r\n#ifndef NO_FREE\r\n            delete b;                                 // warning: uses locks (for some allocators)\r\n#endif\r\n        } else {\r\n            //DEBUG ++debugPoolDeallocated;\r\n            pool[poolSize++] = b;\r\n        }\r\n    }\r\n};\r\n\r\n#endif\t/* BLOCKPOOL_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/debug_info.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef DEBUG_INFO_H\r\n#define\tDEBUG_INFO_H\r\n\r\n#include \"plaf.h\"\r\n\r\nstruct _memrecl_counters {\r\n    volatile char padding1[PREFETCH_SIZE_BYTES];\r\n    long allocated;\r\n    long deallocated;\r\n    long fromPool;\r\n    long toPool; // how many objects have been added to this pool\r\n    long given; // how many blocks have been moved from this pool to a shared pool\r\n    long taken; // how many blocks have been moved from a shared pool to this pool\r\n    long retired; // how many objects have been retired\r\n    volatile char padding2[PREFETCH_SIZE_BYTES];\r\n};\r\n\r\nclass debugInfo {\r\nprivate:\r\n    const int NUM_PROCESSES;\r\n    _memrecl_counters c[MAX_TID_POW2];\r\npublic:\r\n    void clear() {\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            c[tid].allocated = 0;\r\n            c[tid].deallocated = 0;\r\n            c[tid].fromPool = 0;\r\n            c[tid].toPool = 0;\r\n            c[tid].given = 0;\r\n            c[tid].taken = 0;\r\n            c[tid].retired = 0;\r\n        }\r\n    }\r\n    void addAllocated(const int tid, const int val) {\r\n        c[tid].allocated += val;\r\n    }\r\n    void addDeallocated(const int tid, const int val) {\r\n        c[tid].deallocated += val;\r\n    }\r\n    void addFromPool(const int tid, const int val) {\r\n        c[tid].fromPool += val;\r\n    }\r\n    void addToPool(const int tid, const int val) {\r\n        c[tid].toPool += val;\r\n    }\r\n    void addGiven(const int tid, const int val) {\r\n        c[tid].given += val;\r\n    }\r\n    void addTaken(const int tid, const int val) {\r\n        c[tid].taken += val;\r\n    }\r\n    void addRetired(const int tid, const int val) {\r\n        c[tid].retired += val;\r\n    }\r\n    long getAllocated(const int tid) {\r\n        return c[tid].allocated;\r\n    }\r\n    long getDeallocated(const int tid) {\r\n        return c[tid].deallocated;\r\n    }\r\n    long getFromPool(const int tid) {\r\n        return c[tid].fromPool;\r\n    }\r\n    long getToPool(const int tid) {\r\n        return c[tid].toPool;\r\n    }\r\n    long getGiven(const int tid) {\r\n        return c[tid].given;\r\n    }\r\n    long getTaken(const int tid) {\r\n        return c[tid].taken;\r\n    }\r\n    long getRetired(const int tid) {\r\n        return c[tid].retired;\r\n    }\r\n    long getTotalAllocated() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getAllocated(tid);\r\n        }\r\n        return result;\r\n    }\r\n    long getTotalDeallocated() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getDeallocated(tid);\r\n        }\r\n        return result;\r\n    }\r\n    long getTotalFromPool() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getFromPool(tid);\r\n        }\r\n        return result;\r\n    }\r\n    long getTotalToPool() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getToPool(tid);\r\n        }\r\n        return result;\r\n    }\r\n    long getTotalGiven() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getGiven(tid);\r\n        }\r\n        return result;\r\n    }\r\n    long getTotalTaken() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getTaken(tid);\r\n        }\r\n        return result;\r\n    }\r\n    long getTotalRetired() {\r\n        long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += getRetired(tid);\r\n        }\r\n        return result;\r\n    }\r\n    debugInfo(int numProcesses) : NUM_PROCESSES(numProcesses) {\r\n//        c = new _memrecl_counters[numProcesses];\r\n        clear();\r\n    }\r\n    ~debugInfo() {\r\n//        delete[] c;\r\n    }\r\n};\r\n\r\n#endif\t/* DEBUG_INFO_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/debugcounter.h",
    "content": "/* \r\n * File:   debugcounter.h\r\n * Author: trbot\r\n *\r\n * Created on September 27, 2015, 4:43 PM\r\n */\r\n\r\n#ifndef DEBUGCOUNTER_H\r\n#define\tDEBUGCOUNTER_H\r\n\r\n#include <string>\r\n#include <sstream>\r\n#include \"plaf.h\"\r\nusing namespace std;\r\n\r\nclass debugCounter {\r\nprivate:\r\n    const int NUM_PROCESSES;\r\n    volatile long long * data; // data[tid*PREFETCH_SIZE_WORDS] = count for thread tid (padded to avoid false sharing)\r\npublic:\r\n    void add(const int tid, const long long val) {\r\n        data[tid*PREFETCH_SIZE_WORDS] += val;\r\n    }\r\n    void inc(const int tid) {\r\n        add(tid, 1);\r\n    }\r\n    long long get(const int tid) {\r\n        return data[tid*PREFETCH_SIZE_WORDS];\r\n    }\r\n    long long getTotal() {\r\n        long long result = 0;\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            result += get(tid);\r\n        }\r\n        return result;\r\n    }\r\n    void clear() {\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            data[tid*PREFETCH_SIZE_WORDS] = 0;\r\n        }\r\n    }\r\n    debugCounter(const int numProcesses) : NUM_PROCESSES(numProcesses) {\r\n        data = new long long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        clear();\r\n    }\r\n    ~debugCounter() {\r\n        delete[] data;\r\n    }\r\n};\r\n\r\n#endif\t/* DEBUGCOUNTER_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/debugprinting.h",
    "content": "/* \r\n * File:   debugprinting.h\r\n * Author: trbot\r\n *\r\n * Created on June 24, 2016, 12:49 PM\r\n */\r\n\r\n#ifndef DEBUGPRINTING_H\r\n#define\tDEBUGPRINTING_H\r\n\r\n#include <atomic>\r\n#include <sstream>\r\n\r\n#define COUTATOMIC(coutstr) /*cout<<coutstr*/ \\\r\n{ \\\r\n    std::stringstream ss; \\\r\n    ss<<coutstr; \\\r\n    std::cout<<ss.str(); \\\r\n}\r\n#define COUTATOMICTID(coutstr) /*cout<<\"tid=\"<<(tid<10?\" \":\"\")<<tid<<\": \"<<coutstr*/ \\\r\n{ \\\r\n    std::stringstream ss; \\\r\n    ss<<\"tid=\"<<tid<<(tid<10?\" \":\"\")<<\": \"<<coutstr; \\\r\n    std::cout<<ss.str(); \\\r\n}\r\n\r\n// define USE_TRACE if you want many paths through the code to be traced with std::cout<<\"...\" statements\r\n#ifdef USE_TRACE\r\nstd::atomic_bool ___trace(1);\r\nstd::atomic_bool ___validateops(1);\r\n#define TRACE_TOGGLE {bool ___t = ___trace; ___trace = !___t;}\r\n#define TRACE_ON {___trace = true;}\r\n#define TRACE if(___trace)\r\n#else\r\n#define TRACE if(0)\r\n#define TRACE_TOGGLE\r\n#define TRACE_ON \r\n#endif\r\n\r\n#endif\t/* DEBUGPRINTING_H */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/globals.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECORDMGR_GLOBALS_H\r\n#define\tRECORDMGR_GLOBALS_H\r\n\r\n#include \"plaf.h\"\r\n#include \"debugprinting.h\"\r\n\r\n#ifndef DEBUG\r\n#define DEBUG if(0)\r\n#define DEBUG2 if(0)\r\n#endif\r\n\r\n#ifndef MEMORY_STATS\r\n#define MEMORY_STATS if(0)\r\n#define MEMORY_STATS2 if(0)\r\n#endif\r\n\r\n// don't touch these options for crash recovery\r\n\r\n#define CRASH_RECOVERY_USING_SETJMP\r\n#define SEND_CRASH_RECOVERY_SIGNALS\r\n#define AFTER_NEUTRALIZING_SET_BIT_AND_RETURN_TRUE\r\n#define PERFORM_RESTART_IN_SIGHANDLER\r\n#define SIGHANDLER_IDENTIFY_USING_PTHREAD_GETSPECIFIC\r\n\r\n// some useful, data structure agnostic definitions\r\n\r\ntypedef bool CallbackReturn;\r\ntypedef void* CallbackArg;\r\ntypedef CallbackReturn (*CallbackType)(CallbackArg);\r\n#ifndef SOFTWARE_BARRIER\r\n#define SOFTWARE_BARRIER asm volatile(\"\": : :\"memory\")\r\n#endif\r\n\r\n#endif\t/* GLOBALS_H */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/hashtable.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef HASHTABLE_H\r\n#define\tHASHTABLE_H\r\n\r\n#include <cassert>\r\n#include <cstdlib>\r\n#include <iostream>\r\n#include \"plaf.h\"\r\nusing namespace std;\r\n\r\nnamespace hashset_namespace {\r\n// note: TABLE_SIZE must be a power of two for bitwise operations below to work\r\n#define TABLE_SIZE 32\r\n#define FIRST_INDEX(key) (hash((key)) & (TABLE_SIZE-1))\r\n#define NEXT_INDEX(ix) ((ix)+1 % TABLE_SIZE)\r\n#define EMPTY_CELL 0\r\n    template<typename K>\r\n    class hashset {\r\n        private:\r\n            bool cleared;\r\n            K* keys[TABLE_SIZE];\r\n            inline int hash(K * const key) {\r\n                // MurmurHash3's integer finalizer\r\n                long long k = (long long) key;\r\n                k ^= k >> 33;\r\n                k *= 0xff51afd7ed558ccd;\r\n                k ^= k >> 33;\r\n                k *= 0xc4ceb9fe1a85ec53;\r\n                k ^= k >> 33;\r\n                return k;\r\n            }\r\n            int getIndex(K * const key) {\r\n                int ix;\r\n                for (ix=FIRST_INDEX(key)\r\n                        ; keys[ix] != EMPTY_CELL && keys[ix] != key\r\n                        ; ix=NEXT_INDEX(ix)) {\r\n                    assert(ix >= 0);\r\n                    assert(ix < TABLE_SIZE);\r\n                }\r\n                assert(ix >= 0);\r\n                assert(ix < TABLE_SIZE);\r\n                return ix;\r\n            }\r\n        public:\r\n            hashset() {\r\n                VERBOSE DEBUG std::cout<<\"constructor hashset\"<<std::endl;\r\n                cleared = false;\r\n                clear();\r\n            }\r\n            ~hashset() {\r\n                VERBOSE DEBUG std::cout<<\"destructor hashset\"<<std::endl;\r\n            }\r\n            void clear() {\r\n                if (!cleared) {\r\n                    memset(keys, EMPTY_CELL, TABLE_SIZE*sizeof(K*));\r\n                    cleared = true;\r\n                }\r\n            }\r\n            bool contains(K * const key) {\r\n                return get(key) != EMPTY_CELL;\r\n            }\r\n            K* get(K * const key) {\r\n                return keys[getIndex(key)];\r\n            }\r\n            void insert(K * const key) {\r\n                int ix = getIndex(key);\r\n                keys[ix] = key;\r\n            }\r\n            void erase(K * const key) {\r\n                int ix = getIndex(key);\r\n                // no need for an if statement, because keys[ix] is either key or null.\r\n                keys[ix] = EMPTY_CELL;\r\n            }\r\n    } __attribute__ ((aligned(PREFETCH_SIZE_BYTES)));\r\n    \r\n//    // hash set that allows multiple readers and ONE updater.\r\n//    // i am pretty certain this is NOT linearizable.\r\n//    // note: to use this with reclaim_hazardptr_hash, this would need to\r\n//    //       be a MULTISET!!!! this is because protectObject is called multiple times,\r\n//    //       and a single unprotectObject must not unprotect the object!!!\r\n//    template<typename K>\r\n//    class AtomicHashSet {\r\n//        private:\r\n//            int size;       // NOT ATOMICALLY ACCESSIBLE BY OTHER THREADS THAN OWNER\r\n//            bool cleared;   // NOT ATOMICALLY ACCESSIBLE BY OTHER THREADS THAN OWNER\r\n//            atomic_uintptr_t keys[TABLE_SIZE];\r\n//            inline int hash(K * const key) {\r\n//                // MurmurHash3's integer finalizer\r\n//                long long k = (long long) key;\r\n//                k ^= k >> 33;\r\n//                k *= 0xff51afd7ed558ccd;\r\n//                k ^= k >> 33;\r\n//                k *= 0xc4ceb9fe1a85ec53;\r\n//                k ^= k >> 33;\r\n//                return k;\r\n//            }\r\n//            int getIndex(K * const key) {\r\n//                int ix;\r\n//                for (ix=FIRST_INDEX(key)\r\n//                        ; keys[ix] != EMPTY_CELL && keys[ix] != key\r\n//                        ; ix=NEXT_INDEX(ix)) {\r\n//                    assert(ix >= 0);\r\n//                    assert(ix < TABLE_SIZE);\r\n//                }\r\n//                assert(ix >= 0);\r\n//                assert(ix < TABLE_SIZE);\r\n//                return ix;\r\n//            }\r\n//        public:\r\n//            AtomicHashSet() {\r\n//                VERBOSE DEBUG std::cout<<\"constructor AtomicHashSet\"<<std::endl;\r\n//                cleared = false;\r\n//                clear();\r\n//            }\r\n//            ~AtomicHashSet() {\r\n//                VERBOSE DEBUG std::cout<<\"destructor AtomicHashSet\"<<std::endl;\r\n//            }\r\n//            void clear() {\r\n//                if (!cleared) {\r\n//                    memset(keys, EMPTY_CELL, TABLE_SIZE*sizeof(K*));\r\n//                    cleared = true;\r\n//                }\r\n//            }\r\n//            bool contains(K * const key) {\r\n//                return get(key) != EMPTY_CELL;\r\n//            }\r\n//            K* get(K * const key) {\r\n//                return (K*) keys[getIndex(key)].load();\r\n//            }\r\n//            void insert(K * const key) {\r\n//                int ix = getIndex(key);\r\n//                keys[ix].store(key);\r\n//                ++size;\r\n//            }\r\n//            void erase(K * const key) {\r\n//                int ix = getIndex(key);\r\n//                // no need for an if statement, because keys[ix] is either key or null.\r\n//                if (keys[ix] == EMPTY_CELL) {\r\n//                    keys[ix].store(EMPTY_CELL);\r\n//                    --size;\r\n//                }\r\n//            }\r\n//    } __attribute__ ((aligned(BYTES_IN_CACHE_LINE)));\r\n\r\n    template<typename K>\r\n    class hashset_new {\r\n    private:\r\n        int tableSize;\r\n        K** keys;\r\n        int __size;\r\n        inline long hash(K * const key) {\r\n            // MurmurHash3's integer finalizer\r\n            long long k = (long long) key;\r\n            k ^= k >> 33;\r\n            k *= 0xff51afd7ed558ccd;\r\n            k ^= k >> 33;\r\n            k *= 0xc4ceb9fe1a85ec53;\r\n            k ^= k >> 33;\r\n            return k;\r\n        }\r\n        inline int getIndex(K * const key) {\r\n            int ix = firstIndex(key);\r\n            assert(ix >= 0);\r\n            assert(ix < tableSize);\r\n            while (true) {\r\n                if (keys[ix] == EMPTY_CELL || keys[ix] == key) {\r\n                    return ix;\r\n                }\r\n                ix = nextIndex(ix);\r\n                assert(ix >= 0);\r\n                assert(ix < tableSize);\r\n            }\r\n        }\r\n        inline int firstIndex(K * const key) {\r\n            return (hash(key) & (tableSize-1));\r\n        }\r\n        inline int nextIndex(const int ix) {\r\n            return ((ix+1) & (tableSize-1));\r\n        }\r\n    public:\r\n        hashset_new(const int numberOfElements) {\r\n            tableSize = 32;\r\n            while (tableSize < numberOfElements*2) {\r\n                tableSize *= 2;\r\n            }\r\n            VERBOSE DEBUG std::cout<<\"constructor hashset_new capacity=\"<<tableSize<<std::endl;\r\n            keys = new K*[tableSize];\r\n            __size = -1;\r\n            clear();\r\n        }\r\n        ~hashset_new() {\r\n//            VERBOSE DEBUG std::cout<<\"destructor hashset_new\"<<std::endl;\r\n            delete[] keys;\r\n        }\r\n        void clear() {\r\n            if (__size) {\r\n                memset(keys, EMPTY_CELL, tableSize*sizeof(K*));\r\n                __size = 0;\r\n            }\r\n        }\r\n        bool contains(K * const key) {\r\n            return get(key) != EMPTY_CELL;\r\n        }\r\n        K* get(K * const key) {\r\n            return keys[getIndex(key)];\r\n        }\r\n        void insert(K * const key) {\r\n            int ix = getIndex(key);\r\n            if (keys[ix] == EMPTY_CELL) {\r\n                keys[ix] = key;\r\n                ++__size;\r\n                assert(__size < tableSize);\r\n            }\r\n        }\r\n        int size() {\r\n            return __size;\r\n        }\r\n    };\r\n\r\n}\r\n\r\n#endif\t/* HASHTABLE_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/lockfreeblockbag.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef LOCKFREESTACK_H\r\n#define\tLOCKFREESTACK_H\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include \"blockbag.h\"\r\nusing namespace std;\r\n\r\n#ifndef VERBOSE\r\n#define VERBOSE if(0)\r\n#endif\r\n\r\n// lock free bag that operates on elements of the block<T> type,\r\n// defined in blockbag.h. this class does NOT allocate or deallocate any memory.\r\n// instead, it simply chains blocks together using their next pointers.\r\n// the implementation is a stack, with push and pop at the head.\r\n// the aba problem is avoided using version numbers with a double-wide CAS.\r\n// any contention issues with using a simple stack and overhead issues with\r\n// double-wide CAS are unimportant, because operations on this bag only happen\r\n// once a process has filled up two blocks of objects and needs to hand one\r\n// off. thus, the number of operations on this class is several orders of\r\n// magnitude smaller than the number of operations on the binary search tree.\r\ntemplate <typename T>\r\nclass lockfreeblockbag {\r\nprivate:\r\n    struct tagged_ptr {\r\n        block<T> *ptr;\r\n        long tag;\r\n    };\r\n    std::atomic<tagged_ptr> head;\r\npublic:\r\n    lockfreeblockbag() {\r\n        VERBOSE DEBUG std::cout<<\"constructor lockfreeblockbag lockfree=\"<<head.is_lock_free()<<std::endl;\r\n        assert(head.is_lock_free());\r\n        head.store(tagged_ptr({NULL,0}));\r\n    }\r\n    ~lockfreeblockbag() {\r\n        VERBOSE DEBUG std::cout<<\"destructor lockfreeblockbag; \";\r\n        block<T> *curr = head.load(memory_order_relaxed).ptr;\r\n        int debugFreed = 0;\r\n        while (curr) {\r\n            block<T> * const temp = curr;\r\n            curr = curr->next;\r\n            //DEBUG ++debugFreed;\r\n            delete temp;\r\n        }\r\n        VERBOSE DEBUG std::cout<<\"freed \"<<debugFreed<<std::endl;\r\n    }\r\n    block<T>* getBlock() {\r\n        while (true) {\r\n            tagged_ptr expHead = head.load(memory_order_relaxed);\r\n            if (expHead.ptr != NULL) {\r\n                if (head.compare_exchange_weak(\r\n                        expHead,\r\n                        tagged_ptr({expHead.ptr->next, expHead.tag+1}))) {\r\n                    block<T> *result = expHead.ptr;\r\n                    result->next = NULL;\r\n                    return result;\r\n                }\r\n            } else {\r\n                return NULL;\r\n            }\r\n        }\r\n    }\r\n    void addBlock(block<T> *b) {\r\n        while (true) {\r\n            tagged_ptr expHead = head.load(memory_order_relaxed);\r\n            b->next = expHead.ptr;\r\n            if (head.compare_exchange_weak(\r\n                    expHead,\r\n                    tagged_ptr({b, expHead.tag+1}))) {\r\n                return;\r\n            }\r\n        }\r\n    }\r\n    // NOT thread safe\r\n    int sizeInBlocks() {\r\n        int result = 0;\r\n        block<T> *curr = head.load(memory_order_relaxed).ptr;\r\n        while (curr) {\r\n            ++result;\r\n            curr = curr->next;\r\n        }\r\n        return result;\r\n    }\r\n    // thread safe, but concurrent operations are very likely to starve it\r\n    long long size() {\r\n        while (1) {\r\n            long long result = 0;\r\n            block<T> *originalHead = head.load(memory_order_relaxed).ptr;\r\n            block<T> *curr = originalHead;\r\n            while (curr) {\r\n                result += curr->computeSize();\r\n                curr = curr->next;\r\n            }\r\n            if (head.load(memory_order_relaxed).ptr == originalHead) {\r\n                return result;\r\n            }\r\n        }\r\n    }\r\n};\r\n\r\n#endif\t/* LOCKFREESTACK_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/pool_interface.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef POOL_INTERFACE_H\r\n#define\tPOOL_INTERFACE_H\r\n\r\n#include <iostream>\r\n#include \"allocator_interface.h\"\r\n#include \"debug_info.h\"\r\n#include \"blockpool.h\"\r\n#include \"blockbag.h\"\r\nusing namespace std;\r\n\r\ntemplate <typename T = void, class Alloc = allocator_interface<T> >\r\nclass pool_interface {\r\npublic:\r\n    debugInfo * const debug;\r\n    \r\n    const int NUM_PROCESSES;\r\n    blockpool<T> **blockpools; // allocated (or not) and freed by descendants\r\n    Alloc *alloc;\r\n\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef pool_interface<_Tp1, Alloc> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef pool_interface<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    string getSizeString() { return \"\"; }\r\n//    long long getSizeInNodes() { return 0; }\r\n    /**\r\n     * if the pool contains any object, then remove one from the pool\r\n     * and return a pointer to it. otherwise, return NULL.\r\n     */\r\n    inline T* get(const int tid);\r\n    inline void add(const int tid, T* ptr);\r\n    inline void addMoveFullBlocks(const int tid, blockbag<T> *bag);\r\n    inline void addMoveAll(const int tid, blockbag<T> *bag);\r\n    inline int computeSize(const int tid);\r\n    \r\n    void debugPrintStatus(const int tid);\r\n    \r\n    pool_interface(const int numProcesses, Alloc * const _alloc, debugInfo * const _debug)\r\n            : debug(_debug) \r\n            , NUM_PROCESSES(numProcesses)\r\n            , alloc(_alloc){\r\n        VERBOSE DEBUG std::cout<<\"constructor pool_interface\"<<std::endl;\r\n        this->blockpools = new blockpool<T>*[numProcesses];\r\n        for (int tid=0;tid<numProcesses;++tid) {\r\n            this->blockpools[tid] = new blockpool<T>();\r\n        }\r\n    }\r\n    ~pool_interface() {\r\n        VERBOSE DEBUG std::cout<<\"destructor pool_interface\"<<std::endl;\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            delete this->blockpools[tid];\r\n        }\r\n        delete[] this->blockpools;\r\n    }\r\n};\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/pool_none.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef POOL_NOOP_H\r\n#define\tPOOL_NOOP_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include \"blockbag.h\"\r\n#include \"blockpool.h\"\r\n#include \"pool_interface.h\"\r\n#include \"plaf.h\"\r\nusing namespace std;\r\n\r\ntemplate <typename T = void, class Alloc = allocator_interface<T> >\r\nclass pool_none : public pool_interface<T, Alloc> {\r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef pool_none<_Tp1, Alloc> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef pool_none<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    string getSizeString() { return \"no pool\"; }\r\n    /**\r\n     * if the freebag contains any object, then remove one from the freebag\r\n     * and return a pointer to it.\r\n     * if not, then retrieve a new object from Alloc\r\n     */\r\n    inline T* get(const int tid) {\r\n        MEMORY_STATS2 this->alloc->debug->addFromPool(tid, 1);\r\n        return this->alloc->allocate(tid);\r\n    }\r\n    inline void add(const int tid, T* ptr) {\r\n        this->alloc->deallocate(tid, ptr);\r\n    }\r\n    inline void addMoveFullBlocks(const int tid, blockbag<T> *bag, block<T> * const predecessor) {\r\n        bag->clearWithoutFreeingElements();\r\n        // note: this will leak memory, but i believe it is only used by debraplus (which really should use a pool)\r\n    }\r\n    inline void addMoveFullBlocks(const int tid, blockbag<T> *bag) {\r\n        this->alloc->deallocateAndClear(tid, bag);\r\n//        T* ptr;\r\n//        while (ptr = bag->remove()) {\r\n//            add(tid, ptr);\r\n//        }\r\n    }\r\n    inline void addMoveAll(const int tid, blockbag<T> *bag) {\r\n        this->alloc->deallocateAndClear(tid, bag);\r\n//        T* ptr;\r\n//        while (ptr = bag->remove()) {\r\n//            add(tid, ptr);\r\n//        }\r\n    }\r\n    inline int computeSize(const int tid) {\r\n        return 0;\r\n    }\r\n    \r\n    void debugPrintStatus(const int tid) {\r\n\r\n    }\r\n    \r\n    pool_none(const int numProcesses, Alloc * const _alloc, debugInfo * const _debug)\r\n            : pool_interface<T, Alloc>(numProcesses, _alloc, _debug) {\r\n        VERBOSE DEBUG std::cout<<\"constructor pool_none\"<<std::endl;\r\n    }\r\n    ~pool_none() {\r\n        VERBOSE DEBUG std::cout<<\"destructor pool_none\"<<std::endl;\r\n    }\r\n};\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/pool_perthread_and_shared.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef POOL_PERTHREAD_AND_SHARED_H\r\n#define\tPOOL_PERTHREAD_AND_SHARED_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include <sstream>\r\n#include \"blockbag.h\"\r\n#include \"blockpool.h\"\r\n#include \"pool_interface.h\"\r\n#include \"plaf.h\"\r\n#include \"globals.h\"\r\nusing namespace std;\r\n\r\n#define POOL_THRESHOLD_IN_BLOCKS 10\r\n\r\ntemplate <typename T = void, class Alloc = allocator_interface<T> >\r\nclass pool_perthread_and_shared : public pool_interface<T, Alloc> {\r\nprivate:\r\n    lockfreeblockbag<T> *sharedBag;       // shared bag that we offload blocks on when we have too many in our freeBag\r\n    blockbag<T> **freeBag;                // freeBag[tid] = bag of objects of type T that are ready to be reused by the thread with id tid\r\n\r\n    // note: only does something if freeBag contains at least two full blocks\r\n    inline bool tryGiveFreeObjects(const int tid) {\r\n        if (freeBag[tid]->getSizeInBlocks() >= POOL_THRESHOLD_IN_BLOCKS) {\r\n            block<T> *b = freeBag[tid]->removeFullBlock(); // returns NULL if freeBag has < 2 full blocks\r\n            assert(b);\r\n//            if (b) {\r\n                sharedBag->addBlock(b);\r\n                MEMORY_STATS this->debug->addGiven(tid, 1);\r\n                //DEBUG2 COUTATOMIC(\"  thread \"<<this->tid<<\" sharedBag(\"<<(sizeof(T)==sizeof(Node<long,long>)?\"Node\":\"SCXRecord\")<<\") now contains \"<<sharedBag->size()<<\" blocks\"<<std::endl);\r\n//            }\r\n            return true;\r\n        }\r\n        return false;\r\n    }\r\n//    \r\n//    inline void tryTakeFreeObjects(const int tid) {\r\n//        block<T> *b = sharedBag->getBlock();\r\n//        if (b) {\r\n//            freeBag[tid]->addFullBlock(b);\r\n//            DEBUG this->debug->addTaken(tid, 1);\r\n//            //DEBUG2 COUTATOMIC(\"  thread \"<<this->tid<<\" took \"<<b->computeSize()<<\" objects from sharedBag\"<<std::endl);\r\n//        }\r\n//    }\r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef pool_perthread_and_shared<_Tp1, Alloc> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef pool_perthread_and_shared<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n//    long long getSizeInNodes() {\r\n//        long long sum = 0;\r\n//        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n//            sum += freeBag[tid]->computeSize();\r\n//        }\r\n////        sum += sharedBag->sizeInBlocks() * BLOCK_SIZE;\r\n//        return sum;\r\n//    }\r\n    string getSizeString() {\r\n        stringstream ss;\r\n        long long insharedbag = sharedBag->size();\r\n        long long infreebags = 0;\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            infreebags += freeBag[tid]->computeSize();\r\n        }\r\n        ss<<infreebags<<\" in free bags and \"<<insharedbag<<\" in the shared bag\";\r\n        return ss.str();\r\n    }\r\n    \r\n    /**\r\n     * if the freebag contains any object, then remove one from the freebag\r\n     * and return a pointer to it.\r\n     * if not, then retrieve a new object from Alloc\r\n     */\r\n    inline T* get(const int tid) {\r\n        MEMORY_STATS2 this->alloc->debug->addFromPool(tid, 1);\r\n        return freeBag[tid]->template remove<Alloc>(tid, sharedBag, this->alloc);\r\n    }\r\n    inline void add(const int tid, T* ptr) {\r\n        MEMORY_STATS2 this->debug->addToPool(tid, 1);\r\n        freeBag[tid]->add(tid, ptr, sharedBag, POOL_THRESHOLD_IN_BLOCKS, this->alloc);\r\n    }\r\n    inline void addMoveFullBlocks(const int tid, blockbag<T> *bag, block<T> * const predecessor) {\r\n        // WARNING: THE FOLLOWING DEBUG COMPUTATION GETS THE WRONG NUMBER OF BLOCKS.\r\n        MEMORY_STATS2 this->debug->addToPool(tid, (bag->getSizeInBlocks()-1)*BLOCK_SIZE);\r\n        freeBag[tid]->appendMoveFullBlocks(bag, predecessor);\r\n        while (tryGiveFreeObjects(tid)) {}\r\n    }\r\n    inline void addMoveFullBlocks(const int tid, blockbag<T> *bag) {\r\n        // WARNING: THE FOLLOWING DEBUG COMPUTATION GETS THE WRONG NUMBER OF BLOCKS.\r\n        MEMORY_STATS2 this->debug->addToPool(tid, (bag->getSizeInBlocks()-1)*BLOCK_SIZE);\r\n        freeBag[tid]->appendMoveFullBlocks(bag);\r\n        while (tryGiveFreeObjects(tid)) {}\r\n    }\r\n    inline void addMoveAll(const int tid, blockbag<T> *bag) {\r\n        MEMORY_STATS2 this->debug->addToPool(tid, bag->computeSize());\r\n        freeBag[tid]->appendMoveAll(bag);\r\n        while (tryGiveFreeObjects(tid)) {}\r\n    }\r\n    inline int computeSize(const int tid) {\r\n        return freeBag[tid]->computeSize();\r\n    }\r\n    \r\n    void debugPrintStatus(const int tid) {\r\n//        long free = computeSize(tid);\r\n//        long share = sharedBag->sizeInBlocks();\r\n//        COUTATOMIC(\"free=\"<<free<<\" share=\"<<share);\r\n    }\r\n    \r\n    pool_perthread_and_shared(const int numProcesses, Alloc * const _alloc, debugInfo * const _debug)\r\n            : pool_interface<T, Alloc>(numProcesses, _alloc, _debug) {\r\n        VERBOSE DEBUG COUTATOMIC(\"constructor pool_perthread_and_shared\"<<std::endl);\r\n        freeBag = new blockbag<T>*[numProcesses];\r\n        for (int tid=0;tid<numProcesses;++tid) {\r\n            freeBag[tid] = new blockbag<T>(tid, this->blockpools[tid]);\r\n        }\r\n        sharedBag = new lockfreeblockbag<T>();\r\n    }\r\n    ~pool_perthread_and_shared() {\r\n        VERBOSE DEBUG COUTATOMIC(\"destructor pool_perthread_and_shared\"<<std::endl);\r\n        // clean up shared bag\r\n        const int dummyTid = 0;\r\n        block<T> *fullBlock;\r\n        while ((fullBlock = sharedBag->getBlock()) != NULL) {\r\n            while (!fullBlock->isEmpty()) {\r\n                T * const ptr = fullBlock->pop();\r\n                this->alloc->deallocate(dummyTid, ptr);\r\n            }\r\n            this->blockpools[dummyTid]->deallocateBlock(fullBlock);\r\n        }\r\n        // clean up free bags\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            this->alloc->deallocateAndClear(tid, freeBag[tid]);\r\n            delete freeBag[tid];\r\n        }\r\n        delete[] freeBag;\r\n        delete sharedBag;\r\n    }\r\n};\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/reclaimer_debra.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECLAIM_EPOCH_H\r\n#define\tRECLAIM_EPOCH_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include <sstream>\r\n#include <limits.h>\r\n#include \"blockbag.h\"\r\n#include \"plaf.h\"\r\n#include \"allocator_interface.h\"\r\n#include \"reclaimer_interface.h\"\r\nusing namespace std;\r\n\r\n\r\n\r\ntemplate <typename T = void, class Pool = pool_interface<T> >\r\nclass reclaimer_debra : public reclaimer_interface<T, Pool> {\r\nprotected:\r\n#define EPOCH_INCREMENT 2\r\n#define BITS_EPOCH(ann) ((ann)&~(EPOCH_INCREMENT-1))\r\n#define QUIESCENT(ann) ((ann)&1)\r\n#define GET_WITH_QUIESCENT(ann) ((ann)|1)\r\n\r\n#ifdef RAPID_RECLAMATION\r\n#define MIN_OPS_BEFORE_READ 1\r\n//#define MIN_OPS_BEFORE_CAS_EPOCH 1\r\n#else\r\n#define MIN_OPS_BEFORE_READ 20\r\n//#define MIN_OPS_BEFORE_CAS_EPOCH 100\r\n#endif\r\n    \r\n#define NUMBER_OF_EPOCH_BAGS 9\r\n#define NUMBER_OF_ALWAYS_EMPTY_EPOCH_BAGS 3\r\n    \r\n    // for epoch based reclamation\r\n    volatile long epoch;\r\n    atomic_long *announcedEpoch;        // announcedEpoch[tid*PREFETCH_SIZE_WORDS] // todo: figure out if volatile here would help processes notice changes more quickly.\r\n    long *checked;                      // checked[tid*PREFETCH_SIZE_WORDS] = how far we've come in checking the announced epochs of other threads\r\n    blockbag<T> **epochbags;            // epochbags[NUMBER_OF_EPOCH_BAGS*tid+0..NUMBER_OF_EPOCH_BAGS*tid+(NUMBER_OF_EPOCH_BAGS-1)] are epoch bags for thread tid.\r\n    blockbag<T> **currentBag;           // pointer to current epoch bag for each process\r\n    long *index;                        // index of currentBag in epochbags for each process\r\n    // note: oldest bag is number (index+1)%NUMBER_OF_EPOCH_BAGS\r\n    long *opsSinceRead;\r\n    \r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef reclaimer_debra<_Tp1, Pool> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef reclaimer_debra<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n//    inline int getOldestBlockbagIndexOffset(const int tid) {\r\n//        long long min_val = LLONG_MAX;\r\n//        int min_i = -1;\r\n//        for (int i=0;i<NUMBER_OF_EPOCH_BAGS;++i) {\r\n//            long long reclaimCount = epochbags[tid*NUMBER_OF_EPOCH_BAGS+i]->getReclaimCount();\r\n//            if (reclaimCount % 1) { // bag's contents are currently being freed\r\n//                return i;\r\n//            }\r\n//            if (reclaimCount < min_val) {\r\n//                min_val = reclaimCount;\r\n//                min_i = i;\r\n//            }\r\n//        }\r\n//        return min_i;\r\n//    }\r\n//    \r\n//    inline set_of_bags<T> getBlockbags() { // blockbag_iterator<T> ** const output) {\r\n////        int cnt=0;\r\n////        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n////            for (int j=0;j<NUMBER_OF_EPOCH_BAGS;++j) {\r\n////                output[cnt++] = epochbags[NUMBER_OF_EPOCH_BAGS*tid+j];\r\n////            }\r\n////        }\r\n////        return cnt;\r\n//        return {epochbags, this->NUM_PROCESSES*NUMBER_OF_EPOCH_BAGS};\r\n//    }\r\n//    \r\n//    inline void getOldestTwoBlockbags(const int tid, blockbag<T> ** oldest, blockbag<T> ** secondOldest) {\r\n//        long long min_val = LLONG_MAX;\r\n//        int min_i = -1;\r\n//        for (int i=0;i<NUMBER_OF_EPOCH_BAGS;++i) {\r\n//            long long reclaimCount = epochbags[tid*NUMBER_OF_EPOCH_BAGS+i]->getReclaimCount();\r\n//            if (reclaimCount % 1) { // bag's contents are currently being freed\r\n//                min_i = i;\r\n//                break;\r\n//            }\r\n//            if (reclaimCount < min_val) {\r\n//                min_val = reclaimCount;\r\n//                min_i = i;\r\n//            }\r\n//        }\r\n//        if (min_i == -1) {\r\n//            *oldest = *secondOldest = NULL;\r\n//        } else {\r\n//            *oldest = epochbags[tid*NUMBER_OF_EPOCH_BAGS + min_i];\r\n//            *secondOldest = epochbags[tid*NUMBER_OF_EPOCH_BAGS + ((min_i+1)%NUMBER_OF_EPOCH_BAGS)];\r\n//        }\r\n//    }\r\n    \r\n    inline void getSafeBlockbags(const int tid, blockbag<T> ** bags) {\r\n        SOFTWARE_BARRIER;\r\n        int ix = index[tid*PREFETCH_SIZE_WORDS];\r\n        bags[0] = epochbags[tid*NUMBER_OF_EPOCH_BAGS+ix];\r\n        bags[1] = epochbags[tid*NUMBER_OF_EPOCH_BAGS+((ix+NUMBER_OF_EPOCH_BAGS-1)%NUMBER_OF_EPOCH_BAGS)];\r\n        bags[2] = epochbags[tid*NUMBER_OF_EPOCH_BAGS+((ix+NUMBER_OF_EPOCH_BAGS-2)%NUMBER_OF_EPOCH_BAGS)];\r\n        bags[3] = NULL;\r\n        SOFTWARE_BARRIER;\r\n        \r\n//        SOFTWARE_BARRIER;\r\n//        // find first dangerous blockbag\r\n//        long long min_val = LLONG_MAX;\r\n//        int min_i = -1;\r\n//        for (int i=0;i<NUMBER_OF_EPOCH_BAGS;++i) {\r\n//            long long reclaimCount = epochbags[tid*NUMBER_OF_EPOCH_BAGS+i]->getReclaimCount();\r\n//            if (reclaimCount % 1) { // bag's contents are currently being freed\r\n//                min_i = i;\r\n//                break;\r\n//            }\r\n//            if (reclaimCount < min_val) {\r\n//                min_val = reclaimCount;\r\n//                min_i = i;\r\n//            }\r\n//        }\r\n//        assert(min_i != -1);\r\n//        min_i = (min_i + NUMBER_OF_ALWAYS_EMPTY_EPOCH_BAGS) % NUMBER_OF_EPOCH_BAGS;\r\n//        \r\n//        // process might free from bag at offset min_i, or the next one.\r\n//        // the others are safe.\r\n//        int i;\r\n//        for (i=0;i<NUMBER_OF_EPOCH_BAGS-NUMBER_OF_UNSAFE_EPOCH_BAGS;++i) {\r\n//            bags[i] = epochbags[tid*NUMBER_OF_EPOCH_BAGS + ((min_i + NUMBER_OF_UNSAFE_EPOCH_BAGS + i)%NUMBER_OF_EPOCH_BAGS)];\r\n//        }\r\n//        bags[i] = NULL; // null terminated array\r\n//        \r\n////        bags[0] = epochbags[tid*NUMBER_OF_EPOCH_BAGS + ((min_i + NUMBER_OF_UNSAFE_EPOCH_BAGS)%NUMBER_OF_EPOCH_BAGS)];\r\n////        bags[1] = NULL; // null terminated array\r\n////        bags[0] = NULL;\r\n//\r\n//        SOFTWARE_BARRIER; \r\n\r\n//        SOFTWARE_BARRIER;\r\n//        /**\r\n//         * find first dangerous blockbag.\r\n//         * a process may free bag index+i+NUMBER_OF_ALWAYS_EMPTY_EPOCH_BAGS,\r\n//         * where i=1,2,...,(NUMBER_OF_EPOCH_BAGS - NUMBER_OF_ALWAYS_EMPTY_EPOCH_BAGS).\r\n//         * the rest are safe, and\r\n//         * MUST contain all nodes retired in this epoch or the last.\r\n//         */\r\n//        int ix = (index[tid*PREFETCH_SIZE_WORDS]+1+NUMBER_OF_ALWAYS_EMPTY_EPOCH_BAGS) % NUMBER_OF_EPOCH_BAGS;\r\n//        SOFTWARE_BARRIER;\r\n//        int i;\r\n//        // #safebags = total - #unsafe\r\n//        for (i=0;i<NUMBER_OF_EPOCH_BAGS-NUMBER_OF_UNSAFE_EPOCH_BAGS;++i) {\r\n//            // find i-th safe bag\r\n//            int ix2 = (ix+NUMBER_OF_UNSAFE_EPOCH_BAGS+i)%NUMBER_OF_EPOCH_BAGS; // UNFINISHED CODE FROM HERE DOWN\r\n//            bags[i] = epochbags[tid*NUMBER_OF_EPOCH_BAGS + ix2];\r\n//        }\r\n//        bags[i] = NULL; // null terminated array\r\n//        SOFTWARE_BARRIER;\r\n    }\r\n    \r\n    long long getSizeInNodes() {\r\n        long long sum = 0;\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            for (int j=0;j<NUMBER_OF_EPOCH_BAGS;++j) {\r\n                sum += epochbags[NUMBER_OF_EPOCH_BAGS*tid+j]->computeSize();\r\n            }\r\n        }\r\n        return sum;\r\n    }\r\n    string getSizeString() {\r\n        stringstream ss;\r\n        ss<<getSizeInNodes()<<\" in epoch bags\";\r\n        return ss.str();\r\n    }\r\n    \r\n    inline static bool quiescenceIsPerRecordType() { return false; }\r\n    \r\n    inline bool isQuiescent(const int tid) {\r\n        return QUIESCENT(announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed));\r\n    }\r\n\r\n    inline static bool isProtected(const int tid, T * const obj) {\r\n        return true;\r\n    }\r\n    inline static bool isQProtected(const int tid, T * const obj) {\r\n        return false;\r\n    }\r\n    inline static bool protect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void unprotect(const int tid, T * const obj) {}\r\n    inline static bool qProtect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void qUnprotectAll(const int tid) {}\r\n    \r\n    inline static bool shouldHelp() { return true; }\r\n    \r\n    // rotate the epoch bags and reclaim any objects retired two epochs ago.\r\n    inline void rotateEpochBags(const int tid) {\r\n        int nextIndex = (index[tid*PREFETCH_SIZE_WORDS]+1) % NUMBER_OF_EPOCH_BAGS;\r\n        blockbag<T> * const freeable = epochbags[NUMBER_OF_EPOCH_BAGS*tid + ((nextIndex+NUMBER_OF_ALWAYS_EMPTY_EPOCH_BAGS) % NUMBER_OF_EPOCH_BAGS)];\r\n        this->pool->addMoveFullBlocks(tid, freeable); // moves any full blocks (may leave a non-full block behind)\r\n        SOFTWARE_BARRIER;\r\n        index[tid*PREFETCH_SIZE_WORDS] = nextIndex;\r\n        currentBag[tid*PREFETCH_SIZE_WORDS] = epochbags[NUMBER_OF_EPOCH_BAGS*tid + nextIndex];\r\n    }\r\n\r\n    // objects reclaimed by this epoch manager.\r\n    // returns true if the call rotated the epoch bags for thread tid\r\n    // (and reclaimed any objects retired two epochs ago).\r\n    // otherwise, the call returns false.\r\n    inline bool leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers) {\r\n        SOFTWARE_BARRIER; // prevent any bookkeeping from being moved after this point by the compiler.\r\n        bool result = false;\r\n\r\n        // ver 1\r\n        long readEpoch = epoch;\r\n        const long ann = announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n//        // debug ver2\r\n//        const long ann = announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n//        ++opsSinceRead[tid*PREFETCH_SIZE_WORDS];\r\n//        long readEpoch = ((opsSinceRead[tid*PREFETCH_SIZE_WORDS] % MIN_OPS_BEFORE_READ) == 0) ? epoch : BITS_EPOCH(ann);\r\n\r\n        // if our announced epoch is different from the current epoch\r\n        if (readEpoch != BITS_EPOCH(ann)) {\r\n            // announce the new epoch, and rotate the epoch bags and\r\n            // reclaim any objects retired two epochs ago.\r\n            checked[tid*PREFETCH_SIZE_WORDS] = 0;\r\n            //rotateEpochBags(tid);\r\n            for (int i=0;i<numReclaimers;++i) {\r\n                ((reclaimer_debra<T, Pool> * const) reclaimers[i])->rotateEpochBags(tid);\r\n            }\r\n            result = true;\r\n        }\r\n        // note: readEpoch, when written to announcedEpoch[tid],\r\n        //       will set the state to non-quiescent and non-neutralized\r\n\r\n        // incrementally scan the announced epochs of all threads\r\n        int otherTid = checked[tid*PREFETCH_SIZE_WORDS];\r\n        if ((++opsSinceRead[tid*PREFETCH_SIZE_WORDS] % MIN_OPS_BEFORE_READ) == 0) {\r\n            long otherAnnounce = announcedEpoch[otherTid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n            if (BITS_EPOCH(otherAnnounce) == readEpoch\r\n                    || QUIESCENT(otherAnnounce)) {\r\n                const int c = ++checked[tid*PREFETCH_SIZE_WORDS];\r\n                if (c >= this->NUM_PROCESSES /*&& c > MIN_OPS_BEFORE_CAS_EPOCH*/) {\r\n                    __sync_bool_compare_and_swap(&epoch, readEpoch, readEpoch+EPOCH_INCREMENT);\r\n                }\r\n            }\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        if (readEpoch != ann) {\r\n            announcedEpoch[tid*PREFETCH_SIZE_WORDS].store(readEpoch, memory_order_relaxed);\r\n        }\r\n        return result;\r\n    }\r\n    \r\n    inline void enterQuiescentState(const int tid) {\r\n        const long ann = announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n        announcedEpoch[tid*PREFETCH_SIZE_WORDS].store(GET_WITH_QUIESCENT(ann), memory_order_relaxed);\r\n    }\r\n    \r\n    // for all schemes except reference counting\r\n    inline void retire(const int tid, T* p) {\r\n        currentBag[tid*PREFETCH_SIZE_WORDS]->add(p);\r\n        DEBUG2 this->debug->addRetired(tid, 1);\r\n    }\r\n    \r\n    inline void unretireLast(const int tid) {\r\n        assert(false); // we do not use this, since it makes it harder to reason about iteration over blockbags when they shrink (aside from when their contents are being reclaimed, and we can determine this is the case by inspecting bag->getReclaimCount()...)\r\n        currentBag[tid*PREFETCH_SIZE_WORDS]->remove();\r\n    }\r\n\r\n    void debugPrintStatus(const int tid) {\r\n//        assert(tid >= 0);\r\n//        assert(tid < this->NUM_PROCESSES);\r\n        if (tid == 0) {\r\n            std::cout<<\"global epoch counter=\"<<epoch<<std::endl;\r\n        }\r\n//        long announce = announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n//        std::cout<<\"tid=\"<<tid<<\": announce=\"<<announce<<\" bags(\";\r\n//        for (int i=0;i<NUMBER_OF_EPOCH_BAGS;++i) {\r\n//            std::cout<<(i?\",\":\"\")<</*\" bag\"<<i<<\"=\"<<*/epochbags[NUMBER_OF_EPOCH_BAGS*tid+i]->computeSize();\r\n//        }\r\n//        std::cout<<\")\"<<std::endl;\r\n    }\r\n\r\n    reclaimer_debra(const int numProcesses, Pool *_pool, debugInfo * const _debug, RecoveryMgr<void *> * const _recoveryMgr = NULL)\r\n            : reclaimer_interface<T, Pool>(numProcesses, _pool, _debug, _recoveryMgr) {\r\n        VERBOSE std::cout<<\"constructor reclaimer_debra helping=\"<<this->shouldHelp()<<std::endl;// scanThreshold=\"<<scanThreshold<<std::endl;\r\n        epoch = 0;\r\n        epochbags = new blockbag<T>*[NUMBER_OF_EPOCH_BAGS*numProcesses];\r\n        currentBag = new blockbag<T>*[numProcesses*PREFETCH_SIZE_WORDS];\r\n        index = new long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        opsSinceRead = new long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        announcedEpoch = new atomic_long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        checked = new long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        for (int tid=0;tid<numProcesses;++tid) {\r\n            for (int i=0;i<NUMBER_OF_EPOCH_BAGS;++i) {\r\n                epochbags[NUMBER_OF_EPOCH_BAGS*tid+i] = new blockbag<T>(tid, this->pool->blockpools[tid]);\r\n            }\r\n            currentBag[tid*PREFETCH_SIZE_WORDS] = epochbags[NUMBER_OF_EPOCH_BAGS*tid];\r\n            index[tid*PREFETCH_SIZE_WORDS] = 0;\r\n            opsSinceRead[tid*PREFETCH_SIZE_WORDS] = 0;\r\n            announcedEpoch[tid*PREFETCH_SIZE_WORDS].store(GET_WITH_QUIESCENT(0), memory_order_relaxed);\r\n            checked[tid*PREFETCH_SIZE_WORDS] = 0;\r\n        }\r\n    }\r\n    ~reclaimer_debra() {\r\n        VERBOSE DEBUG std::cout<<\"destructor reclaimer_debra\"<<std::endl;\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            // move contents of all bags into pool\r\n            for (int i=0;i<NUMBER_OF_EPOCH_BAGS;++i) {\r\n//                std::cout<<\"main thread: moving \"<<epochbags[NUMBER_OF_EPOCH_BAGS*tid+i]->computeSize()<<\" objects from epoch bag of tid=\"<<tid<<\" to pool\"<<std::endl;\r\n                this->pool->addMoveAll(tid, epochbags[NUMBER_OF_EPOCH_BAGS*tid+i]);\r\n                delete epochbags[NUMBER_OF_EPOCH_BAGS*tid+i];\r\n            }\r\n        }\r\n        delete[] epochbags;\r\n        delete[] index;\r\n        delete[] opsSinceRead;\r\n        delete[] currentBag;\r\n        delete[] announcedEpoch;\r\n        delete[] checked;\r\n    }\r\n\r\n};\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/reclaimer_debraplus.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECLAIM_EPOCH_CRASHRECOV_H\r\n#define\tRECLAIM_EPOCH_CRASHRECOV_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include \"plaf.h\"\r\n#include \"globals.h\"\r\n#include \"blockbag.h\"\r\n#include \"allocator_interface.h\"\r\n#include \"reclaimer_interface.h\"\r\n#include \"arraylist.h\"\r\n#include \"hashtable.h\"\r\n#include \"record_manager_single_type.h\"\r\nusing namespace std;\r\nusing namespace hashset_namespace;\r\n\r\ntemplate <typename T = void, class Pool = pool_interface<T> >\r\nclass reclaimer_debraplus : public reclaimer_interface<T, Pool> {\r\nprivate:\r\n#define EPOCH_INCREMENT 2\r\n#define BITS_EPOCH(ann) ((ann)&~(EPOCH_INCREMENT-1))\r\n#define QUIESCENT(ann) ((ann)&1)\r\n#define GET_WITH_QUIESCENT(ann) ((ann)|1)\r\n// the following threshold allows a process to accumulate about 768 objects in each epoch bag\r\n// (3*BLOCK_SIZE=768, but there are other things that inflate bag size slightly, such as\r\n//  the fact that a thread can do n operations before it successfully neutralizes each thread\r\n//  and can advance the epoch.)\r\n#define NEUTRALIZE_THRESHOLD_IN_BLOCKS 4\r\n// maximum number of objects that can be simultaneously protected by calls to qProtect()\r\n#define MAX_PROTECT_EVEN_IF_QUIESCENT 7\r\n\r\n#define MINIMUM_OPERATIONS_BEFORE_NEW_EPOCH_CR 100\r\n#define NUMBER_OF_EPOCH_BAGS_CR 3\r\n    // for epoch based reclamation\r\n    volatile long epoch;\r\n    atomic_long *announcedEpoch;        // announcedEpoch[tid*PREFETCH_SIZE_WORDS] = bits 1..end contain the last epoch seen by thread tid, and bit 0 indicates quiescence\r\n    long *checked;                      // checked[tid*PREFETCH_SIZE_WORDS] = how far we've come in checking the announced epochs of other threads\r\n    blockbag<T> **epochbags;            // epochbags[NUMBER_OF_EPOCH_BAGS*tid+0..NUMBER_OF_EPOCH_BAGS*tid+(NUMBER_OF_EPOCH_BAGS-1)] are epoch bags for thread tid.\r\n    blockbag<T> **currentBag;           // pointer to current epoch bag for each process\r\n    long *index;                        // index of currentBag in epochbags for each process\r\n    // note: oldest bag is number (index+1)%NUMBER_OF_EPOCH_BAGS_CR\r\n\r\n    // for hazard pointer component of this scheme;\r\n    // each thread has a single hazard pointer that it uses to prevent\r\n    // other threads from reclaiming its current scx record before it can\r\n    // clean up after itself.\r\n    AtomicArrayList<T> **announce;         // announce[tid] = pointer to set of hazard pointers for thread tid\r\n    hashset_new<T> **comparing;         // comparing[tid] = set of announced hazard pointers for ALL threads, as collected by thread tid during it's last retire(tid, ...) call\r\n\r\n    // number of blocks retired[tid] must contain before it is guaranteed to\r\n    // contain at least 5*numProcesses*MAX_PROTECT_EVEN_IF_QUIESCENT items...\r\n    // why 5*numProcesses*MAX_PROTECT_EVEN_IF_QUIESCENT items?\r\n    // to get amortized constant scanning time per object,\r\n    // the number of elements that retired[tid] must contain\r\n    // before we scan hazard pointers to determine\r\n    // which elements of retired[tid] can be deallocated\r\n    // must be nk+Omega(nk), where\r\n    //      n = number of threads and\r\n    //      k = max number of hazard pointers a thread can hold at once\r\n    // in this context, k=MAX_PROTECT_EVEN_IF_QUIESCENT, since a thread only obtains\r\n    // a hazard pointer to the scx record it has most recently created, and\r\n    // the nodes it points to. so, we just need some constant times\r\n    // numProcesses*MAX_PROTECT_EVEN_IF_QUIESCENT.\r\n    static const int scanThreshold = 4;\r\n\r\n    sigset_t neutralizeSignalSet;\r\n    \r\n    inline bool neutralizeOther(const int tid, const int otherTid, const long currentEpoch, const long announceOther) {\r\n#ifdef SEND_CRASH_RECOVERY_SIGNALS\r\n        assert(isQuiescent(tid));\r\n        assert(otherTid != tid);\r\n        // if the epoch bag is too full, then we suspect otherTid has crashed...\r\n        if (epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid+index[tid*PREFETCH_SIZE_WORDS]]->getSizeInBlocks() >= NEUTRALIZE_THRESHOLD_IN_BLOCKS) {\r\n            \r\n            // neutralize otherTid by sending him a signal to make him\r\n            // change what his next step will be, and force him to\r\n            // throw away all pointers into the data structure, and\r\n            // leaveQstate again before re-acquiring any pointers into\r\n            // the data structure. this lets us reclaim memory without\r\n            // waiting for him to progress.\r\n            pthread_t otherPthread = this->recoveryMgr->getPthread(otherTid);\r\n            int error = 0;\r\n//                COUTATOMICTID(\"sending signal to tid \"<<otherTid<<std::endl);\r\n\r\n            if (error = pthread_kill(otherPthread, this->recoveryMgr->neutralizeSignal)) {\r\n                // should never happen\r\n                for (int i=0;i<20;++i) COUTATOMICTID(\"######################################################\"<<std::endl);\r\n                COUTATOMICTID(\"error \"<<error<<\" when trying to pthread_kill(pthread_tFor(\"<<otherTid<<\"), \"<<this->recoveryMgr->neutralizeSignal<<\")\"<<std::endl);\r\n                assert(isQuiescent(tid));\r\n                const long newann = announcedEpoch[otherTid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n                COUTATOMICTID(\"otherThread has newann=\"<<newann<<\" with quiescent bit \"<<QUIESCENT(newann)<<std::endl);\r\n                // this can happen because otherTid has terminated.\r\n                // if otherTid is now quiescent, then we can return true...\r\n                if (QUIESCENT(newann)) return true;\r\n                return false;\r\n            } else {\r\n#ifdef AFTER_NEUTRALIZING_WAIT_FOR_QUIESCENCE\r\n                // debug technique: wait until otherTid is\r\n                // either quiescent or has updated its announced epoch.\r\n                for (;;) {\r\n                    TRACE COUTATOMICTID(\"thread \"<<tid<<\" waiting for quiescence of thread \"<<otherTid<<std::endl);\r\n                    __sync_synchronize();\r\n                    const long newann = announcedEpoch[otherTid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n                    if (QUIESCENT(newann) || BITS_EPOCH(newann) != BITS_EPOCH(announceOther)) {\r\n                        return true;\r\n                    }\r\n                }\r\n#endif\r\n#ifdef AFTER_NEUTRALIZING_SET_BIT_AND_RETURN_TRUE\r\n                assert(isQuiescent(tid));\r\n                return true;\r\n#endif\r\n            }\r\n        }\r\n        assert(isQuiescent(tid));\r\n#endif\r\n        return false;\r\n    }\r\n    \r\npublic:\r\n    \r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef reclaimer_debraplus<_Tp1, Pool> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef reclaimer_debraplus<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    inline static bool quiescenceIsPerRecordType() { return false; }\r\n    inline static bool supportsCrashRecovery() { return true; }\r\n    inline bool isQuiescent(const int tid) {\r\n        //COUTATOMICTID(\"IS QUIESCENT EXECUTED\"<<std::endl);\r\n        return QUIESCENT(announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed));\r\n    }\r\n    \r\n    inline static bool isProtected(const int tid, T * const obj) {\r\n        return true;\r\n    }\r\n    \r\n    inline static bool protect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void unprotect(const int tid, T * const obj) {}\r\n    \r\n    inline bool isQProtected(const int tid, T * const obj) {\r\n        return announce[tid]->contains(obj); // this is inefficient, but should only happen when recovering from being neutralized...\r\n    }\r\n    inline bool qProtect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        TRACE COUTATOMICTID(\"reclaimer_debraplus::protectObjectEvenIfQuiescent(tid=\"<<tid<</*\", \"<<*obj<<*/\")\"<<std::endl);\r\n        int __size; DEBUG __size = announce[tid]->size();\r\n        DEBUG assert(__size < MAX_PROTECT_EVEN_IF_QUIESCENT);\r\n        announce[tid]->add(obj);\r\n        assert(announce[tid]->contains(obj));\r\n        DEBUG assert(announce[tid]->size() == __size+1);\r\n        // if callbackArg = NULL, we assume notRetiredCallback is a noop.\r\n        if (memoryBarrier) __sync_synchronize(); // prevent retired from being read before we set a hazard pointer to obj, and prevent any future reads of fields of obj from being moved before we announce obj.\r\n        if (notRetiredCallback(callbackArg)) {\r\n            TRACE COUTATOMICTID(\"notRetiredCallback returns true\"<<std::endl);\r\n            return true;\r\n        } else {\r\n            // obj MAY be retired\r\n            TRACE COUTATOMICTID(\"notRetiredCallback returns false\"<<std::endl);\r\n            // although we don't care about other threads being able to free\r\n            // this object for efficiency, we still need to null this out\r\n            // because we need to be able to tell whether we successfully\r\n            // protected this when we invoke isProtectedEvenIfQuiescent\r\n            // (otherwise, crash recovery is hard to do)\r\n            announce[tid]->erase(obj); // note: this is inefficient, but it should never happen with regular use.\r\n            DEBUG assert(__size == announce[tid]->size());\r\n            return false;\r\n        }\r\n    }\r\n    inline void qUnprotectAll(const int tid) {\r\n        TRACE COUTATOMICTID(\"reclaimer_debraplus::unprotectAllObjectsEvenIfQuiescent(tid=\"<<tid<<\")\"<<std::endl);\r\n        assert(isQuiescent(tid));\r\n        announce[tid]->clear();\r\n        assert(announce[tid]->size() == 0);\r\n    }\r\n    \r\n    // rotate the epoch bags and reclaim any objects retired two epochs ago.\r\n    inline void rotateEpochBags(const int tid) {\r\n        assert(isQuiescent(tid));\r\n        // we rotate lists in constant time, and scan hazard pointers\r\n        // when the blockbag from two epochs ago is larger than scanThreshold\r\n        // (using an iterator with erase functionality).\r\n        // maybe in the future we could use bloom filters somehow to determine when no hazard pointer\r\n        // can be present in a block, so we can reclaim the entire block in O(k) time...???\r\n        // (if we're willing to accept k full, unreclaimable blocks per thread, then we can avoid\r\n        //  working with individual elements altogether. we can simply check if each HP is in the bloom\r\n        //  filter for each of c*n blocks (for some constant c), and have some probability of being\r\n        //  able to reclaim (c-1)*n blocks. then, this procedure will be worst case O(n) time.)\r\n\r\n        index[tid*PREFETCH_SIZE_WORDS] = (index[tid*PREFETCH_SIZE_WORDS]+1) % NUMBER_OF_EPOCH_BAGS_CR;\r\n        blockbag<T> * const freeable = epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid+index[tid*PREFETCH_SIZE_WORDS]];\r\n        if (freeable->getSizeInBlocks() >= scanThreshold) {\r\n\r\n            TRACE COUTATOMICTID(\"retiring... we have \"<<freeable->computeSize()<<\" things waiting to be retired in this epoch bag...\");\r\n            // hash all announcements\r\n            comparing[tid]->clear();\r\n            assert(comparing[tid]->size() == 0);\r\n            for (int otherTid=0; otherTid < this->NUM_PROCESSES; ++otherTid) {\r\n                int sz = announce[otherTid]->size();\r\n                for (int ixHP = 0; ixHP < sz; ++ixHP) {\r\n                    T* hp = (T*) announce[otherTid]->get(ixHP);\r\n                    if (hp) {\r\n                        int oldSize; DEBUG2 oldSize = comparing[tid]->size();\r\n                        comparing[tid]->insert((T*) hp);\r\n                        DEBUG2 assert(comparing[tid]->size() <= oldSize + 1); // might not increase size if comparing[tid] already contains this item...\r\n                    }\r\n                }\r\n            }\r\n            \r\n            // check if any nodes (from two epochs ago) are announced (qprotected)\r\n            // and swap them to the front of the blockbag.\r\n            // once all announced nodes are at the front of the blockbag,\r\n            // we can free whole blocks in the remainder of the blockbag.\r\n            blockbag_iterator<T> it = freeable->begin();\r\n            blockbag_iterator<T> nextswap = freeable->begin();\r\n            while (it != freeable->end()) {\r\n                if (comparing[tid]->contains(*it)) {\r\n                    // a hazard pointers points to the item\r\n                    it.swap(nextswap.getCurr(), nextswap.getIndex());\r\n                    nextswap++;\r\n                }\r\n                it++;\r\n            }\r\n            block<T> * const curr = nextswap.getCurr();\r\n            if (curr) {\r\n                this->pool->addMoveFullBlocks(tid, freeable, curr);\r\n            }\r\n        }\r\n        \r\n        currentBag[tid*PREFETCH_SIZE_WORDS] = freeable;\r\n        assert(isQuiescent(tid));\r\n    }\r\n    \r\n    // invoke this at the beginning of each operation that accesses\r\n    // objects reclaimed by this epoch manager.\r\n    // returns true if the call rotated the epoch bags for thread tid\r\n    // (and reclaimed any objects retired two epochs ago).\r\n    // otherwise, the call returns false.\r\n    // IMPLIES A FULL MEMORY BARRIER\r\n    inline bool leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers) {\r\n        SOFTWARE_BARRIER; // prevent any bookkeeping from being moved after this point by the compiler.\r\n        bool result = false;\r\n        long readEpoch = epoch; // multiple of EPOCH_INCREMENT\r\n        assert(!QUIESCENT(readEpoch));\r\n        // if our announced epoch is different from the current epoch\r\n        const long ann = announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n        DEBUG2 if (!QUIESCENT(ann)) {\r\n            COUTATOMICTID(\"NOT QUIESCENT\"<<std::endl);\r\n            exit(-1);\r\n        }\r\n        if (readEpoch != BITS_EPOCH(ann)) {\r\n            // announce the new epoch, and rotate the epoch bags and\r\n            // reclaim any objects retired two epochs ago.\r\n            checked[tid*PREFETCH_SIZE_WORDS] = 0;\r\n            //rotateEpochBags(tid);\r\n            for (int i=0;i<numReclaimers;++i) {\r\n                ((reclaimer_debraplus<T, Pool> * const) reclaimers[i])->rotateEpochBags(tid);\r\n            }\r\n            result = true;\r\n        }\r\n        // note: readEpoch, when written to announcedEpoch[tid],\r\n        //       will set the state to non-quiescent and non-neutralized\r\n        \r\n        // incrementally scan the announced epochs of all threads\r\n        int otherTid = checked[tid*PREFETCH_SIZE_WORDS];\r\n        if (otherTid >= this->NUM_PROCESSES) {\r\n            const int c = ++checked[tid*PREFETCH_SIZE_WORDS];\r\n            if (c > MINIMUM_OPERATIONS_BEFORE_NEW_EPOCH_CR) {\r\n                __sync_bool_compare_and_swap(&epoch, readEpoch, readEpoch+EPOCH_INCREMENT);\r\n            }\r\n        } else {\r\n            assert(otherTid >= 0);\r\n            long otherAnnounce = announcedEpoch[otherTid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n            if (BITS_EPOCH(otherAnnounce) == readEpoch\r\n                    || QUIESCENT(otherAnnounce)\r\n                    || neutralizeOther(tid, otherTid, readEpoch, otherAnnounce)) {\r\n                const int c = ++checked[tid*PREFETCH_SIZE_WORDS];\r\n                if (c >= this->NUM_PROCESSES && c > MINIMUM_OPERATIONS_BEFORE_NEW_EPOCH_CR) {\r\n                    __sync_bool_compare_and_swap(&epoch, readEpoch, readEpoch+EPOCH_INCREMENT);\r\n                }\r\n            }\r\n        }\r\n        // it is important that we set the announcedEpoch last, because we must\r\n        // not be neutralized during some of the preceding steps, or we may\r\n        // corrupt the data structure.\r\n        // (on x86/64, writes are not moved earlier in program order, so we don't need any membar before this write.)\r\n        // (on another arch, we'd have to prevent this write from being moved before the write to checked[].)\r\n        assert(isQuiescent(tid));\r\n        SOFTWARE_BARRIER;\r\n        announcedEpoch[tid*PREFETCH_SIZE_WORDS].store(readEpoch, memory_order_relaxed);\r\n        return result;\r\n    }\r\n    // IN A SCHEME THAT SUPPORTS CRASH RECOVERY, THIS IMPLIES A FULL MEMORY BARRIER IFF THIS MOVES THE THREAD FROM AN ACTIVE STATE TO A QUIESCENT STATE\r\n    inline void enterQuiescentState(const int tid) {\r\n        const long ann = announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed);\r\n        announcedEpoch[tid*PREFETCH_SIZE_WORDS].store(GET_WITH_QUIESCENT(ann), memory_order_relaxed);\r\n        assert(isQuiescent(tid));\r\n    }\r\n    \r\n    // for all schemes except reference counting\r\n    inline void retire(const int tid, T* p) {\r\n        assert(isQuiescent(tid));\r\n        currentBag[tid*PREFETCH_SIZE_WORDS]->add(p);\r\n        DEBUG2 this->debug->addRetired(tid, 1);\r\n    }\r\n\r\n    void debugPrintStatus(const int tid) {\r\n//        assert(tid >= 0);\r\n//        assert(tid < this->NUM_PROCESSES);\r\n//        long announce = BITS_EPOCH(announcedEpoch[tid*PREFETCH_SIZE_WORDS].load(memory_order_relaxed))/EPOCH_INCREMENT;\r\n//        std::cout<<\"announce=\"<<announce;\r\n//        std::cout<<\" bags:\";\r\n//        for (int i=0;i<NUMBER_OF_EPOCH_BAGS_CR;++i) {\r\n//            std::cout<<\" bag\"<<i<<\"=\"<<epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid+i]->computeSize();\r\n//        }\r\n    }\r\n\r\n    reclaimer_debraplus(const int numProcesses, Pool *_pool, debugInfo * const _debug, RecoveryMgr<void *> * const _recoveryMgr = NULL)\r\n            : reclaimer_interface<T, Pool>(numProcesses, _pool, _debug, _recoveryMgr) {\r\n        VERBOSE DEBUG COUTATOMIC(\"constructor reclaimer_debraplus helping=\"<<this->shouldHelp()<<std::endl);// scanThreshold=\"<<scanThreshold<<std::endl;\r\n        if (_recoveryMgr) COUTATOMIC(\"SIGRTMIN=\"<<SIGRTMIN<<\" neutralizeSignal=\"<<this->recoveryMgr->neutralizeSignal<<std::endl);\r\n        // set up signal set for neutralize signal\r\n        if (sigemptyset(&neutralizeSignalSet)) {\r\n            COUTATOMIC(\"error creating empty signal set\"<<std::endl);\r\n            exit(-1);\r\n        }\r\n        if (_recoveryMgr) {\r\n            if (sigaddset(&neutralizeSignalSet, this->recoveryMgr->neutralizeSignal)) {\r\n                COUTATOMIC(\"error adding signal to signal set\"<<std::endl);\r\n                exit(-1);\r\n            }\r\n        }\r\n        \r\n        // all other initialization and allocation\r\n        epoch = 0;\r\n        epochbags = new blockbag<T>*[NUMBER_OF_EPOCH_BAGS_CR*numProcesses];\r\n        currentBag = new blockbag<T>*[numProcesses*PREFETCH_SIZE_WORDS];\r\n        index = new long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        announcedEpoch = new atomic_long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        checked = new long[numProcesses*PREFETCH_SIZE_WORDS];\r\n        announce = new AtomicArrayList<T>*[numProcesses];\r\n        comparing = new hashset_new<T>*[numProcesses];\r\n        for (int tid=0;tid<numProcesses;++tid) {\r\n            for (int i=0;i<NUMBER_OF_EPOCH_BAGS_CR;++i) {\r\n                epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid+i] = new blockbag<T>(tid, this->pool->blockpools[tid]);\r\n            }\r\n            currentBag[tid*PREFETCH_SIZE_WORDS] = epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid];\r\n            index[tid*PREFETCH_SIZE_WORDS] = 0;\r\n            announcedEpoch[tid*PREFETCH_SIZE_WORDS].store(GET_WITH_QUIESCENT(0), memory_order_relaxed);\r\n            checked[tid*PREFETCH_SIZE_WORDS] = 0;\r\n            announce[tid] = new AtomicArrayList<T>(MAX_PROTECT_EVEN_IF_QUIESCENT);\r\n            comparing[tid] = new hashset_new<T>(numProcesses*MAX_PROTECT_EVEN_IF_QUIESCENT);\r\n        }\r\n    }\r\n    ~reclaimer_debraplus() {\r\n        VERBOSE DEBUG COUTATOMIC(\"destructor reclaimer_debraplus\"<<std::endl);\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            // move contents of all bags into pool\r\n            for (int i=0;i<NUMBER_OF_EPOCH_BAGS_CR;++i) {\r\n                this->pool->addMoveAll(tid, epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid+i]);\r\n                delete epochbags[NUMBER_OF_EPOCH_BAGS_CR*tid+i];\r\n            }\r\n            delete comparing[tid];\r\n            delete announce[tid];\r\n        }\r\n        delete[] announce;\r\n        delete[] epochbags;\r\n        delete[] index;\r\n        delete[] currentBag;\r\n        delete[] announcedEpoch;\r\n        delete[] checked;\r\n        delete[] comparing;\r\n    }\r\n\r\n};\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/reclaimer_hazardptr.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECLAIM_HAZARDPTR_STACK_H\r\n#define\tRECLAIM_HAZARDPTR_STACK_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include <sstream>\r\n#include <string>\r\n#include \"blockbag.h\"\r\n#include \"plaf.h\"\r\n#include \"allocator_interface.h\"\r\n#include \"hashtable.h\"\r\n#include \"reclaimer_interface.h\"\r\n#include \"arraylist.h\"\r\nusing namespace std;\r\nusing namespace hashset_namespace;\r\n\r\n#define MAX_HAZARDPTRS_PER_THREAD 16\r\n\r\ntemplate <typename T = void, class Pool = pool_interface<T> >\r\nclass reclaimer_hazardptr : public reclaimer_interface<T, Pool> {\r\nprivate:\r\n    AtomicArrayList<T> **announce;  // announce[tid] = set of announced hazard pointers for thread tid\r\n    ArrayList<T> **retired;         // retired[tid] = set of retired objects for thread tid\r\n    hashset_new<T> **comparing;     // comparing[tid] = set of announced hazard pointers for ALL threads, as collected by thread tid during it's last retire(tid, ...) call\r\n    \r\n    // number of elements that retired[tid] must contain\r\n    // before we scan hazard pointers to determine\r\n    // which elements of retired[tid] can be deallocated.\r\n    // to get amortized constant scanning time per object,\r\n    // this must be nk+Omega(nk), where\r\n    //      n = number of threads and\r\n    //      k = max number of hazard pointers a thread can hold at once\r\n    const int scanThreshold;\r\n    \r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef reclaimer_hazardptr<_Tp1, Pool> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef reclaimer_hazardptr<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    inline static bool shouldHelp() {\r\n        return false;\r\n    }\r\n    \r\n    bool isProtected(const int tid, T * const obj) {\r\n        return announce[tid]->contains(obj);\r\n    }\r\n    bool static isQProtected(const int tid, T * const obj) {\r\n        return false;\r\n    }\r\n    inline static bool isQuiescent(const int tid) {\r\n        return true;\r\n    }    \r\n    \r\n    // for hazard pointers (and counting references from threads)\r\n    inline bool protect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        TRACE std::cout<<\"reclaimer_hazardptr::protect(tid=\"<<tid<<\", \"<<debugPointerOutput(obj)<<\")\"<<std::endl;\r\n        int size; DEBUG2 size = announce[tid]->size();\r\n//        DEBUG if (sizeof(T) < 80 /* is a node */) assert(!announce[tid]->contains(obj));\r\n        announce[tid]->add(obj);\r\n        if (memoryBarrier) __sync_synchronize(); // prevent retired from being read before we set a hazard pointer to obj\r\n        DEBUG2 assert(isProtected(tid, obj)); //announce[tid]->contains(obj));\r\n        DEBUG2 assert(size + 1 == announce[tid]->size());\r\n//        SOFTWARE_BARRIER;\r\n        if (notRetiredCallback(callbackArg)) {\r\n//            SOFTWARE_BARRIER;\r\n            TRACE std::cout<<\"notRetiredCallback returns true\"<<std::endl;\r\n            DEBUG2 assert(announce[tid]->size() <= MAX_HAZARDPTRS_PER_THREAD);\r\n            DEBUG2 assert(isProtected(tid, obj));\r\n//            SOFTWARE_BARRIER;\r\n            assert(isProtected(tid, obj));\r\n            return true;\r\n        } else {\r\n            TRACE std::cout<<\"notRetiredCallback returns false\"<<std::endl;\r\n            unprotect(tid, obj); // note: it is unnecessary to unprotect here if we promise to enter a quiescent state as soon as we fail to protect an object.\r\n//            DEBUG if (sizeof(T) < 80 /* is a node */) assert(!isProtected(tid, obj));\r\n//            SOFTWARE_BARRIER;\r\n            return false;\r\n        }\r\n    }\r\n    inline void unprotect(const int tid, T * const obj) {\r\n        TRACE std::cout<<\"reclaimer_hazardptr::unprotect(tid=\"<<tid<<\", \"<<debugPointerOutput(obj)<<\")\"<<std::endl;\r\n//        SOFTWARE_BARRIER;\r\n        DEBUG2 assert(isProtected(tid, obj));\r\n        int size; DEBUG2 size = announce[tid]->size();\r\n        announce[tid]->erase(obj);\r\n//        DEBUG if (sizeof(T) < 80 /* is a node */) assert(!announce[tid]->contains(obj));\r\n        DEBUG2 assert(size - 1 == announce[tid]->size());\r\n//        SOFTWARE_BARRIER;\r\n    }\r\n    inline bool qProtect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        TRACE std::cout<<\"reclaimer_debraplus::qProtect(tid=\"<<tid<</*\", \"<<*obj<<*/\")\"<<std::endl;\r\n        return false;\r\n    }\r\n    inline void qUnprotectAll(const int tid) {\r\n        TRACE std::cout<<\"reclaimer_debraplus::qUnprotectAll(tid=\"<<tid<<\")\"<<std::endl;\r\n    }\r\n    \r\n    // for epoch based reclamation\r\n    inline void enterQuiescentState(const int tid) {\r\n        TRACE std::cout<<\"reclaimer_hazardptr::enterQuiescentState(tid=\"<<tid<<\")\"<<std::endl;\r\n//        SOFTWARE_BARRIER;\r\n        announce[tid]->clear();\r\n//        __sync_synchronize();\r\n//        announce[tid]->clearWithoutFreeingElements();\r\n        DEBUG2 assert(announce[tid]->size() == 0);\r\n        DEBUG2 assert(announce[tid]->isEmpty());\r\n//        SOFTWARE_BARRIER;\r\n    }\r\n    inline static bool leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers) {\r\n        TRACE std::cout<<\"reclaimer_hazardptr::leaveQuiescentState(tid=\"<<tid<<\")\"<<std::endl;\r\n//        SOFTWARE_BARRIER;\r\n        return false;\r\n    }\r\n    inline static void rotateEpochBags(const int tid) {}\r\n    \r\n    string debugPointerOutput(T* p) {\r\n        long x = (long) p;\r\n        ostringstream os;\r\n        const int base = 10+26+26;\r\n        while (x > 0) {\r\n            int c = x % base;\r\n            if (c < 10) os<<(char)(c+(int)'0');\r\n            else if (c < 10+26) os<<(char)(c-10+(int)'a');\r\n            else os<<(char)(c-10-26+(int)'A');\r\n            x /= base;\r\n        }\r\n        return os.str();\r\n    }\r\n    \r\n    inline void retire(const int tid, T* p) {\r\n        TRACE std::cout<<\"reclaimer_hazardptr::retire(tid=\"<<tid<<\", \"<<debugPointerOutput(p)<<\")\"<<std::endl;\r\n        DEBUG2 this->debug->addRetired(tid, 1);\r\n        retired[tid]->add(p);\r\n        \r\n        // if the retired bag is sufficiently large\r\n        if (retired[tid]->isFull()) {\r\n//            __sync_synchronize(); // not necessary, since there is a membar implied by the update cas between here and the marked bit that makes the retired predicate return true... (it follows that the retired predicate for a node u will see marked and return true if it executes when we are performing retire(u).)\r\n            \r\n//            TRACE std::cout<<\"retiring... we have \"<<retired[tid]->size()<<\" things waiting to be retired (#hps=\"<<announce[tid]->size()<<\")...\";\r\n//            // hash all announcements\r\n//            int totalSize = 0;\r\n//            int sizes[MAX_TID_POW2];\r\n//            for (int otherTid=0; otherTid < this->NUM_PROCESSES; ++otherTid) {\r\n//                sizes[otherTid] = announce[tid]->size();\r\n//                totalSize += sizes[otherTid];\r\n//            }\r\n//            hashset_new<T> hset = hashset_new<T>(totalSize);\r\n//            for (int otherTid=0; otherTid < this->NUM_PROCESSES; ++otherTid) {\r\n//                for (int i=0;i<sizes[tid];++i) {\r\n//                    hset.insert(announce[tid]->get(i));\r\n//                }\r\n//            }\r\n//            \r\n//            // iterate over all items in retired[tid]\r\n//            TRACE std::cout<<\"retiring... we have \"<<retired[tid]->size()<<\" things waiting to be retired (#hps=\"<<announce[tid]->size()<<\", totalSize=\"<<totalSize<<\")...\";\r\n//            for (int ix=0;ix<retired[tid]->size();++ix) {\r\n//                TRACE std::cout<<\" \"<<debugPointerOutput(retired[tid]->get(ix))<<\"=\"<<(hset.contains(retired[tid]->get(ix))?\"1\":\"0\");\r\n//                if (!hset.contains(retired[tid]->get(ix))) {\r\n//                    // no hazard pointers point to the item, so we send it to the pool\r\n//                    this->pool->add(tid, retired[tid]->get(ix));\r\n//                    // now we remove the item from retired[tid] and\r\n//                    // adjust ix to continue where we left off\r\n//                    retired[tid]->erase(ix);\r\n//                    --ix;\r\n//                }\r\n//            }\r\n//            TRACE std::cout<<\"    afterwards, we have \"<<retired[tid]->size()<<\" things waiting to be retired...\"<<std::endl;\r\n\r\n//            TRACE std::cout<<\"retiring... we have \"<<retired[tid]->size()<<\" things waiting to be retired (THIS thread #hps=\"<<announce[tid]->size()<<\")...\";\r\n//            for (int ix=0;ix<retired[tid]->size();) {\r\n//                // check if retired[tid]->data[ix] is in any set of hazard pointers\r\n//                bool found = false;\r\n//                for (int otherTid=0;otherTid<this->NUM_PROCESSES;++otherTid) {\r\n//                    int sz = announce[otherTid]->size();\r\n//                    for (int ixHP=0;ixHP<sz;++ixHP) {\r\n//                        if (retired[tid]->get(ix) == announce[otherTid]->get(ixHP)) {\r\n//                            found = true;\r\n//                            // break out of both loops\r\n//                            otherTid = this->NUM_PROCESSES;\r\n//                            break;\r\n//                        }\r\n//                    }\r\n//                }\r\n//                if (!found) {\r\n//                    // no hazard pointers point to the item, so we send it to the pool\r\n//                    this->pool->add(tid, retired[tid]->get(ix));\r\n//                    // now we remove the item from retired[tid]\r\n//                    retired[tid]->erase(ix);\r\n//                } else {\r\n//                    ++ix; // we didn't erase, so we need to move on to the next element\r\n//                }\r\n//            }\r\n//            TRACE std::cout<<\"    afterwards, we have \"<<retired[tid]->size()<<\" things waiting to be retired...\"<<std::endl;\r\n\r\n            TRACE std::cout<<\"retiring... we have \"<<retired[tid]->size()<<\" things waiting to be retired (THIS thread #hps=\"<<announce[tid]->size()<<\")...\";\r\n            // hash all announcements\r\n            comparing[tid]->clear();\r\n            assert(comparing[tid]->size() == 0);\r\n            for (int otherTid=0; otherTid < this->NUM_PROCESSES; ++otherTid) {\r\n                int sz = announce[otherTid]->size();\r\n                assert(sz < MAX_HAZARDPTRS_PER_THREAD);\r\n                for (int ixHP=0;ixHP<sz;++ixHP) {\r\n                    int oldSize; DEBUG2 oldSize = comparing[tid]->size();\r\n                    comparing[tid]->insert(announce[otherTid]->get(ixHP));\r\n                    DEBUG2 assert(comparing[tid]->size() <= oldSize + 1); // might not increase size if comparing[tid] already contains this item...\r\n                }\r\n            }\r\n            for (int ix=0;ix<retired[tid]->size();) {\r\n                // check if retired[tid]->data[ix] is in any set of hazard pointers\r\n                if (!comparing[tid]->contains(retired[tid]->get(ix))) {\r\n                    // no hazard pointers point to the item, so we send it to the pool\r\n                    this->pool->add(tid, retired[tid]->get(ix));\r\n                    // now we remove the item from retired[tid]\r\n                    retired[tid]->erase(ix);\r\n                } else {\r\n                    ++ix; // we didn't erase, so we need to move on to the next element\r\n                }\r\n            }\r\n            TRACE std::cout<<\"    afterwards, we have \"<<retired[tid]->size()<<\" things waiting to be retired...\"<<std::endl;\r\n            \r\n            DEBUG2 assert(!retired[tid]->isFull());\r\n        }\r\n    }\r\n\r\n    void debugPrintStatus(const int tid) {\r\n//        assert(tid >= 0);\r\n//        assert(tid < this->NUM_PROCESSES);\r\n    }\r\n\r\n    reclaimer_hazardptr(const int numProcesses, Pool *_pool, debugInfo * const _debug, RecoveryMgr<void *> * const _recoveryMgr = NULL)\r\n            : scanThreshold(5*numProcesses*MAX_HAZARDPTRS_PER_THREAD),\r\n              reclaimer_interface<T, Pool>(numProcesses, _pool, _debug, _recoveryMgr) {\r\n        VERBOSE DEBUG std::cout<<\"constructor reclaimer_hazardptr\"<<std::endl;\r\n        announce = new AtomicArrayList<T>*[numProcesses];\r\n        retired = new ArrayList<T>*[numProcesses];\r\n        comparing = new hashset_new<T>*[numProcesses];\r\n        for (int tid=0;tid<numProcesses;++tid) {\r\n            announce[tid] = new AtomicArrayList<T>(MAX_HAZARDPTRS_PER_THREAD);\r\n            retired[tid] = new ArrayList<T>(scanThreshold);\r\n            comparing[tid] = new hashset_new<T>(numProcesses*MAX_HAZARDPTRS_PER_THREAD);\r\n        }\r\n    }\r\n    ~reclaimer_hazardptr() {\r\n        VERBOSE DEBUG std::cout<<\"destructor reclaimer_hazardptr\"<<std::endl;\r\n        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n            int sz = retired[tid]->size();\r\n            for (int ix=0;ix<sz;++ix) {\r\n                this->pool->add(tid, retired[tid]->get(ix));\r\n            }\r\n            delete announce[tid];\r\n            delete retired[tid];\r\n            delete comparing[tid];\r\n        }\r\n        delete[] announce;\r\n        delete[] retired;\r\n        delete[] comparing;\r\n    }\r\n\r\n}; // end class\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/reclaimer_interface.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECLAIM_INTERFACE_H\r\n#define\tRECLAIM_INTERFACE_H\r\n\r\n#include \"recovery_manager.h\"\r\n#include \"pool_interface.h\"\r\n#include \"globals.h\"\r\n#include <iostream>\r\n#include <cstdlib>\r\nusing namespace std;\r\n\r\ntemplate <typename T>\r\nstruct set_of_bags {\r\n    blockbag<T> * const * const bags;\r\n    const int numBags;\r\n};\r\n\r\ntemplate <typename T = void, class Pool = pool_interface<T> >\r\nclass reclaimer_interface {\r\npublic:\r\n#ifndef __CYGWIN__\r\n    RecoveryMgr<void *> * recoveryMgr;\r\n#endif\r\n    debugInfo * const debug;\r\n    \r\n    const int NUM_PROCESSES;\r\n    Pool *pool;\r\n\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef reclaimer_interface<_Tp1, Pool> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef reclaimer_interface<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    long long getSizeInNodes() { return 0; }\r\n    string getSizeString() { return \"\"; }\r\n\r\n    inline static bool quiescenceIsPerRecordType() { return true; }\r\n    inline static bool shouldHelp() { return true; } // FOR DEBUGGING PURPOSES\r\n    inline static bool supportsCrashRecovery() { return false; }\r\n    inline bool isProtected(const int tid, T * const obj);\r\n    inline bool isQProtected(const int tid, T * const obj);\r\n    inline static bool isQuiescent(const int tid) {\r\n        COUTATOMICTID(\"reclaimer_interface::isQuiescent(tid) is not implemented!\"<<std::endl);\r\n        exit(-1);\r\n    }\r\n    \r\n    // for hazard pointers (and reference counting)\r\n    inline bool protect(const int tid, T* obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true);\r\n    inline void unprotect(const int tid, T* obj);\r\n    inline bool qProtect(const int tid, T* obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true);\r\n    inline void qUnprotectAll(const int tid);\r\n    \r\n    // for epoch based reclamation (or, more generally, any quiescent state based reclamation)\r\n//    inline long readEpoch();\r\n//    inline long readAnnouncedEpoch(const int tid);\r\n    /**\r\n     * enterQuiescentState<T> must be idempotent,\r\n     * and must unprotect all objects protected by calls to protectObject<T>.\r\n     * it must NOT unprotect any object protected by a call to\r\n     * protectObjectEvenAfterRestart.\r\n     */\r\n    inline void enterQuiescentState(const int tid);\r\n    inline bool leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers);\r\n    inline void rotateEpochBags(const int tid);\r\n\r\n    // for all schemes except reference counting\r\n    inline void retire(const int tid, T* p);\r\n    inline void unretireLast(const int tid) {}\r\n    \r\n    inline void initThread(const int tid) {}\r\n    inline void deinitThread(const int tid) {}\r\n    void debugPrintStatus(const int tid);\r\n    \r\n    reclaimer_interface(const int numProcesses, Pool *_pool, debugInfo * const _debug, RecoveryMgr<void *> * const _recoveryMgr = NULL)\r\n#ifndef __CYGWIN__\r\n            : recoveryMgr(_recoveryMgr)\r\n#endif\r\n            , debug(_debug)\r\n            , NUM_PROCESSES(numProcesses)\r\n            , pool(_pool) {\r\n        VERBOSE DEBUG COUTATOMIC(\"constructor reclaimer_interface\"<<std::endl);\r\n    }\r\n    ~reclaimer_interface() {\r\n        VERBOSE DEBUG COUTATOMIC(\"destructor reclaimer_interface\"<<std::endl);\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/reclaimer_none.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECLAIM_NOOP_H\r\n#define\tRECLAIM_NOOP_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include \"pool_interface.h\"\r\n#include \"reclaimer_interface.h\"\r\nusing namespace std;\r\n\r\ntemplate <typename T = void, class Pool = pool_interface<T> >\r\nclass reclaimer_none : public reclaimer_interface<T, Pool> {\r\nprivate:\r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef reclaimer_none<_Tp1, Pool> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef reclaimer_none<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    string getSizeString() { return \"no reclaimer\"; }\r\n    inline static bool shouldHelp() {\r\n        return true;\r\n    }\r\n    \r\n    inline static bool isQuiescent(const int tid) {\r\n        return true;\r\n    }\r\n    inline static bool isProtected(const int tid, T * const obj) {\r\n        return true;\r\n    }\r\n    inline static bool isQProtected(const int tid, T * const obj) {\r\n        return false;\r\n    }\r\n    \r\n    // for hazard pointers (and reference counting)\r\n    inline static bool protect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void unprotect(const int tid, T * const obj) {}\r\n    inline static bool qProtect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void qUnprotectAll(const int tid) {}\r\n    \r\n    // rotate the epoch bags and reclaim any objects retired two epochs ago.\r\n    inline static void rotateEpochBags(const int tid) {\r\n    }\r\n    // invoke this at the beginning of each operation that accesses\r\n    // objects reclaimed by this epoch manager.\r\n    // returns true if the call rotated the epoch bags for thread tid\r\n    // (and reclaimed any objects retired two epochs ago).\r\n    // otherwise, the call returns false.\r\n    inline static bool leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers) {\r\n        return false;\r\n    }\r\n    inline static void enterQuiescentState(const int tid) {\r\n    }\r\n    \r\n    // for all schemes except reference counting\r\n    inline static void retire(const int tid, T* p) {\r\n    }\r\n\r\n    void debugPrintStatus(const int tid) {\r\n    }\r\n\r\n//    set_of_bags<T> getBlockbags() {\r\n//        set_of_bags<T> empty = {.bags = NULL, .numBags = 0};\r\n//        return empty;\r\n//    }\r\n//    \r\n//    void getOldestTwoBlockbags(const int tid, blockbag<T> ** oldest, blockbag<T> ** secondOldest) {\r\n//        *oldest = *secondOldest = NULL;\r\n//    }\r\n//    \r\n//    int getOldestBlockbagIndexOffset(const int tid) {\r\n//        return -1;\r\n//    }\r\n    \r\n    void getSafeBlockbags(const int tid, blockbag<T> ** bags) {\r\n        bags[0] = NULL;\r\n    }\r\n    \r\n    reclaimer_none(const int numProcesses, Pool *_pool, debugInfo * const _debug, RecoveryMgr<void *> * const _recoveryMgr = NULL)\r\n            : reclaimer_interface<T, Pool>(numProcesses, _pool, _debug, _recoveryMgr) {\r\n        VERBOSE DEBUG std::cout<<\"constructor reclaimer_none\"<<std::endl;\r\n    }\r\n    ~reclaimer_none() {\r\n        VERBOSE DEBUG std::cout<<\"destructor reclaimer_none\"<<std::endl;\r\n    }\r\n\r\n}; // end class\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/reclaimer_rcu.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n// NOTE: this reclaimer can ONLY be used with allocator_new,\r\n//       and cannot be used with any pool!\r\n\r\n#ifndef RECLAIM_RCU_H\r\n#define\tRECLAIM_RCU_H\r\n\r\n#include <cassert>\r\n#include <iostream>\r\n#include <sstream>\r\n#include <urcu.h>\r\n#include \"blockbag.h\"\r\n#include \"plaf.h\"\r\n#ifdef USE_DEBUGCOUNTERS\r\n    #include \"debugcounter.h\"\r\n#endif\r\n#include \"allocator_interface.h\"\r\n#include \"reclaimer_interface.h\"\r\n#ifdef BST\r\n    #include \"node.h\"\r\n    #include \"scxrecord.h\"\r\n#elif defined KCAS_MAXK\r\n    #include \"kcas.h\"\r\n#else\r\n    #error ONLY SUPPORTS BST(main.cpp) and KCAS(ubench.cpp)\r\n#endif\r\nusing namespace std;\r\n\r\n#include <cstddef>\r\n\r\ntemplate <typename T, typename M> M get_member_type(M T::*);\r\ntemplate <typename T, typename M> T get_class_type(M T::*);\r\n\r\ntemplate <typename T,\r\n          typename R,\r\n          R T::*M\r\n         >\r\nconstexpr std::size_t offset_of()\r\n{\r\n    return reinterpret_cast<std::size_t>(&(((T*)0)->*M));\r\n}\r\n\r\n#define OFFSET_OF(m) offset_of<decltype(get_class_type(m)), \\\r\n                     decltype(get_member_type(m)), m>()\r\n\r\n#define comma ,\r\n\r\n__thread long long rcuthrFreesNode = 0;       // for RCU THREADS ONLY\r\n__thread long long rcuthrFreesDescriptor = 0; // for RCU THREADS ONLY\r\nlong long freesNode = 0;\r\nlong long freesDescriptor = 0;\r\n\r\n#if defined BST || defined BST_THROWAWAY\r\n    void rcuCallback_Node(struct rcu_head *rcu) {\r\n        Node<test_type, test_type> * n = (Node<test_type, test_type> *)\r\n                (((char*) rcu) - OFFSET_OF(\r\n                        &Node<test_type comma test_type>::rcuHeadField));\r\n        if (++rcuthrFreesNode == 1<<10) {\r\n            __sync_fetch_and_add(&freesNode, rcuthrFreesNode);\r\n            rcuthrFreesNode = 0;\r\n        }\r\n        free(n);\r\n    }\r\n    #ifdef BST_THROWAWAY\r\n        void rcuCallback_SCXRecord(struct rcu_head *rcu) {\r\n            SCXRecord<test_type, test_type> * n = (SCXRecord<test_type, test_type> *)\r\n                    (((char*) rcu) - OFFSET_OF(\r\n                            &SCXRecord<test_type comma test_type>::rcuHeadField));\r\n            if (++rcuthrFreesDescriptor == 1<<10) {\r\n                __sync_fetch_and_add(&freesDescriptor, rcuthrFreesDescriptor);\r\n                rcuthrFreesDescriptor = 0;\r\n            }\r\n            free(n);\r\n        }\r\n    #endif\r\n#elif defined KCAS_MAXK\r\n    void rcuCallback_kcasdesc(struct rcu_head *rcu) {\r\n        kcasdesc_t<KCAS_MAXK, KCAS_MAXTHREADS> * n = (kcasdesc_t<KCAS_MAXK, KCAS_MAXTHREADS> *)\r\n                (((char*) rcu) - OFFSET_OF(\r\n                        &kcasdesc_t<KCAS_MAXK comma KCAS_MAXTHREADS>::rcuHeadField));\r\n        if (++rcuthrFreesDescriptor == 1<<10) {\r\n            __sync_fetch_and_add(&freesDescriptor, rcuthrFreesDescriptor);\r\n            rcuthrFreesDescriptor = 0;\r\n        }\r\n        free(n);\r\n    }\r\n    void rcuCallback_rdcssdesc(struct rcu_head *rcu) {\r\n        rdcssdesc_t * n = (rdcssdesc_t *)\r\n                (((char*) rcu) - OFFSET_OF(\r\n                        &rdcssdesc_t::rcuHeadField));\r\n        if (++rcuthrFreesNode == 1<<10) {\r\n            __sync_fetch_and_add(&freesNode, rcuthrFreesNode);\r\n            rcuthrFreesNode = 0;\r\n        }\r\n        free(n);\r\n    }\r\n#endif\r\n\r\n//template <typename T>\r\n//void rcuCallback(struct rcu_head *rcu) {\r\n//    T * n = (T *) (((char *) rcu) - OFFSET_OF(&T::rcuHeadField));\r\n//    free(n);\r\n//}\r\n\r\n__thread bool calledRCULock = false;\r\n__thread bool rcuInitialized = false;\r\n\r\ntemplate <typename T = void, class Pool = pool_interface<T> >\r\nclass reclaimer_rcu : public reclaimer_interface<T, Pool> {\r\nprotected:\r\n    \r\npublic:\r\n    template<typename _Tp1>\r\n    struct rebind {\r\n        typedef reclaimer_rcu<_Tp1, Pool> other;\r\n    };\r\n    template<typename _Tp1, typename _Tp2>\r\n    struct rebind2 {\r\n        typedef reclaimer_rcu<_Tp1, _Tp2> other;\r\n    };\r\n    \r\n    long long getSizeInNodes() {\r\n        long long sum = 0;\r\n        return sum;\r\n    }\r\n    string getSizeString() {\r\n        stringstream ss;\r\n        ss<<getSizeInNodes()<<\" in reclaimer_rcu\";\r\n        return ss.str();\r\n    }\r\n    \r\n    inline static bool quiescenceIsPerRecordType() { return false; }\r\n    \r\n    inline bool isQuiescent(const int tid) {\r\n        return false;\r\n    }\r\n\r\n    inline static bool isProtected(const int tid, T * const obj) {\r\n        return true;\r\n    }\r\n    inline static bool isQProtected(const int tid, T * const obj) {\r\n        return false;\r\n    }\r\n    inline static bool protect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void unprotect(const int tid, T * const obj) {}\r\n    inline static bool qProtect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool memoryBarrier = true) {\r\n        return true;\r\n    }\r\n    inline static void qUnprotectAll(const int tid) {}\r\n    \r\n    inline static bool shouldHelp() { return true; }\r\n    \r\n    inline void rotateEpochBags(const int tid) {}\r\n    \r\n    inline bool leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers) {\r\n        if (!calledRCULock) {\r\n            rcu_read_lock();\r\n            calledRCULock = true;\r\n        }\r\n        return true;\r\n    }\r\n    \r\n    inline void enterQuiescentState(const int tid) {\r\n        if (calledRCULock) {\r\n            rcu_read_unlock();\r\n            calledRCULock = false;\r\n        }\r\n    }\r\n    \r\n    // for all schemes except reference counting\r\n    inline void retire(const int tid, T* p) {\r\n//        call_rcu(&p->rcuHeadField, rcuCallback<T>);\r\n#if defined BST || defined BST_THROWAWAY\r\n        if (sizeof(*p) == sizeof(Node<test_type, test_type>)) {\r\n            call_rcu(&p->rcuHeadField, rcuCallback_Node);\r\n#ifdef BST_THROWAWAY\r\n        } else if (sizeof(*p) == sizeof(SCXRecord<test_type, test_type>)) {\r\n            call_rcu(&p->rcuHeadField, rcuCallback_SCXRecord);\r\n#endif\r\n        }\r\n#elif defined KCAS_MAXK\r\n        if (sizeof(*p) == sizeof(kcasdesc_t<KCAS_MAXK comma KCAS_MAXTHREADS>)) {\r\n            call_rcu(&p->rcuHeadField, rcuCallback_kcasdesc);\r\n        } else if (sizeof(*p) == sizeof(rdcssdesc_t)) {\r\n            call_rcu(&p->rcuHeadField, rcuCallback_rdcssdesc);\r\n        }\r\n#endif\r\n    }\r\n\r\n    void debugPrintStatus(const int tid) {\r\n        if (freesNode) std::cout<<\"freesNode=\"<<freesNode<<std::endl;\r\n        if (freesDescriptor) std::cout<<\"freesDescriptor=\"<<freesDescriptor<<std::endl;\r\n    }\r\n    \r\n    void initThread(const int tid) {\r\n        if (!rcuInitialized) {\r\n            rcu_register_thread();\r\n            struct call_rcu_data * crdp = create_call_rcu_data(0,-1);\r\n            set_thread_call_rcu_data(crdp);\r\n            rcuInitialized = true;\r\n        }\r\n    }\r\n    \r\n    void deinitThread(const int tid) {\r\n        if (rcuInitialized) {\r\n            rcu_unregister_thread();\r\n            rcuInitialized = false;\r\n        }\r\n    }\r\n\r\n    reclaimer_rcu(const int numProcesses, Pool *_pool, debugInfo * const _debug, RecoveryMgr<void *> * const _recoveryMgr = NULL)\r\n            : reclaimer_interface<T, Pool>(numProcesses, _pool, _debug, _recoveryMgr) {\r\n        rcu_init();\r\n    }\r\n    ~reclaimer_rcu() {}\r\n};\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/record_manager.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECORD_MANAGER_H\r\n#define\tRECORD_MANAGER_H\r\n\r\n#include <atomic>\r\n#include \"globals.h\"\r\n#include \"record_manager_single_type.h\"\r\n\r\n#include <iostream>\r\n#include <exception>\r\n#include <stdexcept>\r\n#include <typeinfo>\r\nusing namespace std;\r\n\r\ninline CallbackReturn callbackReturnTrue(CallbackArg arg) {\r\n    return true;\r\n}\r\n\r\n// compile time check for duplicate template parameters\r\n// compare first with rest to find any duplicates\r\ntemplate <typename T> void check_duplicates(void) {}\r\ntemplate <typename T, typename First, typename... Rest>\r\nvoid check_duplicates(void) {\r\n    if (typeid(T) == typeid(First)) {\r\n        throw logic_error(\"duplicate template arguments provided to RecordManagerSet\");\r\n    }\r\n    check_duplicates<T, Rest...>();\r\n}\r\n\r\n// base case: empty template\r\n// this is a compile time check for invalid arguments\r\ntemplate <class Reclaim, class Alloc, class Pool, typename... Rest>\r\nclass RecordManagerSet {\r\npublic:\r\n    RecordManagerSet(const int numProcesses, RecoveryMgr<void *> * const _recoveryMgr) {}\r\n    template <typename T>\r\n    record_manager_single_type<T, Reclaim, Alloc, Pool> * get(T * const recordType) {\r\n        throw logic_error(\"invalid type passed to RecordManagerSet::get()\");\r\n        return NULL;\r\n    }\r\n    void clearCounters(void) {}\r\n    void registerThread(const int tid) {}\r\n    void unregisterThread(const int tid) {}\r\n    void printStatus() {}\r\n    inline void qUnprotectAll(const int tid) {}\r\n    inline void getReclaimers(const int tid, void ** const reclaimers, int index) {}\r\n    inline void enterQuiescentState(const int tid) {}\r\n    inline void leaveQuiescentStateForEach(const int tid) {}\r\n    inline void leaveQuiescentState(const int tid, const bool callForEach) {}\r\n};\r\n\r\n// \"recursive\" case\r\ntemplate <class Reclaim, class Alloc, class Pool, typename First, typename... Rest>\r\nclass RecordManagerSet<Reclaim, Alloc, Pool, First, Rest...> : RecordManagerSet<Reclaim, Alloc, Pool, Rest...> {\r\n    record_manager_single_type<First, Reclaim, Alloc, Pool> * const mgr;\r\npublic:\r\n    RecordManagerSet(const int numProcesses, RecoveryMgr<void *> * const _recoveryMgr)\r\n        : RecordManagerSet<Reclaim, Alloc, Pool, Rest...>(numProcesses, _recoveryMgr)\r\n        , mgr(new record_manager_single_type<First, Reclaim, Alloc, Pool>(numProcesses, _recoveryMgr))\r\n        {\r\n        //cout<<\"RecordManagerSet with First=\"<<typeid(First).name()<<\" and sizeof...(Rest)=\"<<sizeof...(Rest)<<std::endl;\r\n        check_duplicates<First, Rest...>(); // check if first is in {rest...}\r\n    }\r\n    ~RecordManagerSet() {\r\n        delete mgr;\r\n        // note: should automatically call the parent class' destructor afterwards\r\n    }\r\n    // note: the compiled code for get() should be a single read and return statement\r\n    template<typename T>\r\n    inline record_manager_single_type<T, Reclaim, Alloc, Pool> * get(T * const recordType) {\r\n        if (typeid(First) == typeid(T)) {\r\n            //cout<<\"MATCH: typeid(First)=\"<<typeid(First).name()<<\" typeid(T)=\"<<typeid(T).name()<<std::endl;\r\n            return (record_manager_single_type<T, Reclaim, Alloc, Pool> *) mgr;\r\n        } else {\r\n            //cout<<\"NO MATCH: typeid(First)=\"<<typeid(First).name()<<\" typeid(T)=\"<<typeid(T).name()<<std::endl;\r\n            return ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->get(recordType);\r\n        }\r\n    }\r\n    // note: recursion should be compiled out\r\n    void clearCounters(void) {\r\n        mgr->clearCounters();\r\n        ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->clearCounters();\r\n    }\r\n    void registerThread(const int tid) {\r\n        mgr->initThread(tid);\r\n        ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->registerThread(tid);\r\n    }\r\n    void unregisterThread(const int tid) {\r\n        mgr->deinitThread(tid);\r\n        ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->unregisterThread(tid);\r\n    }\r\n    void printStatus() {\r\n        mgr->printStatus();\r\n        ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->printStatus();\r\n    }\r\n    inline void qUnprotectAll(const int tid) {\r\n        mgr->qUnprotectAll(tid);\r\n        ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->qUnprotectAll(tid);\r\n    }\r\n    inline void getReclaimers(const int tid, void ** const reclaimers, int index) {\r\n        reclaimers[index] = mgr->reclaim;\r\n        ((RecordManagerSet <Reclaim, Alloc, Pool, Rest...> *) this)->getReclaimers(tid, reclaimers, 1+index);\r\n    }\r\n    inline void enterQuiescentState(const int tid) {\r\n        mgr->enterQuiescentState(tid);\r\n        ((RecordManagerSet<Reclaim, Alloc, Pool, Rest...> *) this)->enterQuiescentState(tid);\r\n    }\r\n    inline void leaveQuiescentStateForEach(const int tid) {\r\n        mgr->leaveQuiescentState(tid, NULL, 0);\r\n        ((RecordManagerSet <Reclaim, Alloc, Pool, Rest...> *) this)->leaveQuiescentStateForEach(tid);\r\n    }\r\n    inline void leaveQuiescentState(const int tid, const bool callForEach) {\r\n        if (callForEach) {\r\n            leaveQuiescentStateForEach(tid);\r\n        } else {\r\n            void * reclaimers[1+sizeof...(Rest)];\r\n            getReclaimers(tid, reclaimers, 0);\r\n            get((First *) NULL)->leaveQuiescentState(tid, reclaimers, 1+sizeof...(Rest));\r\n            __sync_synchronize(); // memory barrier needed (only) for epoch based schemes at the moment...\r\n        }\r\n    }\r\n};\r\n\r\ntemplate <class Reclaim, class Alloc, class Pool, typename RecordTypesFirst, typename... RecordTypesRest>\r\nclass record_manager {\r\nprotected:\r\n    typedef record_manager<Reclaim,Alloc,Pool,RecordTypesFirst,RecordTypesRest...> SelfType;\r\n    RecordManagerSet<Reclaim,Alloc,Pool,RecordTypesFirst,RecordTypesRest...> * rmset;\r\n    \r\n    int init[MAX_TID_POW2] = {0,};\r\n\r\npublic:\r\n    const int NUM_PROCESSES;\r\n    RecoveryMgr<SelfType> * const recoveryMgr;\r\n    \r\n    record_manager(const int numProcesses, const int _neutralizeSignal)\r\n            : NUM_PROCESSES(numProcesses)\r\n            , recoveryMgr(new RecoveryMgr<SelfType>(numProcesses, _neutralizeSignal, this))\r\n    {\r\n        rmset = new RecordManagerSet<Reclaim, Alloc, Pool, RecordTypesFirst, RecordTypesRest...>(numProcesses, (RecoveryMgr<void *> *) recoveryMgr);\r\n    }\r\n    ~record_manager() {\r\n        delete recoveryMgr;\r\n        delete rmset;\r\n    }\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        rmset->registerThread(tid);\r\n        recoveryMgr->initThread(tid);\r\n        enterQuiescentState(tid);\r\n    }\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        rmset->unregisterThread(tid);\r\n    }\r\n    void clearCounters() {\r\n        rmset->clearCounters();\r\n    }\r\n    void printStatus(void) {\r\n        rmset->printStatus();\r\n    }\r\n    template <typename T>\r\n    debugInfo * getDebugInfo(T * const recordType) {\r\n        return &rmset->get((T *) NULL)->debugInfoRecord;\r\n    }\r\n    template<typename T>\r\n    inline record_manager_single_type<T, Reclaim, Alloc, Pool> * get(T * const recordType) {\r\n        return rmset->get((T *) NULL);\r\n    }\r\n    \r\n    // for hazard pointers\r\n\r\n    template <typename T>\r\n    inline bool isProtected(const int tid, T * const obj) {\r\n        return rmset->get((T *) NULL)->isProtected(tid, obj);\r\n    }\r\n    \r\n    template <typename T>\r\n    inline bool protect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool hintMemoryBarrier = true) {\r\n        return rmset->get((T *) NULL)->protect(tid, obj, notRetiredCallback, callbackArg, hintMemoryBarrier);\r\n    }\r\n    \r\n    template <typename T>\r\n    inline void unprotect(const int tid, T * const obj) {\r\n        rmset->get((T *) NULL)->unprotect(tid, obj);\r\n    }\r\n    \r\n    // for DEBRA+\r\n    \r\n    // warning: qProtect must be reentrant and lock-free (i.e., async-signal-safe)\r\n    template <typename T>\r\n    inline bool qProtect(const int tid, T * const obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool hintMemoryBarrier = true) {\r\n        return rmset->get((T *) NULL)->qProtect(tid, obj, notRetiredCallback, callbackArg, hintMemoryBarrier);\r\n    }\r\n    \r\n    template <typename T>\r\n    inline bool isQProtected(const int tid, T * const obj) {\r\n        return rmset->get((T *) NULL)->isQProtected(tid, obj);\r\n    }\r\n    \r\n    inline void qUnprotectAll(const int tid) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        rmset->qUnprotectAll(tid);\r\n    }\r\n\r\n    // for epoch based reclamation\r\n    inline bool isQuiescent(const int tid) {\r\n        return rmset->get((RecordTypesFirst *) NULL)->isQuiescent(tid); // warning: if quiescence information is logically shared between all types, with the actual data being associated only with the first type (as it is here), then isQuiescent will return inconsistent results if called in functions that recurse on the template argument list in this class.\r\n    }\r\n    inline void enterQuiescentState(const int tid) {\r\n//        VERBOSE DEBUG2 COUTATOMIC(\"record_manager_single_type::enterQuiescentState(tid=\"<<tid<<\")\"<<std::endl);\r\n        if (Reclaim::quiescenceIsPerRecordType()) {\r\n//            std::cout<<\"setting quiescent state for all record types\\n\";\r\n            rmset->enterQuiescentState(tid);\r\n        } else {\r\n            // only call enterQuiescentState for one object type\r\n//            std::cout<<\"setting quiescent state for just one record type: \"<<typeid(RecordTypesFirst).name()<<\"\\n\";\r\n            rmset->get((RecordTypesFirst *) NULL)->enterQuiescentState(tid);\r\n        }\r\n    }\r\n    inline void leaveQuiescentState(const int tid) {\r\n//        assert(isQuiescent(tid));\r\n//        VERBOSE DEBUG2 COUTATOMIC(\"record_manager_single_type::leaveQuiescentState(tid=\"<<tid<<\")\"<<std::endl);\r\n        // for some types of reclaimers, different types of records retired in the same\r\n        // epoch can be reclaimed together (by aggregating their epochs), so we don't actually need\r\n        // separate calls to leaveQuiescentState for each object type.\r\n        // if appropriate, we make a single call to leaveQuiescentState,\r\n        // and it takes care of all record types managed by this record manager.\r\n        //cout<<\"quiescenceIsPerRecordType = \"<<Reclaim::quiescenceIsPerRecordType()<<std::endl;\r\n        rmset->leaveQuiescentState(tid, Reclaim::quiescenceIsPerRecordType());\r\n    }\r\n\r\n    // for algorithms that retire nodes before a deletion is linearized\r\n    template <typename T>\r\n    inline void unretireLast(const int tid) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        rmset->get((T *) NULL)->unretireLast(tid);\r\n    }\r\n\r\n    // for all schemes\r\n    template <typename T>\r\n    inline void retire(const int tid, T * const p) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        rmset->get((T *) NULL)->retire(tid, p);\r\n    }\r\n\r\n    template <typename T>\r\n    inline T * allocate(const int tid) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        return rmset->get((T *) NULL)->allocate(tid);\r\n    }\r\n    \r\n    // optional function which can be used if it is safe to call free()\r\n    template <typename T>\r\n    inline void deallocate(const int tid, T * const p) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        rmset->get((T *) NULL)->deallocate(tid, p);\r\n    }\r\n\r\n    inline static bool shouldHelp() { // FOR DEBUGGING PURPOSES\r\n        return Reclaim::shouldHelp();\r\n    }\r\n    inline static bool supportsCrashRecovery() {\r\n        return Reclaim::supportsCrashRecovery();\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/record_manager_single_type.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECORD_MANAGER_SINGLE_TYPE_H\r\n#define\tRECORD_MANAGER_SINGLE_TYPE_H\r\n\r\n#include <pthread.h>\r\n#include <errno.h>\r\n#include <cstring>\r\n#include <iostream>\r\n#include <typeinfo>\r\n\r\n#include \"plaf.h\"\r\n#include \"debug_info.h\"\r\n#include \"globals.h\"\r\n\r\n#include \"recovery_manager.h\"\r\n\r\n#include \"allocator_interface.h\"\r\n#include \"allocator_bump.h\"\r\n#include \"allocator_new.h\"\r\n#include \"allocator_new_segregated.h\"\r\n#include \"allocator_once.h\"\r\n\r\n#include \"pool_interface.h\"\r\n#include \"pool_none.h\"\r\n#include \"pool_perthread_and_shared.h\"\r\n\r\n#include \"reclaimer_interface.h\"\r\n#include \"reclaimer_none.h\"\r\n#include \"reclaimer_debra.h\"\r\n#include \"reclaimer_debraplus.h\"\r\n#include \"reclaimer_hazardptr.h\"\r\n#ifdef USE_RECLAIMER_RCU\r\n#include \"reclaimer_rcu.h\"\r\n#endif\r\n\r\nusing namespace std;\r\n\r\n// maybe Record should be a size\r\ntemplate <typename Record, class Reclaim, class Alloc, class Pool>\r\nclass record_manager_single_type {\r\nprotected:\r\n    typedef Record* record_pointer;\r\n\r\n    typedef typename Alloc::template    rebind<Record>::other              classAlloc;\r\n    typedef typename Pool::template     rebind2<Record, classAlloc>::other classPool;\r\n    typedef typename Reclaim::template  rebind2<Record, classPool>::other  classReclaim;\r\n    \r\npublic:\r\n    classAlloc      *alloc;\r\n    classPool       *pool;\r\n    classReclaim    *reclaim;\r\n    \r\n    const int NUM_PROCESSES;\r\n    debugInfo debugInfoRecord;\r\n    RecoveryMgr<void *> * const recoveryMgr;\r\n\r\n    record_manager_single_type(const int numProcesses, RecoveryMgr<void *> * const _recoveryMgr)\r\n            : NUM_PROCESSES(numProcesses), debugInfoRecord(debugInfo(numProcesses)), recoveryMgr(_recoveryMgr) {\r\n        VERBOSE DEBUG COUTATOMIC(\"constructor record_manager_single_type\"<<std::endl);\r\n        alloc = new classAlloc(numProcesses, &debugInfoRecord);\r\n        pool = new classPool(numProcesses, alloc, &debugInfoRecord);\r\n        reclaim = new classReclaim(numProcesses, pool, &debugInfoRecord, recoveryMgr);\r\n    }\r\n    ~record_manager_single_type() {\r\n        VERBOSE DEBUG COUTATOMIC(\"destructor record_manager_single_type\"<<std::endl);\r\n        delete reclaim;\r\n        delete pool;\r\n        delete alloc;\r\n    }\r\n\r\n    void initThread(const int tid) {\r\n        alloc->initThread(tid);\r\n        reclaim->initThread(tid);\r\n//        enterQuiescentState(tid);\r\n    }\r\n    \r\n    void deinitThread(const int tid) {\r\n        reclaim->deinitThread(tid);\r\n    }\r\n    \r\n    inline void clearCounters() {\r\n        debugInfoRecord.clear();\r\n    }\r\n\r\n    inline static bool shouldHelp() { // FOR DEBUGGING PURPOSES\r\n        return Reclaim::shouldHelp();\r\n    }\r\n    inline bool isProtected(const int tid, record_pointer obj) {\r\n        return reclaim->isProtected(tid, obj);\r\n    }\r\n    // for hazard pointers (and reference counting)\r\n    inline bool protect(const int tid, record_pointer obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool hintMemoryBarrier = true) {\r\n        return reclaim->protect(tid, obj, notRetiredCallback, callbackArg, hintMemoryBarrier);\r\n    }\r\n    inline void unprotect(const int tid, record_pointer obj) {\r\n        reclaim->unprotect(tid, obj);\r\n    }\r\n    // warning: qProtect must be reentrant and lock-free (=== async-signal-safe)\r\n    inline bool qProtect(const int tid, record_pointer obj, CallbackType notRetiredCallback, CallbackArg callbackArg, bool hintMemoryBarrier = true) {\r\n        return reclaim->qProtect(tid, obj, notRetiredCallback, callbackArg, hintMemoryBarrier);\r\n    }\r\n    inline void qUnprotectAll(const int tid) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        reclaim->qUnprotectAll(tid);\r\n    }\r\n    inline bool isQProtected(const int tid, record_pointer obj) {\r\n        return reclaim->isQProtected(tid, obj);\r\n    }\r\n    \r\n    inline static bool supportsCrashRecovery() {\r\n        return Reclaim::supportsCrashRecovery();\r\n    }\r\n    inline static bool quiescenceIsPerRecordType() {\r\n        return Reclaim::quiescenceIsPerRecordType();\r\n    }\r\n    inline bool isQuiescent(const int tid) {\r\n        return reclaim->isQuiescent(tid);\r\n    }\r\n\r\n    // for epoch based reclamation\r\n    inline void enterQuiescentState(const int tid) {\r\n//        VERBOSE DEBUG2 COUTATOMIC(\"record_manager_single_type::enterQuiescentState(tid=\"<<tid<<\")\"<<std::endl);\r\n        reclaim->enterQuiescentState(tid);\r\n    }\r\n    inline void leaveQuiescentState(const int tid, void * const * const reclaimers, const int numReclaimers) {\r\n//        assert(isQuiescent(tid));\r\n        reclaim->leaveQuiescentState(tid, reclaimers, numReclaimers);\r\n    }\r\n\r\n    // for all schemes except reference counting\r\n    inline void retire(const int tid, record_pointer p) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        reclaim->retire(tid, p);\r\n    }\r\n    \r\n    // for algs that retire before the linearization point of a deletion\r\n    inline void unretireLast(const int tid) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        reclaim->unretireLast(tid);\r\n    }\r\n\r\n    // for all schemes\r\n    inline record_pointer allocate(const int tid) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        return pool->get(tid);\r\n    }\r\n    inline void deallocate(const int tid, record_pointer p) {\r\n        assert(!Reclaim::supportsCrashRecovery() || isQuiescent(tid));\r\n        pool->add(tid, p);\r\n    }\r\n\r\n    void printStatus(void) {\r\n        long long allocated = debugInfoRecord.getTotalAllocated();\r\n        long long allocatedBytes = allocated * sizeof(Record);\r\n        long long deallocated = debugInfoRecord.getTotalDeallocated();\r\n        long long recycled = debugInfoRecord.getTotalFromPool() - allocated;\r\n        COUTATOMIC(\"recmgr status for objects of size \"<<sizeof(Record)<<\" and type \"<<typeid(Record).name()<<std::endl);\r\n        COUTATOMIC(\"allocated   : \"<<allocated<<\" objects totaling \"<<allocatedBytes<<\" bytes (\"<<(allocatedBytes/1000000.)<<\"MB)\"<<std::endl);\r\n        COUTATOMIC(\"recycled    : \"<<recycled<<std::endl);\r\n        COUTATOMIC(\"deallocated : \"<<deallocated<<\" objects\"<<std::endl);\r\n        COUTATOMIC(\"pool        : \"<<pool->getSizeString()<<std::endl);\r\n        COUTATOMIC(\"reclaim     : \"<<reclaim->getSizeString()<<std::endl);\r\n        COUTATOMIC(\"unreclaimed : \"<<(allocated - deallocated - atoi(reclaim->getSizeString().c_str()))<<std::endl);\r\n//        COUTATOMIC(endl);\r\n\r\n        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n            reclaim->debugPrintStatus(tid);\r\n        }\r\n        COUTATOMIC(endl);\r\n        \r\n//        for (int tid=0;tid<this->NUM_PROCESSES;++tid) {\r\n//            COUTATOMIC(\"thread \"<<tid<<\" \");\r\n//            alloc->debugPrintStatus(tid);\r\n//            \r\n//            COUTATOMIC(\"    \");\r\n//            //COUTATOMIC(\"allocated \"<<debugInfoRecord.getAllocated(tid)<<\" Nodes\");\r\n//            //COUTATOMIC(\"allocated \"<<(debugInfoRecord.getAllocated(tid) / 1000)<<\"k Nodes\");\r\n//            //COUTATOMIC(\" \");\r\n//            reclaim->debugPrintStatus(tid);\r\n//            COUTATOMIC(\" \");\r\n//            pool->debugPrintStatus(tid);\r\n//            COUTATOMIC(\" \");\r\n//            COUTATOMIC(\"(given=\"<<debugInfoRecord.getGiven(tid)<<\" taken=\"<<debugInfoRecord.getTaken(tid)<<\") toPool=\"<<debugInfoRecord.getToPool(tid)<<\" fromPool=\"<<debugInfoRecord.getFromPool(tid));\r\n//            COUTATOMIC(endl);\r\n//        }\r\n    }\r\n};\r\n\r\n#endif"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/recordmgr/recovery_manager.h",
    "content": "/**\r\n * C++ record manager implementation (PODC 2015) by Trevor Brown.\r\n * \r\n * Copyright (C) 2015 Trevor Brown\r\n *\r\n */\r\n\r\n#ifndef RECOVERY_MANAGER_H\r\n#define\tRECOVERY_MANAGER_H\r\n\r\n#ifdef __CYGWIN__\r\n    struct sigaction { void * sa_sigaction; int sa_flags; int sa_mask; };\r\n    struct siginfo_t {};\r\n    struct sigjmp_buf {};\r\n    #define sigsetjmp(buf, flags) 0\r\n    #define siglongjmp(buf, flags) 0\r\n    #define sigemptyset(x) 0\r\n    #define sigfillset(x) 0\r\n    #define sigaddset(x, sig) 0\r\n    #define pthread_sigmask(sig, set, nul) 0\r\n    #define SIG_UNBLOCK 0\r\n    #define SA_RESTART 0\r\n    #define SA_SIGINFO 0\r\n#else\r\n    #include <setjmp.h>\r\n#endif\r\n\r\n#ifndef VERBOSE\r\n    #define VERBOSE if(0)\r\n#endif\r\n    \r\n#include <cassert>\r\n#include <csignal>\r\n#include \"globals.h\"\r\n#ifdef USE_DEBUGCOUNTERS\r\n    #include \"debugcounter.h\"\r\n#endif\r\n\r\n// for crash recovery\r\nstatic pthread_key_t pthreadkey;\r\nstatic struct sigaction ___act;\r\nstatic void *___singleton = NULL;\r\nextern pthread_key_t pthreadkey;\r\nextern struct sigaction ___act;\r\nextern void *___singleton;\r\n\r\nstatic pthread_t registeredThreads[MAX_TID_POW2];\r\nstatic void *errnoThreads[MAX_TID_POW2];\r\nstatic sigjmp_buf *setjmpbuffers;\r\nextern pthread_t registeredThreads[MAX_TID_POW2];\r\nextern void *errnoThreads[MAX_TID_POW2];\r\nextern sigjmp_buf *setjmpbuffers;\r\n\r\n#ifdef USE_DEBUGCOUNTERS\r\nstatic debugCounter countInterrupted(MAX_TID_POW2);\r\nstatic debugCounter countLongjmp(MAX_TID_POW2);\r\nextern debugCounter countInterrupted;\r\nextern debugCounter countLongjmp;\r\n#endif\r\n#define MAX_THREAD_ADDR 10000\r\n\r\n#ifdef CRASH_RECOVERY_USING_SETJMP\r\n#define CHECKPOINT_AND_RUN_UPDATE(tid, finishedbool) \\\r\n    if (MasterRecordMgr::supportsCrashRecovery() && sigsetjmp(setjmpbuffers[(tid)], 0)) { \\\r\n        recordmgr->enterQuiescentState((tid)); \\\r\n        (finishedbool) = recoverAnyAttemptedSCX((tid), -1); \\\r\n        recordmgr->recoveryMgr->unblockCrashRecoverySignal(); \\\r\n    } else\r\n#define CHECKPOINT_AND_RUN_QUERY(tid) \\\r\n    if (MasterRecordMgr::supportsCrashRecovery() && sigsetjmp(setjmpbuffers[(tid)], 0)) { \\\r\n        recordmgr->enterQuiescentState((tid)); \\\r\n        recordmgr->recoveryMgr->unblockCrashRecoverySignal(); \\\r\n    } else\r\n#endif\r\n\r\n// warning: this crash recovery code will only work if you've created a SINGLE instance of bst during an execution.\r\n// there are ways to make it work for multiple instances; i just haven't done that.\r\ntemplate <class MasterRecordMgr>\r\nvoid crashhandler(int signum, siginfo_t *info, void *uctx) {\r\n    MasterRecordMgr * const recordmgr = (MasterRecordMgr * const) ___singleton;\r\n#ifdef SIGHANDLER_IDENTIFY_USING_PTHREAD_GETSPECIFIC\r\n    int tid = (int) ((long) pthread_getspecific(pthreadkey));\r\n#endif\r\n    TRACE COUTATOMICTID(\"received signal \"<<signum<<std::endl);\r\n\r\n    // if i'm active (not in a quiescent state), i must throw an exception\r\n    // and clean up after myself, instead of continuing my operation.\r\n#ifdef USE_DEBUGCOUNTERS\r\n    DEBUG countInterrupted.inc(tid);\r\n#endif\r\n    __sync_synchronize();\r\n    if (!recordmgr->isQuiescent(tid)) {\r\n#ifdef PERFORM_RESTART_IN_SIGHANDLER\r\n        recordmgr->enterQuiescentState(tid);\r\n    #ifdef USE_DEBUGCOUNTERS\r\n        DEBUG countLongjmp.inc(tid);\r\n    #endif\r\n        __sync_synchronize();\r\n    #ifdef CRASH_RECOVERY_USING_SETJMP\r\n        siglongjmp(setjmpbuffers[tid], 1);\r\n    #endif\r\n#endif\r\n    }\r\n    // otherwise, i simply continue my operation as if nothing happened.\r\n    // this lets me behave nicely when it would be dangerous for me to be\r\n    // restarted (being in a Q state is analogous to having interrupts \r\n    // disabled in an operating system kernel; however, whereas disabling\r\n    // interrupts blocks other processes' progress, being in a Q state\r\n    // implies that you cannot block the progress of any other thread.)\r\n}\r\n\r\ntemplate <class MasterRecordMgr>\r\nclass RecoveryMgr {\r\npublic:\r\n    const int NUM_PROCESSES;\r\n    const int neutralizeSignal;\r\n    \r\n    inline int getTidInefficient(const pthread_t me) {\r\n        int tid = -1;\r\n        for (int i=0;i<NUM_PROCESSES;++i) {\r\n            if (pthread_equal(registeredThreads[i], me)) {\r\n                tid = i;\r\n            }\r\n        }\r\n        // fail to find my tid -- should be impossible\r\n        if (tid == -1) {\r\n            COUTATOMIC(\"THIS SHOULD NEVER HAPPEN\"<<std::endl);\r\n            assert(false);\r\n            exit(-1);\r\n        }\r\n        return tid;\r\n    }\r\n    inline int getTidInefficientErrno() {\r\n        int tid = -1;\r\n        for (int i=0;i<NUM_PROCESSES;++i) {\r\n            // here, we use the fact that errno is defined to be a thread local variable\r\n            if (&errno == errnoThreads[i]) {\r\n                tid = i;\r\n            }\r\n        }\r\n        // fail to find my tid -- should be impossible\r\n        if (tid == -1) {\r\n            COUTATOMIC(\"THIS SHOULD NEVER HAPPEN\"<<std::endl);\r\n            assert(false);\r\n            exit(-1);\r\n        }\r\n        return tid;\r\n    }\r\n    inline int getTid_pthread_getspecific() {\r\n        void * result = pthread_getspecific(pthreadkey);\r\n        if (!result) {\r\n            assert(false);\r\n            COUTATOMIC(\"ERROR: failed to get thread id using pthread_getspecific\"<<std::endl);\r\n            exit(-1);\r\n        }\r\n        return (int) ((long) result);\r\n    }\r\n    inline pthread_t getPthread(const int tid) {\r\n        return registeredThreads[tid];\r\n    }\r\n    \r\n    void initThread(const int tid) {\r\n        // create mapping between tid and pthread_self for the signal handler\r\n        // and for any thread that neutralizes another\r\n        registeredThreads[tid] = pthread_self();\r\n\r\n        // here, we use the fact that errno is defined to be a thread local variable\r\n        errnoThreads[tid] = &errno;\r\n        if (pthread_setspecific(pthreadkey, (void*) (long) tid)) {\r\n            COUTATOMIC(\"ERROR: failure of pthread_setspecific for tid=\"<<tid<<std::endl);\r\n        }\r\n        const long __readtid = (long) ((int *) pthread_getspecific(pthreadkey));\r\n        VERBOSE DEBUG COUTATOMICTID(\"did pthread_setspecific, pthread_getspecific of \"<<__readtid<<std::endl);\r\n        assert(__readtid == tid);\r\n    }\r\n    \r\n    void unblockCrashRecoverySignal() {\r\n        __sync_synchronize();\r\n        sigset_t oldset;\r\n        sigemptyset(&oldset);\r\n        sigaddset(&oldset, neutralizeSignal);\r\n        if (pthread_sigmask(SIG_UNBLOCK, &oldset, NULL)) {\r\n            VERBOSE COUTATOMIC(\"ERROR UNBLOCKING SIGNAL\"<<std::endl);\r\n            exit(-1);\r\n        }\r\n    }\r\n    \r\n    RecoveryMgr(const int numProcesses, const int _neutralizeSignal, MasterRecordMgr * const masterRecordMgr)\r\n            : NUM_PROCESSES(numProcesses) , neutralizeSignal(_neutralizeSignal){\r\n        setjmpbuffers = new sigjmp_buf[numProcesses];\r\n        pthread_key_create(&pthreadkey, NULL);\r\n        \r\n#ifndef __CYGWIN__\r\n        if (MasterRecordMgr::supportsCrashRecovery()) {\r\n            // set up crash recovery signal handling for this process\r\n            memset(&___act, 0, sizeof(___act));\r\n            ___act.sa_sigaction = crashhandler<MasterRecordMgr>; // specify signal handler\r\n            ___act.sa_flags = SA_RESTART | SA_SIGINFO; // restart any interrupted sys calls instead of silently failing\r\n            sigfillset(&___act.sa_mask);               // block signals during handler\r\n            if (sigaction(_neutralizeSignal, &___act, NULL)) {\r\n                COUTATOMIC(\"ERROR: could not register signal handler for signal \"<<_neutralizeSignal<<std::endl);\r\n                assert(false);\r\n                exit(-1);\r\n            } else {\r\n                VERBOSE COUTATOMIC(\"registered signal \"<<_neutralizeSignal<<\" for crash recovery\"<<std::endl);\r\n            }\r\n        }\r\n#endif\r\n        // set up shared pointer to this class instance for the signal handler\r\n        ___singleton = (void *) masterRecordMgr;\r\n    }\r\n    ~RecoveryMgr() {\r\n        delete[] setjmpbuffers;\r\n    }\r\n};\r\n\r\n#endif\t/* RECOVERY_MANAGER_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_dcssp.h",
    "content": "/* \r\n * File:   rq_dcssp.h\r\n * Author: trbot\r\n *\r\n * Created on May 9, 2017, 4:30 PM\r\n */\r\n\r\n#ifndef RQ_DCSSP_H\r\n#define\tRQ_DCSSP_H\r\n\r\n#ifdef ADD_DELAY_BEFORE_DTIME\r\nextern Random rngs[MAX_TID_POW2*PREFETCH_SIZE_WORDS];\r\n#define GET_RAND(tid,n) (rngs[(tid)*PREFETCH_SIZE_WORDS].nextNatural((n)))\r\n#define DELAY_UP_TO(n) { \\\r\n    unsigned __r = GET_RAND(tid,(n)); \\\r\n    for (int __i=0;__i<__r;++__i) { \\\r\n        SOFTWARE_BARRIER; \\\r\n    } \\\r\n}\r\n#else\r\n#define DELAY_UP_TO(n) \r\n#endif\r\n\r\n#ifdef RQ_LOCKFREE_WAITS_FOR_DTIME\r\n#define WAIT_FOR_DTIME(node) ({ while ((node)->dtime == TIMESTAMP_NOT_SET) ; true; })\r\n#else\r\n#define WAIT_FOR_DTIME(node) ({ false; })\r\n#endif\r\n\r\n#include <pthread.h>\r\n#include <hashlist.h>\r\n#include \"rq_debugging.h\"\r\n#include \"dcss_plus_impl.h\"\r\n\r\ntemplate <typename T>\r\ninline bool contains(T ** nullTerminatedArray, T * element) {\r\n    for (int i=0;nullTerminatedArray[i];++i) {\r\n        if (nullTerminatedArray[i] == element) return true;\r\n    }\r\n    return false;\r\n}\r\n\r\ntemplate <typename T>\r\ninline bool contains(T * array, const int numElements, T element) {\r\n    for (int i=0;i<numElements;++i) {\r\n        if (array[i] == element) return true;\r\n    }\r\n    return false;\r\n}\r\n\r\n#define SNAPSHOT_CONTAINS_INSERTED_NODE(snap, node) contains((void **) (snap).payload1, (void *) (node))\r\n#define SNAPSHOT_CONTAINS_DELETED_NODE(snap, node) contains((void **) (snap).payload2, (void *) (node))\r\n\r\ntemplate <typename K, typename V, typename NodeType, typename DataStructure, typename RecordManager, bool logicalDeletion, bool canRetireNodesLogicallyDeletedByOtherProcesses>\r\nclass RQProvider {\r\nprivate:\r\n    struct __rq_thread_data {\r\n        #define __RQ_THREAD_DATA_SIZE 1024\r\n        #define MAX_NODES_DELETED_ATOMICALLY 8\r\n        #define CODE_COVERAGE_MAX_PATHS 11\r\n        union {\r\n            struct { // anonymous struct inside anonymous union means we don't need to type anything special to access these variables\r\n                long long rq_lin_time;\r\n                HashList<K> * hashlist;\r\n#ifdef COUNT_CODE_PATH_EXECUTIONS\r\n                long long codePathExecutions[CODE_COVERAGE_MAX_PATHS];\r\n#endif\r\n                volatile char padding0[PREFETCH_SIZE_BYTES];\r\n                void * announcements[MAX_NODES_DELETED_ATOMICALLY];\r\n                int numAnnouncements;\r\n            };\r\n            char bytes[__RQ_THREAD_DATA_SIZE]; // avoid false sharing (note: anon struct above contains around 96 bytes)\r\n        };\r\n    } __attribute__((aligned(__RQ_THREAD_DATA_SIZE)));\r\n    \r\n#ifdef COUNT_CODE_PATH_EXECUTIONS\r\n    #define COUNT_CODE_PATH(path) { assert((path) < CODE_COVERAGE_MAX_PATHS); (++threadData[tid].codePathExecutions[(path)]); }\r\n    long long codePathExecutions[CODE_COVERAGE_MAX_PATHS];\r\n#else\r\n    #define COUNT_CODE_PATH(path) \r\n#endif\r\n\r\n    #define TIMESTAMP_NOT_SET 0\r\n    #define HASHLIST_INIT_CAPACITY_POW2 (1<<8)\r\n\r\n    const int NUM_PROCESSES;\r\n    volatile char padding0[PREFETCH_SIZE_BYTES];\r\n    volatile long long timestamp = 1;\r\n    volatile char padding1[PREFETCH_SIZE_BYTES];\r\n    __rq_thread_data * threadData;\r\n\r\n    #define NODE_DELETED_BEFORE_RQ 0\r\n    #define NODE_DELETED_AFTER_RQ 1\r\n    #define NODE_NOT_DELETED_BY_THREAD -1\r\n    dcsspProvider<void *> * prov;\r\n    \r\n    DataStructure * ds;\r\n    RecordManager * const recmgr;\r\n\r\n    int init[MAX_TID_POW2] = {0,};\r\n\r\npublic:\r\n    RQProvider(const int numProcesses, DataStructure * ds, RecordManager * recmgr) : NUM_PROCESSES(numProcesses), ds(ds), recmgr(recmgr) {\r\n        prov = new dcsspProvider<void *>(numProcesses);\r\n        threadData = new __rq_thread_data[numProcesses];\r\n        DEBUG_INIT_RQPROVIDER(numProcesses);\r\n#ifdef COUNT_CODE_PATH_EXECUTIONS\r\n        for (int i=0;i<CODE_COVERAGE_MAX_PATHS;++i) {\r\n            codePathExecutions[i] = 0;\r\n        }\r\n#endif\r\n    }\r\n    \r\n    ~RQProvider() {\r\n#ifdef COUNT_CODE_PATH_EXECUTIONS\r\n        cout<<\"code path executions:\";\r\n        for (int i=0;i<CODE_COVERAGE_MAX_PATHS;++i) {\r\n            if (codePathExecutions[i]) {\r\n                cout<<\" \"<<codePathExecutions[i];\r\n            } else {\r\n                cout<<\" .\";\r\n            }\r\n        }\r\n        cout<<endl;\r\n#endif\r\n//        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n//            prov->deinitThread(tid);\r\n//            threadData[tid].hashlist->destroy();\r\n//            delete threadData[tid].hashlist;\r\n//        }\r\n        \r\n        prov->debugPrint();\r\n        delete prov;\r\n        delete[] threadData;\r\n        DEBUG_DEINIT_RQPROVIDER(NUM_PROCESSES);\r\n    }\r\n    \r\n    // invoke before a given thread can invoke any functions on this object\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        prov->initThread(tid);\r\n        threadData[tid].hashlist = new HashList<K>();\r\n        threadData[tid].hashlist->init(HASHLIST_INIT_CAPACITY_POW2);\r\n        threadData[tid].numAnnouncements = 0;\r\n        for (int i=0;i<MAX_NODES_DELETED_ATOMICALLY;++i) {\r\n            threadData[tid].announcements[i] = NULL;\r\n        }\r\n#ifdef COUNT_CODE_PATH_EXECUTIONS\r\n        for (int i=0;i<CODE_COVERAGE_MAX_PATHS;++i) {\r\n            threadData[tid].codePathExecutions[i] = 0;\r\n        }\r\n#endif\r\n        DEBUG_INIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke once a given thread will no longer invoke any functions on this object\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        prov->deinitThread(tid);\r\n        threadData[tid].hashlist->destroy();\r\n        delete threadData[tid].hashlist;\r\n#ifdef COUNT_CODE_PATH_EXECUTIONS\r\n        for (int i=0;i<CODE_COVERAGE_MAX_PATHS;++i) {\r\n            __sync_fetch_and_add(&codePathExecutions[i], threadData[tid].codePathExecutions[i]);\r\n        }\r\n#endif\r\n        DEBUG_DEINIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke whenever a new node is created/initialized\r\n    inline void init_node(const int tid, NodeType * const node) {\r\n        node->itime = TIMESTAMP_NOT_SET;\r\n        node->dtime = TIMESTAMP_NOT_SET;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any initialization of addr\r\n    // with invocations of rq_write_addr\r\n    //\r\n    // NOTE: this CANNOT be used on fields that might be concurrently being modified\r\n    // by an invocation of rq_linearize_update_at_write or\r\n    // rq_linearize_update_at_cas\r\n    template <typename T>\r\n    inline void write_addr(const int tid, T volatile * const addr, const T val) {\r\n        if (is_pointer<T>::value) {\r\n            prov->writePtr((casword_t *) addr, (casword_t) val);\r\n        } else {\r\n            prov->writeVal((casword_t *) addr, (casword_t) val);\r\n        }\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any reads of addr with\r\n    // invocations of rq_read_addr\r\n    template <typename T>\r\n    inline T read_addr(const int tid, T volatile * const addr) {\r\n        return (T) ((is_pointer<T>::value)\r\n                ? prov->readPtr(tid, (casword_t *) addr)\r\n                : prov->readVal(tid, (casword_t *) addr));\r\n    }\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run some time BEFORE the physical deletion of a node\r\n    // whose key has ALREADY been logically deleted.\r\n    void announce_physical_deletion(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            threadData[tid].announcements[threadData[tid].numAnnouncements+i] = deletedNodes[i];\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        threadData[tid].numAnnouncements += i;\r\n        assert(threadData[tid].numAnnouncements <= MAX_NODES_DELETED_ATOMICALLY);\r\n        SOFTWARE_BARRIER;\r\n    }\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node failed.\r\n    void physical_deletion_failed(const int tid, NodeType * const * const deletedNodes) {\r\n        for (int i=0;deletedNodes[i];++i) {\r\n            --threadData[tid].numAnnouncements;\r\n        }\r\n        assert(threadData[tid].numAnnouncements >= 0);\r\n    }\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node succeeded.\r\n    void physical_deletion_succeeded(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            recmgr->retire(tid, deletedNodes[i]);\r\n        }\r\n        SOFTWARE_BARRIER; // ensure nodes are placed in the epoch bag BEFORE they are removed from announcements.\r\n        threadData[tid].numAnnouncements -= i;\r\n        assert(threadData[tid].numAnnouncements >= 0);\r\n    }\r\n    \r\nprivate:\r\n    \r\n    inline void set_insertion_timestamps(\r\n            const int tid,\r\n            const long long ts,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        // set insertion timestamps\r\n        // for each i_node in insertedNodes\r\n        for (int i_nodeix=0;insertedNodes[i_nodeix];++i_nodeix) {\r\n            insertedNodes[i_nodeix]->itime = ts;\r\n        }\r\n    }\r\n\r\n    inline void set_deletion_timestamps(\r\n            const int tid,\r\n            const long long ts,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        // set deletion timestamps\r\n        // for each d_node in deletedNodes\r\n        for (int d_nodeix=0;deletedNodes[d_nodeix];++d_nodeix) {\r\n            deletedNodes[d_nodeix]->dtime = ts;\r\n        }\r\n    }\r\n    \r\npublic:\r\n    \r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a WRITE\r\n    template <typename T>\r\n    inline T linearize_update_at_write(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n        casword_t old1;\r\n        while (true) {\r\n            old1 = (casword_t) timestamp;\r\n\r\n            casword_t old2 = (is_pointer<T>::value)\r\n                    ? (casword_t) prov->readPtr(tid, (casword_t *) lin_addr)\r\n                    : (casword_t) prov->readVal(tid, (casword_t *) lin_addr);\r\n            casword_t new2 = (casword_t) lin_newval;\r\n            dcsspresult_t result = (is_pointer<T>::value)\r\n                    ? prov->dcsspPtr(tid, (casword_t *) &timestamp, old1, (casword_t *) lin_addr, old2, new2, (void **) insertedNodes, (void **) deletedNodes)\r\n                    : prov->dcsspVal(tid, (casword_t *) &timestamp, old1, (casword_t *) lin_addr, old2, new2, (void **) insertedNodes, (void **) deletedNodes);\r\n            if (result.status == DCSSP_SUCCESS) {\r\n                break;\r\n            }\r\n        }\r\n        //DELAY_UP_TO(10000);\r\n\r\n        set_insertion_timestamps(tid, old1 /* timestamp */, insertedNodes, deletedNodes);\r\n        set_deletion_timestamps(tid, old1 /* timestamp */, insertedNodes, deletedNodes);\r\n        \r\n        // discard the payloads (insertedNodes and deletedNodes) in this thread's descriptor\r\n        // so other threads can't access them far in the future if we become QUIESCENT and sleep for a long time\r\n        // (must be performed after setting itimes and dtimes, but before enterQuiescentState)\r\n        prov->discardPayloads(tid);\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            physical_deletion_succeeded(tid, deletedNodes);\r\n        }\r\n        \r\n#if defined USE_RQ_DEBUGGING\r\n        DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, old1 /* timestamp */, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        return lin_newval;\r\n    }\r\n\r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a CAS\r\n    template <typename T>\r\n    inline T linearize_update_at_cas(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_oldval,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n        casword_t old2 = (casword_t) lin_oldval;\r\n        casword_t new2 = (casword_t) lin_newval;\r\n        dcsspresult_t result;\r\n        while (true) {\r\n            casword_t old1 = (casword_t) timestamp;\r\n\r\n            result = (is_pointer<T>::value)\r\n                    ? prov->dcsspPtr(tid, (casword_t *) &timestamp, old1 /* timestamp */, (casword_t *) lin_addr, old2, new2, (void **) insertedNodes, (void **) deletedNodes)\r\n                    : prov->dcsspVal(tid, (casword_t *) &timestamp, old1 /* timestamp */, (casword_t *) lin_addr, old2, new2, (void **) insertedNodes, (void **) deletedNodes);\r\n            if (result.status == DCSSP_SUCCESS) {\r\n                //DELAY_UP_TO(1000);\r\n\r\n                set_insertion_timestamps(tid, old1 /* timestamp */, insertedNodes, deletedNodes);\r\n                set_deletion_timestamps(tid, old1 /* timestamp */, insertedNodes, deletedNodes);\r\n\r\n                // discard the payloads (insertedNodes and deletedNodes) in this thread's descriptor\r\n                // so other threads can't access them far in the future if we become QUIESCENT and sleep for a long time\r\n                // (must be performed after setting itimes and dtimes, but before enterQuiescentState)\r\n                prov->discardPayloads(tid);\r\n                \r\n                if (!logicalDeletion) {\r\n                    // physical deletion will happen at the same time as logical deletion\r\n                    physical_deletion_succeeded(tid, deletedNodes);\r\n                }             \r\n                \r\n#if defined USE_RQ_DEBUGGING\r\n                DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, old1 /* timestamp */, insertedNodes, deletedNodes, ds);\r\n#endif\r\n                return lin_oldval;\r\n            } else if (result.status == DCSSP_FAILED_ADDR2) {\r\n                // failed due to original CAS's failure (NOT due to the timestamp changing)\r\n\r\n                if (!logicalDeletion) {\r\n                    // physical deletion will happen at the same time as logical deletion\r\n                    physical_deletion_failed(tid, deletedNodes);\r\n                }\r\n                \r\n                break;\r\n            }\r\n        }\r\n        assert(result.status == DCSSP_FAILED_ADDR2);\r\n        assert(old2 != result.failed_val);\r\n        return (T) result.failed_val;\r\n    }\r\n\r\n    // invoke at the start of each traversal\r\n    inline void traversal_start(const int tid) {\r\n        threadData[tid].hashlist->clear();\r\n        threadData[tid].rq_lin_time = __sync_add_and_fetch(&timestamp, 1);      // linearize rq here!\r\n    }\r\n\r\nprivate:\r\n    // invoke each time a traversal visits a node with a key in the desired range:\r\n    // if the node belongs in the range query, it will be placed in rqResult[index]\r\n    inline int __traversal_try_add(const int tid, NodeType * const node, K * const outputKeys, V * const outputValues, const K& lo, const K& hi, bool foundDuringTraversal) {\r\n\r\n        // rqResultKeys should have space for MAX_KEYS_PER_NODE keys, AT LEAST\r\n        \r\n        // in the following, rather than having deeply nested if-else blocks,\r\n        // we return asap, and list facts that must be true if we didn't return\r\n        assert(foundDuringTraversal || !logicalDeletion || ds->isLogicallyDeleted(tid, node));\r\n\r\n        // TODO: ensure this makes sense when called with announced nodes\r\n        \r\n        long long itime = node->itime;\r\n        if (itime != TIMESTAMP_NOT_SET & node->itime >= threadData[tid].rq_lin_time) return 0; // node was inserted after the range query\r\n        // fact: either itime was not set above, or node was inserted before rq\r\n        \r\n        ///////////////////////// HANDLE UNKNOWN ITIME /////////////////////////\r\n\r\n        // TODO: try adding a bit of spinning before falling back to the full lock-free solution\r\n        \r\n        // determine if any other process inserted, or is trying to insert node, and, if so, when\r\n        for (int otherTid=0; (itime = node->itime) == TIMESTAMP_NOT_SET && otherTid<NUM_PROCESSES; ++otherTid) if (otherTid != tid) {\r\n            tagptr_t tagptr = prov->getDescriptorTagptr(otherTid);              // try to get a snapshot of otherTid's dcssp descriptor\r\n            dcsspdesc_t<void *> snap;\r\n            if (!prov->getDescriptorSnapshot(tagptr, &snap)) {                  // we failed to obtain a snapshot, which means that while getDescriptorSnapshot() was running, the process finished one dcssp, and started a new dcssp.\r\n                continue; // goto check next process                            // if the finished dcssp inserted node, then before the next dcssp by the same process, node->itime is set. so, we check whether itime is set.\r\n            }\r\n            // fact: we obtained a snapshot\r\n\r\n            if (!SNAPSHOT_CONTAINS_INSERTED_NODE(snap, node)) continue; // goto check next process\r\n            // fact: otherTid is trying/tried to insert node\r\n\r\n            int state = MUTABLES_UNPACK_FIELD(snap.mutables, DCSSP_MUTABLES_MASK_STATE, DCSSP_MUTABLES_OFFSET_STATE);\r\n            if (state == DCSSP_STATE_FAILED) {                                  // the operation described by snap did not insert node, so either this process did not insert it, or the process inserted/inserted it in a PREVIOUS operation, so it must have already set itime as appropriate\r\n                continue; // goto check next process\r\n            } else if (state == DCSSP_STATE_SUCCEEDED) {                        // the dcssp operation finished, and inserted node. to determine WHEN it inserted node, we look at the argument old1 to the dcssp, which contains the timestamp when the dcssp took place. (observe that this is the value process otherTid would write to node->itime)\r\n                if (snap.old1 >= threadData[tid].rq_lin_time) return 0;         // node was inserted after rq\r\n                break; // process inserted node at time snap.old1, BEFORE the RQ\r\n            }\r\n            // fact: state is UNDECIDED\r\n            \r\n            // now we try to help\r\n            casword_t addr2 = *snap.addr2;\r\n            if (addr2 == tagptr) {                                              // addr2 indeed points to the dcssp descriptor. the linearization point of the dcssp operation occurs after this step, so the dcssp might have been linearized, but not yet had its state set.\r\n                prov->helpProcess(tid, otherTid);                               // we need to know what its final state will be to determine whether it successfully inserted node. so, we HELP otherTid finish its dcssp.\r\n            }\r\n            // note: the following all happens in BOTH the cases where addr2 == tagptr and where addr2 != tagptr, except there is some extra work if addr2 != tagptr and state2 != SUCCEEDED. i've folded the two cases together simply for compactness / less repetition.\r\n\r\n            // then, we reread the state\r\n            bool valid = false;\r\n            dcsspdesc_t<void *> * ptr = prov->getDescriptorPtr(tagptr);\r\n            int state2 = DESC_READ_FIELD(valid, ptr->mutables, tagptr, DCSSP_MUTABLES_MASK_STATE, DCSSP_MUTABLES_OFFSET_STATE);\r\n            if (!valid) continue; // goto check next process                    // the read of the state field was invalid, which means that the dcssp operation has terminated, the next dcssp operation by otherTid has begun. since the next dcssp operation has begun, and each high-level data structure operation performs only one successful dcssp (in a call to linearize_update_at_...), if this dcssp that finished in fact inserted node, then the next dcssp would be part of the next high-level operation. thus, if node->itime was inserted by the finished dcssp, then the high-level operation that performed this dcssp will already have set node->itime.\r\n            // fact: the read of state was valid\r\n            \r\n            if (state2 == DCSSP_STATE_SUCCEEDED) {                              // we are in case (b) described above. the dcssp operation finished, and insert node. to determine WHEN it inserted node, we look at the argument old1 to the dcssp, which contains the timestamp when the dcssp took place. (observe that this is the value process otherTid would write to node->itime)\r\n                if (snap.old1 >= threadData[tid].rq_lin_time) return 0;         // node was inserted after rq\r\n                break; // process inserted node at time snap.old1, BEFORE the RQ\r\n            } else { // undecided or failed\r\n                continue; // goto check next process                            // we are in case (a) or case (c) described above. so, otherTid did NOT delete node.\r\n            }\r\n        }\r\n        if (itime != TIMESTAMP_NOT_SET && itime >= threadData[tid].rq_lin_time) return 0; // node was inserted after rq\r\n\r\n        /////////////// HANDLE LOGICAL DELETION AND CHECK DTIME ////////////////\r\n        \r\n        long long dtime = TIMESTAMP_NOT_SET;\r\n\r\n        if (!logicalDeletion && foundDuringTraversal) goto tryAddToRQ;          // no logical deletion. since node was inserted before the range query, and the traversal encountered it, it must have been deleted AFTER the traversal encountered it.\r\n        // fact: no logical deletion ==> did not find node during traversal\r\n\r\n        dtime = node->dtime;\r\n        if (dtime != TIMESTAMP_NOT_SET && dtime < threadData[tid].rq_lin_time) return 0;\r\n        // fact: either dtime was not set above, or node was deleted after rq\r\n\r\n        if (logicalDeletion && !ds->isLogicallyDeleted(tid, node)) goto tryAddToRQ; // if logical deletion is used with marking, the fact that node was inserted before the range query, and that the traversal encountered node, is NOT enough to argue that node was in the data structure when the traversal started. why? when the traversal encountered node, it might have already been marked. so, we check if node is marked. if not, then the node has not yet been deleted.\r\n        // fact: logical deletion ==> node has been logically deleted\r\n        \r\n        ///////////////////////// HANDLE UNKNOWN DTIME /////////////////////////\r\n        \r\n        // determine if any other process is trying/tried to delete node\r\n        for (int otherTid=0; (dtime = node->dtime) == TIMESTAMP_NOT_SET && otherTid<NUM_PROCESSES; ++otherTid) if (otherTid != tid) {\r\n            tagptr_t tagptr = prov->getDescriptorTagptr(otherTid);              // try to get a snapshot of otherTid's dcssp descriptor\r\n            dcsspdesc_t<void *> snap;\r\n            if (!prov->getDescriptorSnapshot(tagptr, &snap)) {                  // we failed to obtain a snapshot, which means that while getDescriptorSnapshot() was running, the process finished one dcssp, and started a new dcssp.\r\n                continue; // goto check next process                            // if the finished dcssp deleted node, then before the next dcssp by the same process, node->dtime is set (and it will be seen after the loop).\r\n            }\r\n            // fact: we obtained a snapshot\r\n\r\n            if (!SNAPSHOT_CONTAINS_DELETED_NODE(snap, node)) continue; // goto check next process\r\n            // fact: otherTid is trying/tried to delete node\r\n\r\n            // we must determine whether otherTid's dcssp operation (whose descriptor we obtained a snapshot of) has been linearized, and whether it was successful.\r\n            // we use the following facts.\r\n            // (1) the dcssp descriptor has a state that is initially UNDECIDED, and becomes SUCCEEDED or FAILED after the dcssp has been linearized.\r\n            // (2) a dcssp that succeeds or fails changes *snap.addr2 to tagptr, then reads *snap.addr1 and linearizes, then sets its state to SUCCEEDED or FAILED, then changes *snap.addr2 from tagptr to another value.\r\n            // (3) once *snap.addr2 has been changed from tagptr to another value, it can never again contain tagptr.\r\n            // (4) each high-level data structure operation invokes dcssp only via linearize_update_at_write or linearize_update_at_cas, and only performs one invocation of linearize_update_at_write or one /successful/ invocation of linearize_update_at_cas (and possibly many unsuccessful invocations of linearize_update_at_cas).\r\n            // (5) if a dcssp operation deletes node, then before the next dcssp by the same process, node->dtime is set.\r\n            // so, we check the state of the dcssp operation. if it is SUCCEEDED or FAILED, we have our answer. but, if the state is UNDECIDED, the dcssp may or may not have been linearized.\r\n            // in the latter case, to determine whether it has been linearized, we would like to HELP the dcssp operation to complete.\r\n            // note, however, that the help procedure for the dcssp algorithm can be invoked only if otherTid has already changed *snap.addr2 to tagptr.\r\n            // thus, we must determine whether otherTid has changed *snap.addr2 to tagptr, before we can help the dcssp operation.\r\n            // so, we read *snap.addr2. if we see that it contains tagptr, then we can help the dcssp.\r\n            // otherwise, one of the following must be true:\r\n            // (a) otherTid has not yet changed *snap.addr2 to tagptr, or\r\n            // (b) otherTid changed *snap.addr2 to tagptr, then it (or a helper) changed its state to SUCCEEDED, then changed *snap.addr2 to a different value (never again to contain tagptr), or\r\n            // (c) otherTid changed *snap.addr2 to tagptr, then it (or a helper) changed its state to FAILED, then changed *snap.addr2 to a different value (never again to contain tagptr).\r\n            // in case (a), we know that the dcssp has not yet been linearized.\r\n            // in case (b), the dcssp has been linearized, has state SUCCEEDED, and deleted node.\r\n            // in case (c), the dcssp has been linearized, has state FAILED, and did NOT delete node.\r\n            // so, after reading *snap.addr2, we read the dcssp operation's state again to determine which case has occurred.\r\n\r\n            int state = MUTABLES_UNPACK_FIELD(snap.mutables, DCSSP_MUTABLES_MASK_STATE, DCSSP_MUTABLES_OFFSET_STATE);\r\n            if (state == DCSSP_STATE_FAILED) {                                  // the operation described by snap did not insert/delete node, so either this process did not insert/delete it, or the process inserted/deleted it in a PREVIOUS operation, so it must have already set itime/dtime as appropriate\r\n                continue; // goto check next process\r\n            } else if (state == DCSSP_STATE_SUCCEEDED) {                        // the dcssp operation finished, and deleted node. to determine WHEN it deleted node, we look at the argument old1 to the dcssp, which contains the timestamp when the dcssp took place. (observe that this is the value process otherTid would write to node->dtime)\r\n                if (WAIT_FOR_DTIME(node)) {\r\n                    // the following assertions are thread safe ONLY if WAIT_FOR_DTIME actually waits! (which is true only if it returns true, which is true only if RQ_LOCKFREE_WAITS_FOR_DTIME is defined)\r\n                    assert(snap.old1 <= node->dtime);\r\n                    assert((snap.old1 >= threadData[tid].rq_lin_time) == (node->dtime >= threadData[tid].rq_lin_time));\r\n                    assert(foundDuringTraversal || node->dtime == snap.old1);\r\n                    assert(!foundDuringTraversal || node->dtime == snap.old1);\r\n                }\r\n                if (snap.old1 < threadData[tid].rq_lin_time) return 0;          // node was deleted before rq\r\n                goto tryAddToRQ; // node was deleted by this process after rq\r\n            }\r\n            // fact: state is UNDECIDED\r\n            \r\n            // maya: in logicalDeletion, since the node is marked the DCSS was successful and only the dtime is not yet set. Thus, UNDECIDED means that otherThread did not mark the node, it was some other thread and we can continue. \r\n            if (logicalDeletion) continue; // goto check next process\r\n\r\n            // now we try to help\r\n            casword_t addr2 = *snap.addr2;\r\n            if (addr2 == tagptr) {                                              // TODO: prove it is impossible to execute this block with logical deletion (idea: since node is marked, either (1) otherTid marked it earlier with a DCSS whose state is SUCCEEDED, or (2) someone else marked node, so otherTid cannot successfully CAS addr2.)\r\n                // addr2 indeed points to the dcssp descriptor. the linearization point of the dcssp operation occurs after this step, so the dcssp might have been linearized, but not yet had its state set.\r\n                prov->helpProcess(tid, otherTid);                       // we need to know what its final state will be to determine whether it successfully deleted node. so, we HELP otherTid finish its dcssp.\r\n            }\r\n            // note: the following all happens in BOTH the cases where addr2 == tagptr and where addr2 != tagptr, except there is some extra work if addr2 != tagptr and state2 != SUCCEEDED. i've folded the two cases together simply for compactness / less repetition.\r\n\r\n            // then, we reread the state\r\n            bool valid = false;\r\n            dcsspdesc_t<void *> * ptr = prov->getDescriptorPtr(tagptr);\r\n            int state2 = DESC_READ_FIELD(valid, ptr->mutables, tagptr, DCSSP_MUTABLES_MASK_STATE, DCSSP_MUTABLES_OFFSET_STATE);\r\n            if (!valid) continue; // goto check next process                    // the read of the state field was invalid, which means that the dcssp operation has terminated, the next dcssp operation by otherTid has begun. since the next dcssp operation has begun, and each high-level data structure operation performs only one successful dcssp (in a call to linearize_update_at_...), if this dcssp that finished in fact deleted node, then the next dcssp would be part of the next high-level operation. thus, if node->itime was inserted by the finished dcssp, then the high-level operation that performed this dcssp will already have set node->itime.\r\n            // fact: the read of state was valid\r\n\r\n            if (state2 == DCSSP_STATE_SUCCEEDED) {                              // we are in case (b) described above. the dcssp operation finished, and deleted node. to determine WHEN it deleted node, we look at the argument old1 to the dcssp, which contains the timestamp when the dcssp took place. (observe that this is the value process otherTid would write to node->dtime)\r\n                if (snap.old1 >= threadData[tid].rq_lin_time) goto tryAddToRQ;\r\n                return 0; // do not add to rq\r\n            } else { // undecided or failed\r\n                continue; // goto check next process                            // we are in case (a) or case (c) described above. so, otherTid did NOT delete node.\r\n            }\r\n        }\r\n        if(dtime == TIMESTAMP_NOT_SET) {\r\n            assert(!logicalDeletion); \r\n            assert(!foundDuringTraversal);\r\n            goto tryAddToRQ; // no process deleted node before the range query\r\n        }\r\n        COUNT_CODE_PATH(9);\r\n        if (dtime >= threadData[tid].rq_lin_time) goto tryAddToRQ;\r\n        return 0; // do not add to rq\r\n\r\n        ///////////////////// TRY TO ADD NODE'S KEYS TO RQ /////////////////////\r\n        // note: this way of organizing this decision tree favors trees with fat multi-key nodes, because getKeys is delayed as long as possible.\r\n        \r\ntryAddToRQ:\r\n        // fetch the node's keys that are in the set\r\n        int cnt = ds->getKeys(tid, node, outputKeys, outputValues);\r\n        assert(cnt < RQ_DEBUGGING_MAX_KEYS_PER_NODE);\r\n        if (cnt == 0) return 0;                                                 // node doesn't contain any keys that are in the set and in the desired range\r\n        \r\n        // note: in the following loop, we shift keys in the outputKeys array left to eliminate any that ultimately should not be added to the range query\r\n        int numNewKeys = 0;\r\n        for (int i=0;i<cnt;++i) {                                               // decide whether key = outputKeys[i] should be in the range query\r\n            if (!ds->isInRange(outputKeys[i], lo, hi)) goto doNotAddToRQ;       // key is NOT in the desired range\r\n            if (threadData[tid].hashlist->contains(outputKeys[i])) goto doNotAddToRQ; // key is already in the range query\r\n            outputKeys[numNewKeys] = outputKeys[i];                             // save this as a new key added to the RQ\r\n            outputValues[numNewKeys] = outputValues[i];\r\n            ++numNewKeys;\r\n\r\ndoNotAddToRQ: (0);\r\n        }\r\n        return numNewKeys;\r\n    }\r\n\r\n    inline void traversal_try_add(const int tid, NodeType * const node, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi, bool foundDuringTraversal) {\r\n//#if defined MICROBENCH && !defined NDEBUG\r\n//        assert(*startIndex < RQSIZE); // note: this assert is a hack. it should be *startIndex < size of rqResultKeys\r\n//        if (*startIndex > RQSIZE) {\r\n//            cout<<\"ERROR: *startIndex=\"<<(*startIndex)<<\" is unexpectedly greater than or equal to RQSIZE=\"<<RQSIZE<<\" (lo=\"<<lo<<\" hi=\"<<hi<<\")\"<<endl;\r\n//            cout<<\"results:\";\r\n//            for (int i=0;i<*startIndex;++i) {\r\n//                cout<<\" \"<<rqResultKeys[i];\r\n//            }\r\n//            cout<<endl;\r\n//            exit(-1);\r\n//        }\r\n//#endif\r\n        int numNewKeys = __traversal_try_add(tid, node, rqResultKeys+(*startIndex), rqResultValues+(*startIndex), lo, hi, foundDuringTraversal);\r\n//#if defined MICROBENCH\r\n//        assert(*startIndex + numNewKeys < 2*RQSIZE); // note: this assert is a hack. it should be *startIndex + numNewKeys < size of rqResultKeys array\r\n//#endif\r\n        for (int i=0;i<numNewKeys;++i) {\r\n            threadData[tid].hashlist->insert(rqResultKeys[(*startIndex)++]);\r\n        }\r\n        // note: the above increments startIndex\r\n#if defined MICROBENCH\r\n        assert(*startIndex <= RQSIZE);\r\n#endif\r\n    }\r\n    \r\npublic:\r\n    inline void traversal_try_add(const int tid, NodeType * const node, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        traversal_try_add(tid, node, rqResultKeys, rqResultValues, startIndex, lo, hi, true);\r\n    }\r\n    \r\n    // invoke at the end of each traversal:\r\n    // any nodes that were deleted during the traversal,\r\n    // and were consequently missed during the traversal,\r\n    // are placed in rqResult[index]\r\n    void traversal_end(const int tid, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        // todo: possibly optimize by skipping entire blocks if there are many keys to skip (does not seem to be justifiable for 4 work threads and 4 range query threads)\r\n\r\n        SOFTWARE_BARRIER;\r\n        long long end_timestamp = timestamp;\r\n        SOFTWARE_BARRIER;\r\n        \r\n#if 0\r\n        vector<NodeType *> nodes;\r\n        \r\n        // collect nodes announced by other processes\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            int sz = threadData[otherTid].numAnnouncements;\r\n            SOFTWARE_BARRIER;\r\n            for (int i=0;i<sz;++i) {\r\n                NodeType * node = (NodeType *) threadData[otherTid].announcements[i];\r\n                assert(node);\r\n                nodes.push_back(node);\r\n//                traversal_try_add(tid, node, rqResultKeys, startIndex, lo, hi, false);\r\n            }\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        \r\n        // collect epoch bags of other processes (MUST be after checking announcements!)\r\n        blockbag<NodeType> * all_bags[NUM_PROCESSES*NUMBER_OF_EPOCH_BAGS+1];\r\n        vector<blockbag_iterator<NodeType>> all_iterators;\r\n        int numIterators = 0;\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            blockbag<NodeType> * thread_bags[NUMBER_OF_EPOCH_BAGS+1];\r\n            recmgr->get((NodeType *) NULL)->reclaim->getSafeBlockbags(otherTid, thread_bags);\r\n            for (int i=0;thread_bags[i];++i) {\r\n                all_bags[numIterators] = thread_bags[i];\r\n                all_iterators.push_back(thread_bags[i]->begin());\r\n                ++numIterators;\r\n            }\r\n        }\r\n\r\n        // collect nodes in epoch bags\r\n        int numVisitedInEpochBags = 0;\r\n        for (int ix = 0; ix < numIterators; ++ix) {\r\n            for (; all_iterators[ix] != all_bags[ix]->end(); all_iterators[ix]++) {\r\n                NodeType * node = (*all_iterators[ix]);\r\n                nodes.push_back(node);\r\n                \r\n                ++numVisitedInEpochBags;\r\n                \r\n                long long dtime = node->dtime;\r\n                if (dtime != TIMESTAMP_NOT_SET && dtime > end_timestamp) continue;\r\n                \r\n                if (!(logicalDeletion && canRetireNodesLogicallyDeletedByOtherProcesses)) {\r\n                    // if we cannot retire nodes that are logically deleted\r\n                    // by other processes, then we always retire nodes in\r\n                    // order of increasing dtime values.\r\n                    // so, the blockbag will be ordered, which means that,\r\n                    // if dtime is before the RQ, then all remaining nodes\r\n                    // in this bag were deleted before the RQ.\r\n                    // so, in this case, we skip to the next bag.\r\n                    if (dtime != TIMESTAMP_NOT_SET && dtime < threadData[tid].rq_lin_time) break;\r\n                }\r\n            }\r\n        }\r\n        \r\n        // visit collected nodes\r\n        for (auto it = nodes.begin(); it != nodes.end(); it++) {\r\n            NodeType * node = *it;\r\n            traversal_try_add(tid, node, rqResultKeys, startIndex, lo, hi, false);\r\n        }\r\n#else\r\n        // collect nodes announced by other processes\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            int sz = threadData[otherTid].numAnnouncements;\r\n            SOFTWARE_BARRIER;\r\n            for (int i=0;i<sz;++i) {\r\n                NodeType * node = (NodeType *) threadData[otherTid].announcements[i];\r\n                assert(node);\r\n                traversal_try_add(tid, node, rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n            }\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        \r\n        // collect epoch bags of other processes (MUST be after checking announcements!)\r\n        blockbag<NodeType> * all_bags[NUM_PROCESSES*NUMBER_OF_EPOCH_BAGS+1];\r\n        vector<blockbag_iterator<NodeType>> all_iterators;\r\n        int numIterators = 0;\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            blockbag<NodeType> * thread_bags[NUMBER_OF_EPOCH_BAGS+1];\r\n            recmgr->get((NodeType *) NULL)->reclaim->getSafeBlockbags(otherTid, thread_bags);\r\n            for (int i=0;thread_bags[i];++i) {\r\n                all_bags[numIterators] = thread_bags[i];\r\n                all_iterators.push_back(thread_bags[i]->begin());\r\n                ++numIterators;\r\n            }\r\n        }\r\n        \r\n        int numSkippedInEpochBags = 0;\r\n        int numVisitedInEpochBags = 0;\r\n        for (int ix = 0; ix < numIterators; ++ix) {\r\n            for (; all_iterators[ix] != all_bags[ix]->end(); all_iterators[ix]++) {\r\n                NodeType * node = (*all_iterators[ix]);\r\n                assert(node);\r\n\r\n                ++numVisitedInEpochBags;\r\n                ++numSkippedInEpochBags;\r\n\r\n                long long dtime = node->dtime;\r\n                if (dtime != TIMESTAMP_NOT_SET && dtime > end_timestamp) continue;\r\n                \r\n                --numSkippedInEpochBags;\r\n\r\n                if (!(logicalDeletion && canRetireNodesLogicallyDeletedByOtherProcesses)) {\r\n                    // if we cannot retire nodes that are logically deleted\r\n                    // by other processes, then we always retire nodes in\r\n                    // order of increasing dtime values.\r\n                    // so, the blockbag will be ordered, which means that,\r\n                    // if dtime is before the RQ, then all remaining nodes\r\n                    // in this bag were deleted before the RQ.\r\n                    // so, in this case, we skip to the next bag.\r\n                    if (dtime != TIMESTAMP_NOT_SET && dtime < threadData[tid].rq_lin_time) break;\r\n                }\r\n\r\n                traversal_try_add(tid, node, rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n            }\r\n        }\r\n        \r\n#endif\r\n        \r\n#if defined MICROBENCH && !defined NDEBUG\r\n        if (*startIndex > RQSIZE) {\r\n            cout<<\"ERROR: *startIndex=\"<<(*startIndex)<<\" is unexpectedly greater than or equal to RQSIZE=\"<<RQSIZE<<\" (lo=\"<<lo<<\" hi=\"<<hi<<\")\"<<endl;\r\n            cout<<\"results:\";\r\n            for (int i=0;i<*startIndex;++i) {\r\n                cout<<\" \"<<rqResultKeys[i];\r\n            }\r\n            cout<<endl;\r\n            exit(-1);\r\n        }\r\n#endif\r\n\r\n#ifdef __HANDLE_STATS\r\n\r\n        GSTATS_ADD_IX(tid, skipped_in_bags, numSkippedInEpochBags, threadData[tid].rq_lin_time);\r\n        GSTATS_ADD_IX(tid, visited_in_bags, numVisitedInEpochBags, threadData[tid].rq_lin_time);\r\n#endif\r\n        DEBUG_RECORD_RQ_VISITED(tid, threadData[tid].rq_lin_time, numVisitedInEpochBags);\r\n        DEBUG_RECORD_RQ_SIZE(*startIndex);\r\n        DEBUG_RECORD_RQ_CHECKSUM(tid, threadData[tid].rq_lin_time, rqResultKeys, *startIndex);\r\n    }\r\n};\r\n\r\n#endif\t/* RQ_DCSSP_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_debugging.h",
    "content": "/* \r\n * File:   rq_debugging.h\r\n * Author: trbot\r\n *\r\n * Created on May 15, 2017, 5:23 PM\r\n */\r\n\r\n#ifndef RQ_DEBUGGING_H\r\n#define RQ_DEBUGGING_H\r\n\r\n#ifndef RQ_DEBUGGING_MAX_KEYS_PER_NODE\r\n    #define RQ_DEBUGGING_MAX_KEYS_PER_NODE 32\r\n#endif\r\n\r\n#if !defined USE_RQ_DEBUGGING\r\n\r\n    #define DEBUG_INIT_RQPROVIDER(x)\r\n    #define DEBUG_VALIDATE_RQ(x)\r\n    #define DEBUG_DEINIT_RQPROVIDER(x)\r\n    #define DEBUG_INIT_THREAD(x)\r\n    #define DEBUG_DEINIT_THREAD(x)\r\n    #define DEBUG_RECORD_RQ_VISITED //\r\n    #define DEBUG_RECORD_RQ_SIZE //\r\n    #define DEBUG_RECORD_RQ_CHECKSUM //\r\n\r\n#else\r\n\r\n    #include <cassert>\r\n    #include <string>\r\n    #include <iostream>\r\n    using namespace std;\r\n    \r\n    #define MAX_NUM_RQ_IN_EXECUTION (1<<20)\r\n\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n        #include <sstream>\r\n        string twoDigits(int x) {\r\n            stringstream ss;\r\n            if (x >= 0 && x < 10) {\r\n                ss<<\"0\";\r\n            }\r\n            ss<<x;\r\n            return ss.str();\r\n        }\r\n\r\n        template <typename T>\r\n        void printLogarithmicHistogram(T * valuesOverTime, int numValues) {\r\n            constexpr int numBits = sizeof(T)*8;\r\n            int histogram[numBits+1];\r\n            memset(histogram, 0, sizeof(histogram));\r\n            T sum = 0;\r\n            int cntNonZero = 0;\r\n            for (int i=0;i<numValues;++i) {\r\n                T v = valuesOverTime[i];\r\n                if (v == 0) continue;\r\n                sum += v;\r\n                ++cntNonZero;\r\n                int pow2 = 0;\r\n                while (v > 1) {\r\n                    v >>= 1;\r\n                    ++pow2;\r\n                }\r\n                assert(pow2 <= numBits);\r\n                ++histogram[pow2];\r\n            }\r\n            for (int i=0;i<=numBits;++i) {\r\n                if (histogram[i] > 0) {\r\n                    cout<<\"    (2^\"<<twoDigits(i)<<\", 2^\"<<twoDigits(i+1)<<\"]: \"<<histogram[i]<<endl;\r\n                }\r\n            }\r\n            cout<<\"    average = \"<<(sum / (double) cntNonZero)<<endl;\r\n        }\r\n\r\n        int ** threadNumNodesVisitedInBags; //[MAX_TID_POW2][MAX_NUM_RQ_IN_EXECUTION];\r\n    #endif\r\n\r\n    #ifdef RQ_VALIDATION\r\n        #include <cstring>\r\n        #include \"errors.h\"\r\n        #define NO_RQ_CHECKSUM (0)\r\n        long long ** threadUpdateChecksum; //[MAX_TID_POW2][MAX_NUM_RQ_IN_EXECUTION];\r\n        long long ** threadRQChecksum; //[MAX_TID_POW2][MAX_NUM_RQ_IN_EXECUTION];\r\n    #endif\r\n\r\n    #ifdef RQ_HISTOGRAM\r\n        #include <fstream>\r\n        #define CSV_OUTPUT_FILE \"data.csv\"\r\n        std::ofstream ofs;\r\n\r\n        #define MAX_RQ_SIZE (1<<16)\r\n        __thread int numRQs[MAX_RQ_SIZE+1];\r\n        int totalNumRQs[MAX_RQ_SIZE+1];\r\n    #endif\r\n\r\n        inline void DEBUG_RECORD_RQ_VISITED(const int tid, const long long ts, const int numVisited) {\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n            if (ts >= MAX_NUM_RQ_IN_EXECUTION) return;\r\n            threadNumNodesVisitedInBags[tid][ts] = numVisited;\r\n    #endif\r\n        }\r\n\r\n        inline void DEBUG_RECORD_RQ_SIZE(const int size) {\r\n    #ifdef RQ_HISTOGRAM\r\n            ++numRQs[size];\r\n    #endif\r\n        }\r\n\r\n        template <typename K, typename V, typename Node, class DataStructure>\r\n        inline void DEBUG_RECORD_UPDATE_CHECKSUM(const int tid, const long long timestamp, Node * const * const insertedNodes, Node * const * const deletedNodes, DataStructure * const ds) {\r\n    #ifdef RQ_VALIDATION\r\n            if (timestamp >= MAX_NUM_RQ_IN_EXECUTION) {\r\n                return;\r\n    //            cout << \"timestamp is: \" << timestamp << endl;\r\n    //            error(\"timestamp > MAX_NUM_RQ_IN_EXECUTION\");\r\n            }\r\n            for (int i=0;insertedNodes[i];++i) {\r\n                K outputKeys[RQ_DEBUGGING_MAX_KEYS_PER_NODE];\r\n                V outputValues[RQ_DEBUGGING_MAX_KEYS_PER_NODE];\r\n                int cnt = ds->getKeys(tid, insertedNodes[i], outputKeys, outputValues);\r\n                assert(cnt <= RQ_DEBUGGING_MAX_KEYS_PER_NODE);\r\n                for (int j=0;j<cnt;++j) {\r\n                    threadUpdateChecksum[tid][timestamp] += outputKeys[j];\r\n                }\r\n            }\r\n            for (int i=0;deletedNodes[i];++i) {\r\n                K outputKeys[RQ_DEBUGGING_MAX_KEYS_PER_NODE];\r\n                V outputValues[RQ_DEBUGGING_MAX_KEYS_PER_NODE];\r\n                int cnt = ds->getKeys(tid, deletedNodes[i], outputKeys, outputValues);\r\n                assert(cnt <= RQ_DEBUGGING_MAX_KEYS_PER_NODE);\r\n                for (int j=0;j<cnt;++j) {\r\n                    threadUpdateChecksum[tid][timestamp] -= outputKeys[j];\r\n                }\r\n            }\r\n    #endif\r\n        }\r\n\r\n        template <typename K>\r\n        inline void DEBUG_RECORD_RQ_CHECKSUM(const int tid, const long long timestamp, K const * const rqResult, const int len) {\r\n    #ifdef RQ_VALIDATION\r\n            if (timestamp >= MAX_NUM_RQ_IN_EXECUTION) return;\r\n            //if (timestamp >= MAX_NUM_RQ_IN_EXECUTION) error(\"timestamp > MAX_NUM_RQ_IN_EXECUTION\");\r\n            // compute checksum\r\n            long long checksum = 0;\r\n            for (int i=0;i<len;++i) {\r\n                checksum += (long long) rqResult[i];\r\n            }\r\n            threadRQChecksum[tid][timestamp] = checksum;\r\n    #endif\r\n        }\r\n\r\n        void DEBUG_INIT_RQPROVIDER(const int numProcesses) {\r\n    #ifdef RQ_HISTOGRAM\r\n            ofs.open(CSV_OUTPUT_FILE, std::ofstream::out);\r\n            for (int size=0;size<=MAX_RQ_SIZE;++size) {\r\n                totalNumRQs[size] = 0;\r\n            }\r\n    #endif\r\n    #ifdef RQ_VALIDATION\r\n            threadUpdateChecksum = new long long * [numProcesses];\r\n            threadRQChecksum = new long long * [numProcesses];\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n            threadNumNodesVisitedInBags = new int * [numProcesses];\r\n    #endif\r\n            for (int tid=0;tid<numProcesses;++tid) {\r\n                threadUpdateChecksum[tid] = new long long[MAX_NUM_RQ_IN_EXECUTION];\r\n                threadRQChecksum[tid] = new long long[MAX_NUM_RQ_IN_EXECUTION];\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n                threadNumNodesVisitedInBags[tid] = new int[MAX_NUM_RQ_IN_EXECUTION];\r\n    #endif\r\n                memset(threadUpdateChecksum[tid], 0, MAX_NUM_RQ_IN_EXECUTION*sizeof(threadUpdateChecksum[tid][0]));\r\n                memset(threadRQChecksum[tid], 0, MAX_NUM_RQ_IN_EXECUTION*sizeof(threadRQChecksum[tid][0]));\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n                memset(threadNumNodesVisitedInBags[tid], 0, MAX_NUM_RQ_IN_EXECUTION*sizeof(threadNumNodesVisitedInBags[tid][0]));\r\n    #endif\r\n            }\r\n    #endif\r\n        }\r\n\r\n        void DEBUG_VALIDATE_RQ(const int numProcesses) {\r\n    #ifdef RQ_VALIDATION\r\n            long long * updateChecksum = new long long[MAX_NUM_RQ_IN_EXECUTION];\r\n            long long * rqChecksum = new long long[MAX_NUM_RQ_IN_EXECUTION];\r\n            int * numNodesVisitedInBags = new int[MAX_NUM_RQ_IN_EXECUTION];\r\n            memset(updateChecksum, 0, MAX_NUM_RQ_IN_EXECUTION*sizeof(updateChecksum[0]));\r\n            memset(rqChecksum, 0, MAX_NUM_RQ_IN_EXECUTION*sizeof(rqChecksum[0]));\r\n            memset(numNodesVisitedInBags, 0, MAX_NUM_RQ_IN_EXECUTION*sizeof(numNodesVisitedInBags[0]));\r\n\r\n            for (int tid=0;tid<numProcesses;++tid) {\r\n                for (int timestamp=0;timestamp<MAX_NUM_RQ_IN_EXECUTION;++timestamp) {\r\n                    //if (threadUpdateChecksum[tid][timestamp]) cout<<\"threadUpdateChecksum[tid=\"<<tid<<\", timestamp=\"<<timestamp<<\"]=\"<<threadUpdateChecksum[tid][timestamp]<<endl;\r\n                    rqChecksum[timestamp] += threadRQChecksum[tid][timestamp];\r\n                    updateChecksum[timestamp] += threadUpdateChecksum[tid][timestamp];\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n                    numNodesVisitedInBags[timestamp] += threadNumNodesVisitedInBags[tid][timestamp];\r\n    #endif\r\n                }\r\n            } // note: since each rq gets a unique timestamp, rqChecksum only contains one RQ per timestamp, even after summing over all threads\r\n\r\n            bool good = true;\r\n            int numberFailed = 0;\r\n            int numberSucc = 0;\r\n    #ifndef RLU_USED\r\n            long long prefixSum = 0; \r\n            for (int timestamp=0;timestamp<MAX_NUM_RQ_IN_EXECUTION;++timestamp) {\r\n                if (rqChecksum[timestamp] != NO_RQ_CHECKSUM) {\r\n                    if (rqChecksum[timestamp] != prefixSum) {\r\n                        ++numberFailed;\r\n                        if (numberFailed < 100) {\r\n                            cout<<\"RQ VALIDATION ERROR: rqChecksum[timestamp=\"<<timestamp<<\"]=\"<<rqChecksum[timestamp]<<\" is not equal to prefixSum=updateChecksum[0, 1, ..., timestamp-1]=\"<<prefixSum<<endl;\r\n                        } else if (numberFailed == 100) {\r\n                            cout<<\"RQ VALIDATION: too many errors to list...\"<<endl;\r\n                        }\r\n                        good = false;\r\n                        //exit(-1);\r\n                    } else {\r\n                        ++numberSucc;\r\n                    }\r\n                }\r\n                prefixSum += updateChecksum[timestamp];\r\n            }\r\n    #else       \r\n            for (int tid=0;tid<numProcesses;++tid) {\r\n                long long prefixSum = 0;\r\n                for (int timestamp=0;timestamp<MAX_NUM_RQ_IN_EXECUTION;++timestamp) {\r\n                    if (threadRQChecksum[tid][timestamp] != NO_RQ_CHECKSUM) {\r\n                        if (threadRQChecksum[tid][timestamp] != prefixSum) {\r\n                            ++numberFailed;\r\n                            if (numberFailed < 100) {\r\n                                cout<<\"RQ VALIDATION ERROR: threadRQChecksum[tid=\"<< tid <<\"][timestamp=\"<<timestamp<<\"]=\"<<threadRQChecksum[tid][timestamp]<<\" is not equal to prefixSum=updateChecksum[0, 1, ..., timestamp-1]=\"<<prefixSum<<endl;\r\n                            } else if (numberFailed == 100) {\r\n                                cout<<\"RQ VALIDATION: too many errors to list...\"<<endl;\r\n                            }\r\n                            good = false;\r\n                            //exit(-1);\r\n                        } else {\r\n                            ++numberSucc;\r\n                        }\r\n                    }\r\n                    prefixSum += updateChecksum[timestamp];\r\n                }\r\n            }\r\n    #endif\r\n            if (numberFailed > 0) {\r\n                cout<<\"RQ VALIDATION TOTAL FAILURES: \"<<numberFailed<<endl;\r\n                cout<<\"    (note: validation only works for RQs over the entire data structure)\"<<endl;\r\n            }\r\n            cout<<\"RQ VALIDATION TOTAL SUCCESSES: \"<<numberSucc<<endl;\r\n            cout<<\"    (note: this captures only non-empty RQs, and is at most \"<<MAX_NUM_RQ_IN_EXECUTION<<\")\"<<endl;\r\n            if (good) cout<<\"RQ Validation OK\"<<endl;\r\n            cout<<endl;\r\n\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n            cout<<\"histogram: how many RQs visited x nodes in limbo bags?\"<<endl;\r\n            printLogarithmicHistogram(numNodesVisitedInBags, MAX_NUM_RQ_IN_EXECUTION);\r\n            cout<<endl;\r\n    #endif\r\n\r\n            delete[] updateChecksum;\r\n            delete[] rqChecksum;\r\n            delete[] numNodesVisitedInBags;\r\n    #endif\r\n        }\r\n\r\n        void DEBUG_DEINIT_RQPROVIDER(const int numProcesses) {\r\n    #ifdef RQ_HISTOGRAM\r\n            ofs<<\"x,y\"<<endl;\r\n            for (int size=0;size<=MAX_RQ_SIZE;++size) {\r\n                if (totalNumRQs[size]) {\r\n                    ofs<<size<<\",\"<<totalNumRQs[size]<<endl;\r\n                }\r\n            }\r\n            ofs.close();\r\n            long long __sum = 0;\r\n            for (int size=0;size<=MAX_RQ_SIZE;++size) {\r\n                __sum += totalNumRQs[size];\r\n            }\r\n    #endif\r\n    #ifdef RQ_VALIDATION\r\n            DEBUG_VALIDATE_RQ(numProcesses);\r\n            for (int tid=0;tid<numProcesses;++tid) {\r\n                delete[] threadUpdateChecksum[tid];\r\n                delete[] threadRQChecksum[tid];\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n                delete[] threadNumNodesVisitedInBags[tid];\r\n    #endif\r\n            }\r\n            delete[] threadUpdateChecksum;\r\n            delete[] threadRQChecksum;\r\n    #ifdef RQ_VISITED_IN_BAGS_HISTOGRAM\r\n            delete[] threadNumNodesVisitedInBags;\r\n    #endif\r\n    #endif\r\n        }\r\n\r\n        void DEBUG_INIT_THREAD(const int tid) {\r\n    #ifdef RQ_HISTOGRAM\r\n            for (int size=0;size<=MAX_RQ_SIZE;++size) {\r\n                numRQs[size] = 0;\r\n            }\r\n    #endif\r\n        }\r\n\r\n        void DEBUG_DEINIT_THREAD(const int tid) {\r\n    #ifdef RQ_HISTOGRAM\r\n            for (int size=0;size<=MAX_RQ_SIZE;++size) {\r\n                __sync_fetch_and_add(&totalNumRQs[size], numRQs[size]);\r\n            }\r\n    #endif\r\n        }\r\n\r\n#endif // else case for \"if !defined USE_RQ_DEBUGGING\"\r\n    \r\n#endif /* RQ_DEBUGGING_H */"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_htm_rwlock.h",
    "content": "/* \r\n * File:   rq_rwlock.h\r\n * Author: trbot\r\n *\r\n * Created on April 20, 2017, 1:03 PM\r\n */\r\n\r\n#ifndef RQ_RWLOCK_H\r\n#define\tRQ_RWLOCK_H\r\n\r\n#define MAX_NODES_DELETED_ATOMICALLY 8\r\n#define MAX_KEYS_PER_NODE 32\r\n\r\n#include \"rq_debugging.h\"\r\n#include <hashlist.h>\r\n#include <rwlock.h>\r\n#include <rtm.h>\r\n#include <pthread.h>\r\n#include <cassert>\r\n\r\n#define MAX_HTM_ATTEMPTS 30\r\n\r\n#define dosum(src) ({ \\\r\n    long long __sum = 0; \\\r\n    for (int __i=0;__i<NUM_PROCESSES;++__i) { \\\r\n        __sum += threadData[__i].src; \\\r\n    } \\\r\n    __sum; \\\r\n})\r\n\r\ntemplate <typename K, typename V, typename NodeType, typename DataStructure, typename RecordManager, bool logicalDeletion, bool canRetireNodesLogicallyDeletedByOtherProcesses>\r\nclass RQProvider {\r\nprivate:\r\n    struct __rq_thread_data {\r\n        #define __RQ_THREAD_DATA_SIZE 1024\r\n        union {\r\n            struct { // anonymous struct inside anonymous union means we don't need to type anything special to access these variables\r\n                long long rq_lin_time;\r\n                HashList<K> * hashlist;\r\n                volatile char padding0[PREFETCH_SIZE_BYTES];\r\n                void * announcements[MAX_NODES_DELETED_ATOMICALLY+1];\r\n                int numAnnouncements;\r\n                volatile char padding1[PREFETCH_SIZE_BYTES]; // prevent false sharing between htm debugging stats below and announcements\r\n                \r\n                // htm debugging stuff\r\n                int commitWriter;\r\n                int abortWriter;\r\n                int commitReader;\r\n                int abortReader;\r\n                int fallback;\r\n            };\r\n            char bytes[__RQ_THREAD_DATA_SIZE]; // avoid false sharing\r\n        };\r\n    } __attribute__((aligned(__RQ_THREAD_DATA_SIZE)));\r\n\r\n    #define TIMESTAMP_NOT_SET 0\r\n    #define HASHLIST_INIT_CAPACITY_POW2 (1<<8)\r\n\r\n    const int NUM_PROCESSES;\r\n    volatile char padding0[PREFETCH_SIZE_BYTES];\r\n    volatile long long timestamp = 1;\r\n    volatile char padding1[PREFETCH_SIZE_BYTES];\r\n    RWLock rwlock;\r\n    volatile char padding2[PREFETCH_SIZE_BYTES];\r\n    __rq_thread_data * threadData;\r\n    \r\n    DataStructure * ds;\r\n    RecordManager * const recmgr;\r\n\r\n    int init[MAX_TID_POW2] = {0,};\r\n\r\npublic:\r\n    RQProvider(const int numProcesses, DataStructure * ds, RecordManager * recmgr) : NUM_PROCESSES(numProcesses), ds(ds), recmgr(recmgr) {\r\n        threadData = new __rq_thread_data[numProcesses];\r\n        DEBUG_INIT_RQPROVIDER(numProcesses);\r\n    }\r\n\r\n    ~RQProvider() {\r\n        cout<<\"writer commits : \"<<dosum(commitWriter)<<endl;\r\n        cout<<\"writer aborts  : \"<<dosum(abortWriter)<<endl;\r\n        cout<<\"reader commits : \"<<dosum(commitReader)<<endl;\r\n        cout<<\"reader aborts  : \"<<dosum(abortReader)<<endl;\r\n        cout<<\"fallback       : \"<<dosum(fallback)<<endl;\r\n\r\n//        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n//            threadData[tid].hashlist->destroy();\r\n//            delete threadData[tid].hashlist;\r\n//        }\r\n        delete[] threadData;\r\n        DEBUG_DEINIT_RQPROVIDER(NUM_PROCESSES);\r\n    }\r\n\r\n    // invoke before a given thread can perform any rq_functions\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        threadData[tid].hashlist = new HashList<K>();\r\n        threadData[tid].hashlist->init(HASHLIST_INIT_CAPACITY_POW2);\r\n        threadData[tid].numAnnouncements = 0;\r\n        for (int i=0;i<MAX_NODES_DELETED_ATOMICALLY+1;++i) {\r\n            threadData[tid].announcements[i] = NULL;\r\n        }\r\n        threadData[tid].commitWriter = 0;\r\n        threadData[tid].abortWriter = 0;\r\n        threadData[tid].commitReader = 0;\r\n        threadData[tid].abortReader = 0;\r\n        threadData[tid].fallback = 0;\r\n        DEBUG_INIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke once a given thread will no longer perform any rq_ functions\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        threadData[tid].hashlist->destroy();\r\n        delete threadData[tid].hashlist;\r\n        DEBUG_DEINIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke whenever a new node is created/initialized\r\n    inline void init_node(const int tid, NodeType * const node) {\r\n        node->itime = TIMESTAMP_NOT_SET;\r\n        node->dtime = TIMESTAMP_NOT_SET;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any initialization of addr\r\n    // with invocations of rq_write_addr\r\n    template <typename T>\r\n    inline void write_addr(const int tid, T volatile * const addr, const T val) {\r\n        *addr = val;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any reads of addr with\r\n    // invocations of rq_read_addr\r\n    template <typename T>\r\n    inline T read_addr(const int tid, T volatile * const addr) {\r\n        return *addr;\r\n    }\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run some time BEFORE the physical deletion of a node\r\n    // whose key has ALREADY been logically deleted.\r\n    void announce_physical_deletion(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            threadData[tid].announcements[threadData[tid].numAnnouncements+i] = deletedNodes[i];\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        threadData[tid].numAnnouncements += i;\r\n        assert(threadData[tid].numAnnouncements <= MAX_NODES_DELETED_ATOMICALLY);\r\n        SOFTWARE_BARRIER;\r\n    }\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node failed.\r\n    void physical_deletion_failed(const int tid, NodeType * const * const deletedNodes) {\r\n        for (int i=0;deletedNodes[i];++i) {\r\n            --threadData[tid].numAnnouncements;\r\n        }\r\n        assert(threadData[tid].numAnnouncements >= 0);\r\n    }\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node succeeded.\r\n    void physical_deletion_succeeded(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            recmgr->retire(tid, deletedNodes[i]);\r\n        }\r\n        SOFTWARE_BARRIER; // ensure nodes are placed in the epoch bag BEFORE they are removed from announcements.\r\n        threadData[tid].numAnnouncements -= i;\r\n        assert(threadData[tid].numAnnouncements >= 0);\r\n    }\r\n    \r\nprivate:\r\n    \r\n    inline void set_insertion_timestamps(\r\n            const int tid,\r\n            const long long ts,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        // set insertion timestamps\r\n        // for each i_node in insertedNodes\r\n        for (int i_nodeix=0;insertedNodes[i_nodeix];++i_nodeix) {\r\n            insertedNodes[i_nodeix]->itime = ts;\r\n        }\r\n    }\r\n\r\n    inline void set_deletion_timestamps(\r\n            const int tid,\r\n            const long long ts,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        // set deletion timestamps\r\n        // for each d_node in deletedNodes\r\n        for (int d_nodeix=0;deletedNodes[d_nodeix];++d_nodeix) {\r\n            deletedNodes[d_nodeix]->dtime = ts;\r\n        }\r\n    }\r\n    \r\npublic:\r\n\r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a WRITE\r\n    template <typename T>\r\n    inline T linearize_update_at_write(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n\r\n        // htm path\r\n        long long ts;\r\n        int limit = MAX_HTM_ATTEMPTS;\r\n        while (limit--) {\r\n            while (rwlock.isWriteLocked()) {}\r\n            if (XBEGIN() == _XBEGIN_STARTED) {\r\n                if (rwlock.isWriteLocked()) XABORT(1);\r\n                ts = timestamp;\r\n                *lin_addr = lin_newval; // original linearization point\r\n                XEND();\r\n                ++threadData[tid].commitReader;\r\n                goto committed;\r\n            } else ++threadData[tid].abortReader;\r\n\r\n        }\r\n        \r\n        // fallback path\r\n        ++threadData[tid].fallback;\r\n        rwlock.readLock();\r\n        ts = timestamp;\r\n        *lin_addr = lin_newval; // original linearization point\r\n        rwlock.readUnlock();\r\n\r\ncommitted:\r\n        set_insertion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n        set_deletion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n        \r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            physical_deletion_succeeded(tid, deletedNodes);\r\n        }\r\n        \r\n#if defined USE_RQ_DEBUGGING\r\n        DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        return lin_newval;\r\n    }\r\n    \r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a CAS\r\n    template <typename T>\r\n    inline T linearize_update_at_cas(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_oldval,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n        // htm path\r\n        long long ts;\r\n        T res;\r\n        int limit = MAX_HTM_ATTEMPTS;\r\n        while (limit--) {\r\n            while (rwlock.isWriteLocked()) {}\r\n            if (XBEGIN() == _XBEGIN_STARTED) {\r\n                if (rwlock.isWriteLocked()) XABORT(1);\r\n                ts = timestamp;\r\n                res = __sync_val_compare_and_swap(lin_addr, lin_oldval, lin_newval); // original linearization point\r\n//                res = *lin_addr; // manually implement CAS\r\n//                if (res == lin_oldval) *lin_addr = lin_newval;\r\n                XEND();\r\n                ++threadData[tid].commitReader;\r\n                goto committed;\r\n            } else ++threadData[tid].abortReader;\r\n        }\r\n        \r\n        // fallback path\r\n        ++threadData[tid].fallback;\r\n        rwlock.readLock();\r\n        ts = timestamp;\r\n        res = __sync_val_compare_and_swap(lin_addr, lin_oldval, lin_newval);\r\n        rwlock.readUnlock();\r\n        \r\ncommitted:\r\n        if (res == lin_oldval){\r\n            set_insertion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n            set_deletion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n            \r\n            if (!logicalDeletion) {\r\n                // physical deletion will happen at the same time as logical deletion\r\n                physical_deletion_succeeded(tid, deletedNodes);\r\n            }\r\n            \r\n#if defined USE_RQ_DEBUGGING\r\n            DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        } else {\r\n            if (!logicalDeletion) {\r\n                // physical deletion will happen at the same time as logical deletion\r\n                physical_deletion_failed(tid, deletedNodes);\r\n            }            \r\n        }\r\n        return res;\r\n    }\r\n\r\n    // invoke at the start of each traversal\r\n    inline void traversal_start(const int tid) {\r\n        threadData[tid].hashlist->clear();\r\n\r\n//        // htm path\r\n//        int limit = MAX_HTM_ATTEMPTS;\r\n//        while (limit--) {\r\n//            while (rwlock.isLocked()) {}\r\n//            if (XBEGIN() == _XBEGIN_STARTED) {\r\n//                if (rwlock.isLocked()) XABORT(1);\r\n//                threadData[tid].rq_lin_time = ++timestamp; // linearization point of range query (at the write to timestamp)\r\n//                XEND();\r\n//                ++threadData[tid].commitWriter;\r\n//                goto committed;\r\n//            } else ++threadData[tid].abortWriter;\r\n//        }\r\n//committed:\r\n        \r\n        // fallback path\r\n        rwlock.writeLock();\r\n        threadData[tid].rq_lin_time = ++timestamp; // linearization point of range query (at the write to timestamp)\r\n        rwlock.writeUnlock();\r\n    }\r\n\r\nprivate:\r\n    // invoke each time a traversal visits a node with a key in the desired range:\r\n    // if the node belongs in the range query, it will be placed in rqResult[index]\r\n    inline int __traversal_try_add(const int tid, NodeType * const node, NodeType ** const nodeSource, K * const outputKeys, V * const outputValues, const K& lo, const K& hi, bool foundDuringTraversal) {\r\n\r\n        // rqResultKeys should have space for MAX_KEYS_PER_NODE keys, AT LEAST\r\n        \r\n        // in the following, rather than having deeply nested if-else blocks,\r\n        // we return asap, and list facts that must be true if we didn't return\r\n        assert(foundDuringTraversal || !logicalDeletion || ds->isLogicallyDeleted(tid, node));\r\n        \r\n        long long itime = TIMESTAMP_NOT_SET;\r\n        while (itime == TIMESTAMP_NOT_SET) { itime = node->itime; }\r\n        if (node->itime >= threadData[tid].rq_lin_time) return 0;               // node was inserted after the range query\r\n        // fact: node was inserted before the range query\r\n        \r\n        bool logicallyDeleted = (logicalDeletion && ds->isLogicallyDeleted(tid, node));\r\n        long long dtime = TIMESTAMP_NOT_SET;\r\n\r\n        if (!logicalDeletion && foundDuringTraversal) goto tryAddToRQ;          // no logical deletion. since node was inserted before the range query, and the traversal encountered it, it must have been deleted AFTER the traversal encountered it.\r\n        // fact: no logical deletion ==> did not find node during traversal\r\n\r\n        dtime = node->dtime;\r\n        if (dtime != TIMESTAMP_NOT_SET) {\r\n            if (dtime < threadData[tid].rq_lin_time) return 0;                  // node was deleted before the range query\r\n            goto tryAddToRQ;\r\n        }\r\n\r\n        // fact: dtime was not set above\r\n        if (logicalDeletion && !logicallyDeleted) goto tryAddToRQ;              // if logical deletion is used with marking, the fact that node was inserted before the range query, and that the traversal encountered node, is NOT enough to argue that node was in the data structure when the traversal started. why? when the traversal encountered node, it might have already been marked. so, we check if node is marked. if not, then the node has not yet been deleted.\r\n        // fact: if there is logical deletion, then the node has now been deleted\r\n\r\n        ///////////////////////// HANDLE UNKNOWN DTIME /////////////////////////\r\n        // if we are executing this because node was ANNOUNCED by a process,\r\n        // as something that MIGHT soon be deleted (if nodeSource != NULL),\r\n        // then node might not ever actually be deleted,\r\n        // so we can't spin forever on dtime.\r\n        if (nodeSource != NULL) {\r\n            while (dtime == TIMESTAMP_NOT_SET && *nodeSource == node) { dtime = node->dtime; }\r\n            if (dtime == TIMESTAMP_NOT_SET) {\r\n                // above loop exited because the process removed its announcement to this node!\r\n                // if the process deleted the node, then it removed the\r\n                // announcement AFTER setting dtime.\r\n                // so we reread dtime one more time, to figure out whether\r\n                // the process actually deleted the node.\r\n                SOFTWARE_BARRIER; // prevent read of dtime from happening before last read of *nodeSource\r\n                dtime = node->dtime;\r\n                if (dtime == TIMESTAMP_NOT_SET) {\r\n                    // since dtime is not set, the process did NOT delete the node.\r\n                    // so, either a DIFFERENT process deleted it,\r\n                    // or it was found during the data structure traversal.\r\n                    // if another process deleted it, then we will find it\r\n                    // either in that process' announcements, or in a limbo bag.\r\n                    return 0;\r\n                }\r\n                // the node has been deleted, and dtime is set, so we check dtime below.\r\n            }\r\n        } else {\r\n            while (dtime == TIMESTAMP_NOT_SET) { dtime = node->dtime; }\r\n        }\r\n        if (dtime < threadData[tid].rq_lin_time) return 0;                      // node was deleted before the range query\r\n        // fact: node was inserted before the rq and deleted after it\r\n        \r\n        ///////////////////// TRY TO ADD NODE'S KEYS TO RQ /////////////////////\r\n        // note: this way of organizing this decision tree favors trees with fat multi-key nodes, because getKeys is delayed as long as possible.\r\n        \r\ntryAddToRQ:\r\n        // fetch the node's keys that are in the set\r\n        int cnt = ds->getKeys(tid, node, outputKeys, outputValues);\r\n        assert(cnt < RQ_DEBUGGING_MAX_KEYS_PER_NODE);\r\n        if (cnt == 0) return 0;                                                 // node doesn't contain any keys that are in the set\r\n        // TODO: properly assert that getKeys doesn't run out of bounds on outputKeys[...] (i'm quite certain it doesn't, currently, though.)\r\n        \r\n        // note: in the following loop, we shift keys in the outputKeys array left to eliminate any that ultimately should not be added to the range query\r\n        int numNewKeys = 0;\r\n        for (int i=0;i<cnt;++i) {                                               // decide whether key = outputKeys[i] should be in the range query\r\n            if (!ds->isInRange(outputKeys[i], lo, hi)) goto doNotAddToRQ;       // key is NOT in the desired range\r\n            if (threadData[tid].hashlist->contains(outputKeys[i])) goto doNotAddToRQ; // key is already in the range query\r\n            outputKeys[numNewKeys] = outputKeys[i];                             // save this as a new key added to the RQ\r\n            outputValues[numNewKeys] = outputValues[i];\r\n            ++numNewKeys;\r\n\r\ndoNotAddToRQ: (0);\r\n        }\r\n        return numNewKeys;\r\n    }\r\n    \r\n    inline void traversal_try_add(const int tid, NodeType * const node, NodeType ** const nodeSource, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi, bool foundDuringTraversal) {\r\n//#if defined MICROBENCH && !defined NDEBUG\r\n//        assert(*startIndex < 2*RQSIZE); // note: this assert is a hack. it should be *startIndex < size of rqResultKeys\r\n//        if (*startIndex >= RQSIZE) {\r\n//            cout<<\"ERROR: *startIndex=\"<<(*startIndex)<<\" is unexpectedly greater than or equal to RQSIZE=\"<<RQSIZE<<\" (lo=\"<<lo<<\" hi=\"<<hi<<\")\"<<endl;\r\n//            cout<<\"results:\";\r\n//            for (int i=0;i<*startIndex;++i) {\r\n//                cout<<\" \"<<rqResultKeys[i];\r\n//            }\r\n//            cout<<endl;\r\n//            exit(-1);\r\n//        }\r\n//#endif\r\n        int numNewKeys = __traversal_try_add(tid, node, nodeSource, rqResultKeys+(*startIndex), rqResultValues+(*startIndex), lo, hi, foundDuringTraversal);\r\n//#if defined MICROBENCH\r\n//        assert(*startIndex + numNewKeys < 2*RQSIZE); // note: this assert is a hack. it should be *startIndex + numNewKeys < size of rqResultKeys array\r\n//#endif\r\n        for (int i=0;i<numNewKeys;++i) {\r\n            threadData[tid].hashlist->insert(rqResultKeys[(*startIndex)++]);\r\n        }\r\n        // note: the above increments startIndex\r\n#if defined MICROBENCH\r\n        assert(*startIndex <= RQSIZE);\r\n#endif\r\n    }\r\n    \r\npublic:\r\n    inline void traversal_try_add(const int tid, NodeType * const node, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        traversal_try_add(tid, node, NULL, rqResultKeys, rqResultValues, startIndex, lo, hi, true);\r\n    }\r\n    \r\n    // invoke at the end of each traversal:\r\n    // any nodes that were deleted during the traversal,\r\n    // and were consequently missed during the traversal,\r\n    // are placed in rqResult[index]\r\n    void traversal_end(const int tid, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        // todo: possibly optimize by skipping entire blocks if there are many keys to skip (does not seem to be justifiable for 4 work threads and 4 range query threads)\r\n\r\n        SOFTWARE_BARRIER;\r\n        long long end_timestamp = timestamp;\r\n        SOFTWARE_BARRIER;\r\n        \r\n        // collect nodes announced by other processes\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            int sz = threadData[otherTid].numAnnouncements;\r\n            SOFTWARE_BARRIER;\r\n            for (int i=0;i<sz;++i) {\r\n                NodeType * node = (NodeType *) threadData[otherTid].announcements[i];\r\n                assert(node);\r\n                traversal_try_add(tid, node, (NodeType **) &threadData[otherTid].announcements[i], rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n            }\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        \r\n        // collect epoch bags of other processes (MUST be after checking announcements!)\r\n        blockbag<NodeType> * all_bags[NUM_PROCESSES*NUMBER_OF_EPOCH_BAGS+1];\r\n        vector<blockbag_iterator<NodeType>> all_iterators;\r\n        int numIterators = 0;\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            blockbag<NodeType> * thread_bags[NUMBER_OF_EPOCH_BAGS+1];\r\n            recmgr->get((NodeType *) NULL)->reclaim->getSafeBlockbags(otherTid, thread_bags);\r\n            for (int i=0;thread_bags[i];++i) {\r\n                all_bags[numIterators] = thread_bags[i];\r\n                all_iterators.push_back(thread_bags[i]->begin());\r\n                ++numIterators;\r\n            }\r\n        }\r\n        \r\n        int numSkippedInEpochBags = 0;\r\n        int numVisitedInEpochBags = 0;\r\n        for (int ix = 0; ix < numIterators; ++ix) {\r\n            for (; all_iterators[ix] != all_bags[ix]->end(); all_iterators[ix]++) {\r\n                NodeType * node = (*all_iterators[ix]);\r\n                assert(node);\r\n\r\n                ++numVisitedInEpochBags;\r\n                ++numSkippedInEpochBags;\r\n\r\n                long long dtime = node->dtime;\r\n                if (dtime != TIMESTAMP_NOT_SET && dtime > end_timestamp) continue;\r\n\r\n                --numSkippedInEpochBags;\r\n                \r\n                if (!(logicalDeletion && canRetireNodesLogicallyDeletedByOtherProcesses)) {\r\n                    // if we cannot retire nodes that are logically deleted\r\n                    // by other processes, then we always retire nodes in\r\n                    // order of increasing dtime values.\r\n                    // so, the blockbag will be ordered, which means that,\r\n                    // if dtime is before the RQ, then all remaining nodes\r\n                    // in this bag were deleted before the RQ.\r\n                    // so, in this case, we skip to the next bag.\r\n                    if (dtime != TIMESTAMP_NOT_SET && dtime < threadData[tid].rq_lin_time) break;\r\n                }\r\n\r\n                traversal_try_add(tid, node, NULL, rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n            }\r\n        }\r\n\r\n#if defined MICROBENCH && !defined NDEBUG\r\n        if (*startIndex > RQSIZE) {\r\n            cout<<\"ERROR: *startIndex=\"<<(*startIndex)<<\" is unexpectedly greater than or equal to RQSIZE=\"<<RQSIZE<<\" (lo=\"<<lo<<\" hi=\"<<hi<<\")\"<<endl;\r\n            cout<<\"results:\";\r\n            for (int i=0;i<*startIndex;++i) {\r\n                cout<<\" \"<<rqResultKeys[i];\r\n            }\r\n            cout<<endl;\r\n            exit(-1);\r\n        }\r\n#endif\r\n        \r\n#ifdef __HANDLE_STATS\r\n\r\n        GSTATS_ADD_IX(tid, skipped_in_bags, numSkippedInEpochBags, threadData[tid].rq_lin_time);\r\n        GSTATS_ADD_IX(tid, visited_in_bags, numVisitedInEpochBags, threadData[tid].rq_lin_time);\r\n#endif\r\n        DEBUG_RECORD_RQ_VISITED(tid, threadData[tid].rq_lin_time, numVisitedInEpochBags);\r\n        DEBUG_RECORD_RQ_SIZE(*startIndex);\r\n        DEBUG_RECORD_RQ_CHECKSUM(tid, threadData[tid].rq_lin_time, rqResultKeys, *startIndex);\r\n    }\r\n};\r\n\r\n#endif\t/* RQ_RWLOCK_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_provider.h",
    "content": "/* \r\n * File:   rq_provider.h\r\n * Author: trbot\r\n *\r\n * Created on May 16, 2017, 5:14 PM\r\n */\r\n\r\n#ifndef RQ_PROVIDER_H\r\n#define RQ_PROVIDER_H\r\n\r\n#if defined RQ_LOCKFREE\r\n    #include \"rq_dcssp.h\"\r\n#elif defined RQ_RWLOCK\r\n    #include \"rq_rwlock.h\"\r\n#elif defined RQ_HTM_RWLOCK\r\n    #include \"rq_htm_rwlock.h\"\r\n#elif defined RQ_UNSAFE\r\n    #include \"rq_unsafe.h\"\r\n#elif defined RQ_SNAPCOLLECTOR\r\n    #include \"rq_snapcollector.h\"\r\n#else\r\n    #warning \"No range query method specified... using non-linearizable range queries. See rq_provider.h for other options.\"\r\n    #define RQ_UNSAFE\r\n    #include \"rq_unsafe.h\"\r\n    //#error NO RQ PROVIDER DEFINED\r\n#endif\r\n\r\n#endif /* RQ_PROVIDER_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_rwlock.h",
    "content": "/* \r\n * File:   rq_rwlock.h\r\n * Author: trbot\r\n *\r\n * Created on April 20, 2017, 1:03 PM\r\n */\r\n\r\n#ifndef RQ_RWLOCK_H\r\n#define\tRQ_RWLOCK_H\r\n\r\n#define MAX_NODES_DELETED_ATOMICALLY 8\r\n#define MAX_KEYS_PER_NODE 32\r\n\r\n#include \"rq_debugging.h\"\r\n#include <hashlist.h>\r\n#include <rwlock.h>\r\n#include <pthread.h>\r\n#include <cassert>\r\n\r\n// the following define enables an optimization that i'm not sure is correct.\r\n//#define COLLECT_ANNOUNCEMENTS_FAST\r\n\r\ntemplate <typename K, typename V, typename NodeType, typename DataStructure, typename RecordManager, bool logicalDeletion, bool canRetireNodesLogicallyDeletedByOtherProcesses>\r\nclass RQProvider {\r\nprivate:\r\n    struct __rq_thread_data {\r\n        #define __RQ_THREAD_DATA_SIZE 1024\r\n        union {\r\n            struct { // anonymous struct inside anonymous union means we don't need to type anything special to access these variables\r\n                long long rq_lin_time;\r\n                HashList<K> * hashlist;\r\n                volatile char padding0[PREFETCH_SIZE_BYTES];\r\n                void * announcements[MAX_NODES_DELETED_ATOMICALLY+1];\r\n                int numAnnouncements;\r\n            };\r\n            char bytes[__RQ_THREAD_DATA_SIZE]; // avoid false sharing\r\n        };\r\n    } __attribute__((aligned(__RQ_THREAD_DATA_SIZE)));\r\n\r\n    #define TIMESTAMP_NOT_SET 0\r\n    #define HASHLIST_INIT_CAPACITY_POW2 (1<<8)\r\n\r\n    const int NUM_PROCESSES;\r\n    volatile char padding0[PREFETCH_SIZE_BYTES];\r\n    volatile long long timestamp = 1;\r\n    volatile char padding1[PREFETCH_SIZE_BYTES];\r\n    RWLock rwlock;\r\n    volatile char padding2[PREFETCH_SIZE_BYTES];\r\n    __rq_thread_data * threadData;\r\n    \r\n    DataStructure * ds;\r\n    RecordManager * const recmgr;\r\n\r\n    int init[MAX_TID_POW2] = {0,};\r\n\r\npublic:\r\n    RQProvider(const int numProcesses, DataStructure * ds, RecordManager * recmgr) : NUM_PROCESSES(numProcesses), ds(ds), recmgr(recmgr) {\r\n        threadData = new __rq_thread_data[numProcesses];\r\n        DEBUG_INIT_RQPROVIDER(numProcesses);\r\n    }\r\n\r\n    ~RQProvider() {\r\n//        for (int tid=0;tid<NUM_PROCESSES;++tid) {\r\n//            threadData[tid].hashlist->destroy();\r\n//            delete threadData[tid].hashlist;\r\n//        }\r\n        delete[] threadData;\r\n        DEBUG_DEINIT_RQPROVIDER(NUM_PROCESSES);\r\n    }\r\n\r\n    // invoke before a given thread can perform any rq_functions\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        threadData[tid].hashlist = new HashList<K>();\r\n        threadData[tid].hashlist->init(HASHLIST_INIT_CAPACITY_POW2);\r\n        threadData[tid].numAnnouncements = 0;\r\n        for (int i=0;i<MAX_NODES_DELETED_ATOMICALLY+1;++i) {\r\n            threadData[tid].announcements[i] = NULL;\r\n        }\r\n        DEBUG_INIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke once a given thread will no longer perform any rq_ functions\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        threadData[tid].hashlist->destroy();\r\n        delete threadData[tid].hashlist;\r\n        DEBUG_DEINIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke whenever a new node is created/initialized\r\n    inline void init_node(const int tid, NodeType * const node) {\r\n        node->itime = TIMESTAMP_NOT_SET;\r\n        node->dtime = TIMESTAMP_NOT_SET;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any initialization of addr\r\n    // with invocations of rq_write_addr\r\n    template <typename T>\r\n    inline void write_addr(const int tid, T volatile * const addr, const T val) {\r\n        *addr = val;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any reads of addr with\r\n    // invocations of rq_read_addr\r\n    template <typename T>\r\n    inline T read_addr(const int tid, T volatile * const addr) {\r\n        return *addr;\r\n    }\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run some time BEFORE the physical deletion of a node\r\n    // whose key has ALREADY been logically deleted.\r\n    void announce_physical_deletion(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            threadData[tid].announcements[threadData[tid].numAnnouncements+i] = deletedNodes[i];\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        threadData[tid].numAnnouncements += i;\r\n        assert(threadData[tid].numAnnouncements <= MAX_NODES_DELETED_ATOMICALLY);\r\n        SOFTWARE_BARRIER;\r\n    }\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node failed.\r\n    void physical_deletion_failed(const int tid, NodeType * const * const deletedNodes) {\r\n        for (int i=0;deletedNodes[i];++i) {\r\n            --threadData[tid].numAnnouncements;\r\n#ifdef COLLECT_ANNOUNCEMENTS_FAST\r\n            threadData[tid].announcements[threadData[tid].numAnnouncements] = NULL;\r\n#endif\r\n        }\r\n        assert(threadData[tid].numAnnouncements >= 0);\r\n    }\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node succeeded.\r\n    void physical_deletion_succeeded(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            recmgr->retire(tid, deletedNodes[i]);\r\n        }\r\n        SOFTWARE_BARRIER; // ensure nodes are placed in the epoch bag BEFORE they are removed from announcements.\r\n        threadData[tid].numAnnouncements -= i;\r\n        assert(threadData[tid].numAnnouncements >= 0);\r\n    }\r\n    \r\nprivate:\r\n    \r\n    inline void set_insertion_timestamps(\r\n            const int tid,\r\n            const long long ts,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        // set insertion timestamps\r\n        // for each i_node in insertedNodes\r\n        for (int i_nodeix=0;insertedNodes[i_nodeix];++i_nodeix) {\r\n            insertedNodes[i_nodeix]->itime = ts;\r\n        }\r\n    }\r\n\r\n    inline void set_deletion_timestamps(\r\n            const int tid,\r\n            const long long ts,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        // set deletion timestamps\r\n        // for each d_node in deletedNodes\r\n        for (int d_nodeix=0;deletedNodes[d_nodeix];++d_nodeix) {\r\n            deletedNodes[d_nodeix]->dtime = ts;\r\n        }\r\n    }\r\n    \r\npublic:\r\n\r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a WRITE\r\n    template <typename T>\r\n    inline T linearize_update_at_write(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n        rwlock.readLock();\r\n        long long ts = timestamp;\r\n        *lin_addr = lin_newval; // original linearization point\r\n        rwlock.readUnlock();\r\n\r\n        set_insertion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n        set_deletion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n        \r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            physical_deletion_succeeded(tid, deletedNodes);\r\n        }\r\n        \r\n#if defined USE_RQ_DEBUGGING\r\n        DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        return lin_newval;\r\n    }\r\n    \r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a CAS\r\n    template <typename T>\r\n    inline T linearize_update_at_cas(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_oldval,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n        rwlock.readLock();\r\n        long long ts = timestamp;\r\n        T res = __sync_val_compare_and_swap(lin_addr, lin_oldval, lin_newval);\r\n        rwlock.readUnlock();\r\n        \r\n        if (res == lin_oldval){\r\n            set_insertion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n            set_deletion_timestamps(tid, ts, insertedNodes, deletedNodes);\r\n            \r\n            if (!logicalDeletion) {\r\n                // physical deletion will happen at the same time as logical deletion\r\n                physical_deletion_succeeded(tid, deletedNodes);\r\n            }\r\n            \r\n#if defined USE_RQ_DEBUGGING\r\n            DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        } else {\r\n            if (!logicalDeletion) {\r\n                // physical deletion will happen at the same time as logical deletion\r\n                physical_deletion_failed(tid, deletedNodes);\r\n            }            \r\n        }\r\n        return res;\r\n    }\r\n\r\n    // invoke at the start of each traversal\r\n    inline void traversal_start(const int tid) {\r\n        threadData[tid].hashlist->clear();\r\n        rwlock.writeLock();\r\n        threadData[tid].rq_lin_time = ++timestamp; // linearization point of range query (at the write to timestamp)\r\n        rwlock.writeUnlock();\r\n    }\r\n\r\nprivate:\r\n    // invoke each time a traversal visits a node with a key in the desired range:\r\n    // if the node belongs in the range query, it will be placed in rqResult[index]\r\n    inline int __traversal_try_add(const int tid, NodeType * const node, NodeType ** const nodeSource, K * const outputKeys, V * const outputValues, const K& lo, const K& hi, bool foundDuringTraversal) {\r\n        \r\n        // rqResultKeys should have space for MAX_KEYS_PER_NODE keys, AT LEAST\r\n        \r\n        // in the following, rather than having deeply nested if-else blocks,\r\n        // we return asap, and list facts that must be true if we didn't return\r\n        assert(foundDuringTraversal || !logicalDeletion || ds->isLogicallyDeleted(tid, node));\r\n        \r\n        long long itime = TIMESTAMP_NOT_SET;\r\n        while (itime == TIMESTAMP_NOT_SET) { itime = node->itime; }\r\n        if (node->itime >= threadData[tid].rq_lin_time) return 0;               // node was inserted after the range query\r\n        // fact: node was inserted before the range query\r\n        \r\n        bool logicallyDeleted = (logicalDeletion && ds->isLogicallyDeleted(tid, node));\r\n        long long dtime = TIMESTAMP_NOT_SET;\r\n\r\n        if (!logicalDeletion && foundDuringTraversal) goto tryAddToRQ;          // no logical deletion. since node was inserted before the range query, and the traversal encountered it, it must have been deleted AFTER the traversal encountered it.\r\n        // fact: no logical deletion ==> did not find node during traversal\r\n\r\n        dtime = node->dtime;\r\n        if (dtime != TIMESTAMP_NOT_SET) {\r\n            if (dtime < threadData[tid].rq_lin_time) return 0;                  // node was deleted before the range query\r\n            goto tryAddToRQ;\r\n        }\r\n\r\n        // fact: dtime was not set above\r\n        if (logicalDeletion && !logicallyDeleted) goto tryAddToRQ;              // if logical deletion is used with marking, the fact that node was inserted before the range query, and that the traversal encountered node, is NOT enough to argue that node was in the data structure when the traversal started. why? when the traversal encountered node, it might have already been marked. so, we check if node is marked. if not, then the node has not yet been deleted.\r\n        // fact: if there is logical deletion, then the node has now been deleted\r\n\r\n        ///////////////////////// HANDLE UNKNOWN DTIME /////////////////////////\r\n        // if we are executing this because node was ANNOUNCED by a process,\r\n        // as something that MIGHT soon be deleted (if nodeSource != NULL),\r\n        // then node might not ever actually be deleted,\r\n        // so we can't spin forever on dtime.\r\n        if (nodeSource != NULL) {\r\n            while (dtime == TIMESTAMP_NOT_SET && *nodeSource == node) { dtime = node->dtime; }\r\n            if (dtime == TIMESTAMP_NOT_SET) {\r\n                // above loop exited because the process removed its announcement to this node!\r\n                // if the process deleted the node, then it removed the\r\n                // announcement AFTER setting dtime.\r\n                // so we reread dtime one more time, to figure out whether\r\n                // the process actually deleted the node.\r\n                SOFTWARE_BARRIER; // prevent read of dtime from happening before last read of *nodeSource\r\n                dtime = node->dtime;\r\n                if (dtime == TIMESTAMP_NOT_SET) {\r\n                    // since dtime is not set, the process did NOT delete the node.\r\n                    // so, either a DIFFERENT process deleted it,\r\n                    // or it was found during the data structure traversal.\r\n                    // if another process deleted it, then we will find it\r\n                    // either in that process' announcements, or in a limbo bag.\r\n                    return 0;\r\n                }\r\n                // the node has been deleted, and dtime is set, so we check dtime below.\r\n            }\r\n        } else {\r\n            while (dtime == TIMESTAMP_NOT_SET) { dtime = node->dtime; }\r\n        }\r\n        if (dtime < threadData[tid].rq_lin_time) return 0;                      // node was deleted before the range query\r\n        // fact: node was inserted before the rq and deleted after it\r\n        \r\n        ///////////////////// TRY TO ADD NODE'S KEYS TO RQ /////////////////////\r\n        // note: this way of organizing this decision tree favors trees with fat multi-key nodes, because getKeys is delayed as long as possible.\r\n        \r\ntryAddToRQ:\r\n        // fetch the node's keys that are in the set\r\n        int cnt = ds->getKeys(tid, node, outputKeys, outputValues);\r\n        assert(cnt < RQ_DEBUGGING_MAX_KEYS_PER_NODE);\r\n        if (cnt == 0) return 0;                                                 // node doesn't contain any keys that are in the set\r\n        // TODO: properly assert that getKeys doesn't run out of bounds on outputKeys[...] (i'm quite certain it doesn't, currently, though.)\r\n        \r\n        // note: in the following loop, we shift keys in the outputKeys array left to eliminate any that ultimately should not be added to the range query\r\n        int numNewKeys = 0;\r\n        for (int i=0;i<cnt;++i) {                                               // decide whether key = outputKeys[i] should be in the range query\r\n            if (!ds->isInRange(outputKeys[i], lo, hi)) goto doNotAddToRQ;       // key is NOT in the desired range\r\n            if (threadData[tid].hashlist->contains(outputKeys[i])) goto doNotAddToRQ; // key is already in the range query\r\n            outputKeys[numNewKeys] = outputKeys[i];                             // save this as a new key added to the RQ\r\n            outputValues[numNewKeys] = outputValues[i];\r\n            ++numNewKeys;\r\n\r\ndoNotAddToRQ: (0);\r\n        }\r\n        return numNewKeys;\r\n    }\r\n    \r\n    inline void traversal_try_add(const int tid, NodeType * const node, NodeType ** const nodeSource, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi, bool foundDuringTraversal) {\r\n//#if defined MICROBENCH && !defined NDEBUG\r\n//        assert(*startIndex < 2*RQSIZE); // note: this assert is a hack. it should be *startIndex < size of rqResultKeys\r\n//        if (*startIndex >= RQSIZE) {\r\n//            cout<<\"ERROR: *startIndex=\"<<(*startIndex)<<\" is unexpectedly greater than or equal to RQSIZE=\"<<RQSIZE<<\" (lo=\"<<lo<<\" hi=\"<<hi<<\")\"<<endl;\r\n//            cout<<\"results:\";\r\n//            for (int i=0;i<*startIndex;++i) {\r\n//                cout<<\" \"<<rqResultKeys[i];\r\n//            }\r\n//            cout<<endl;\r\n//            exit(-1);\r\n//        }\r\n//#endif\r\n        int numNewKeys = __traversal_try_add(tid, node, nodeSource, rqResultKeys+(*startIndex), rqResultValues+(*startIndex), lo, hi, foundDuringTraversal);\r\n//#if defined MICROBENCH\r\n//        assert(*startIndex + numNewKeys < 2*RQSIZE); // note: this assert is a hack. it should be *startIndex + numNewKeys < size of rqResultKeys array\r\n//#endif\r\n        for (int i=0;i<numNewKeys;++i) {\r\n            threadData[tid].hashlist->insert(rqResultKeys[(*startIndex)++]);\r\n        }\r\n        // note: the above increments startIndex\r\n#if defined MICROBENCH\r\n        assert(*startIndex <= RQSIZE);\r\n#endif\r\n    }\r\n\r\npublic:\r\n    inline void traversal_try_add(const int tid, NodeType * const node, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        traversal_try_add(tid, node, NULL, rqResultKeys, rqResultValues, startIndex, lo, hi, true);\r\n    }\r\n    \r\n    // invoke at the end of each traversal:\r\n    // any nodes that were deleted during the traversal,\r\n    // and were consequently missed during the traversal,\r\n    // are placed in rqResult[index]\r\n    void traversal_end(const int tid, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        // todo: possibly optimize by skipping entire blocks if there are many keys to skip (does not seem to be justifiable for 4 work threads and 4 range query threads)\r\n\r\n        SOFTWARE_BARRIER;\r\n        long long end_timestamp = timestamp;\r\n        SOFTWARE_BARRIER;\r\n        \r\n        // collect nodes announced by other processes\r\n#ifdef COLLECT_ANNOUNCEMENTS_FAST\r\n        int numCollected = 0;\r\n        NodeType * collectedAnnouncement[NUM_PROCESSES*MAX_NODES_DELETED_ATOMICALLY];\r\n        NodeType ** announcementSource[NUM_PROCESSES*MAX_NODES_DELETED_ATOMICALLY];\r\n#endif\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            int sz = threadData[otherTid].numAnnouncements;\r\n            SOFTWARE_BARRIER;\r\n            for (int i=0;i<sz;++i) {\r\n                NodeType * node = (NodeType *) threadData[otherTid].announcements[i];\r\n                assert(node);\r\n#ifdef COLLECT_ANNOUNCEMENTS_FAST\r\n                collectedAnnouncement[numCollected] = node;\r\n                announcementSource[numCollected] = (NodeType **) &threadData[otherTid].announcements[i];\r\n                ++numCollected;\r\n#else\r\n                traversal_try_add(tid, node, (NodeType **) &threadData[otherTid].announcements[i], rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n#endif\r\n            }\r\n        }\r\n        SOFTWARE_BARRIER;\r\n        \r\n        // TODO: add ability to bail out of waiting for dtime if node is no longer announced! (needed when COLLECT_ANNOUNCEMENTS_FAST is NOT defined)\r\n        \r\n        // collect epoch bags of other processes (MUST be after collecting announcements!)\r\n        blockbag<NodeType> * all_bags[NUM_PROCESSES*NUMBER_OF_EPOCH_BAGS+1];\r\n        vector<blockbag_iterator<NodeType>> all_iterators;\r\n        int numIterators = 0;\r\n        for (int otherTid=0;otherTid<NUM_PROCESSES;++otherTid) if (otherTid != tid) {\r\n            blockbag<NodeType> * thread_bags[NUMBER_OF_EPOCH_BAGS+1];\r\n            recmgr->get((NodeType *) NULL)->reclaim->getSafeBlockbags(otherTid, thread_bags);\r\n            for (int i=0;thread_bags[i];++i) {\r\n                all_bags[numIterators] = thread_bags[i];\r\n                all_iterators.push_back(thread_bags[i]->begin());\r\n                ++numIterators;\r\n            }\r\n        }\r\n        \r\n#ifdef COLLECT_ANNOUNCEMENTS_FAST\r\n        // try to add nodes collected from process announcements to the RQ\r\n        for (int i=0;i<numCollected;++i) {\r\n            traversal_try_add(tid, collectedAnnouncement[i], announcementSource[i], rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n        }\r\n#endif\r\n        \r\n        int numSkippedInEpochBags = 0;\r\n        int numVisitedInEpochBags = 0;\r\n        for (int ix = 0; ix < numIterators; ++ix) {\r\n            for (; all_iterators[ix] != all_bags[ix]->end(); all_iterators[ix]++) {\r\n                NodeType * node = (*all_iterators[ix]);\r\n                assert(node);\r\n\r\n                ++numVisitedInEpochBags;\r\n                ++numSkippedInEpochBags;\r\n\r\n                long long dtime = node->dtime;\r\n                if (dtime != TIMESTAMP_NOT_SET && dtime > end_timestamp) continue;\r\n\r\n                --numSkippedInEpochBags;\r\n\r\n                if (!(logicalDeletion && canRetireNodesLogicallyDeletedByOtherProcesses)) {\r\n                    // if we cannot retire nodes that are logically deleted\r\n                    // by other processes, then we always retire nodes in\r\n                    // order of increasing dtime values.\r\n                    // so, the blockbag will be ordered, which means that,\r\n                    // if dtime is before the RQ, then all remaining nodes\r\n                    // in this bag were deleted before the RQ.\r\n                    // so, in this case, we skip to the next bag.\r\n                    if (dtime != TIMESTAMP_NOT_SET && dtime < threadData[tid].rq_lin_time) break;\r\n                }\r\n\r\n                traversal_try_add(tid, node, NULL, rqResultKeys, rqResultValues, startIndex, lo, hi, false);\r\n            }\r\n        }\r\n\r\n#if defined MICROBENCH && !defined NDEBUG\r\n        if (*startIndex > RQSIZE) {\r\n            cout<<\"ERROR: *startIndex=\"<<(*startIndex)<<\" is unexpectedly greater than or equal to RQSIZE=\"<<RQSIZE<<\" (lo=\"<<lo<<\" hi=\"<<hi<<\")\"<<endl;\r\n            cout<<\"results:\";\r\n            for (int i=0;i<*startIndex;++i) {\r\n                cout<<\" \"<<rqResultKeys[i];\r\n            }\r\n            cout<<endl;\r\n            exit(-1);\r\n        }\r\n#endif\r\n        \r\n#ifdef __HANDLE_STATS\r\n        GSTATS_ADD_IX(tid, skipped_in_bags, numSkippedInEpochBags, threadData[tid].rq_lin_time);\r\n        GSTATS_ADD_IX(tid, visited_in_bags, numVisitedInEpochBags, threadData[tid].rq_lin_time);\r\n#endif\r\n        DEBUG_RECORD_RQ_VISITED(tid, threadData[tid].rq_lin_time, numVisitedInEpochBags);\r\n        DEBUG_RECORD_RQ_SIZE(*startIndex);\r\n        DEBUG_RECORD_RQ_CHECKSUM(tid, threadData[tid].rq_lin_time, rqResultKeys, *startIndex);\r\n    }\r\n};\r\n\r\n#endif\t/* RQ_RWLOCK_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_snapcollector.h",
    "content": "/* \r\n * File:   rq_rwlock.h\r\n * Author: trbot\r\n *\r\n * Created on April 20, 2017, 1:03 PM\r\n * \r\n * Implementation of Shahar Timnat's Iterator algorithm.\r\n * \r\n * WARNING:\r\n * 1. Shahar's algorithm ONLY supports data structures with logical deletion.\r\n * 2. It only supports data structures where each node contains ONE key.\r\n * 3. It only supports taking a snapshot of the entire data structure.\r\n * 4. It only supports insertion, deletion and search operations.\r\n *    If a data structure has other operations, it might not be linearizable.\r\n */\r\n\r\n#ifndef RQ_RWLOCK_H\r\n#define\tRQ_RWLOCK_H\r\n\r\n#define MAX_NODES_DELETED_ATOMICALLY 1\r\n#define MAX_KEYS_PER_NODE 1\r\n\r\n#include \"errors.h\"\r\n#include \"rq_debugging.h\"\r\n#include <record_manager.h>\r\n#include <pthread.h>\r\n#include <cassert>\r\n#include \"snapcollector.h\"\r\n\r\ntemplate <typename K, typename V, typename NodeType, typename DataStructure, typename RecordManager, bool logicalDeletion, bool canRetireNodesLogicallyDeletedByOtherProcesses>\r\nclass RQProvider {\r\nprivate:\r\n    struct __rq_thread_data {\r\n        #define __RQ_THREAD_DATA_SIZE 1024\r\n        union {\r\n            struct { // anonymous struct inside anonymous union means we don't need to type anything special to access these variables\r\n                long long rq_lin_time;\r\n                SnapCollector<NodeType,K> * currentSnapCollector;\r\n                SnapCollector<NodeType,K> * snapCollectorToRetire;\r\n            };\r\n            char bytes[__RQ_THREAD_DATA_SIZE]; // avoid false sharing\r\n        };\r\n    } __attribute__((aligned(__RQ_THREAD_DATA_SIZE)));\r\n\r\n    const int NUM_PROCESSES;\r\n    volatile long long timestamp = 1;\r\n    pthread_rwlock_t rwlock;\r\n    __rq_thread_data * threadData;\r\n    \r\n    DataStructure * const ds;\r\n    RecordManager * const recmgr;\r\n    volatile char padding[PREFETCH_SIZE_BYTES];\r\n    SnapCollector<NodeType,K> * volatile snapPointer;\r\n    \r\n    int init[MAX_TID_POW2] = {0,};\r\n\r\npublic:\r\n    RQProvider(const int numProcesses, DataStructure * ds, RecordManager * recmgr) : NUM_PROCESSES(numProcesses), ds(ds), recmgr(recmgr) {\r\n        assert(logicalDeletion); // Timnat's iterator algorithm REQUIRES logical deletion!\r\n        if (pthread_rwlock_init(&rwlock, NULL)) error(\"could not init rwlock\");\r\n        threadData = new __rq_thread_data[numProcesses];\r\n        \r\n        const int dummyTid = 0;\r\n        \r\n        recmgr->initThread(dummyTid); // must initialize record manager before allocating!!\r\n        initThread(dummyTid);\r\n        \r\n        // initialize dummy snap collector\r\n        snapPointer = recmgr->template allocate<SnapCollector<NodeType,K> >(dummyTid);\r\n#ifdef __HANDLE_STATS\r\n        GSTATS_APPEND(dummyTid, extra_type1_allocated_addresses, ((long long) snapPointer)%(1<<12));\r\n#endif\r\n        snapPointer->init(dummyTid, numProcesses, recmgr, ds->KEY_MIN, ds->KEY_MAX+1);\r\n        snapPointer->BlockFurtherPointers(dummyTid, recmgr);\r\n        snapPointer->Deactivate(NULL, NULL, NULL);\r\n        snapPointer->BlockFurtherReports();\r\n        \r\n        DEBUG_INIT_RQPROVIDER(numProcesses);\r\n    }\r\n\r\n    ~RQProvider() {\r\n        if (pthread_rwlock_destroy(&rwlock)) error(\"could not destroy rwlock\");\r\n        delete[] threadData;\r\n        snapPointer->retire(0 /* dummy tid */, recmgr);\r\n        DEBUG_DEINIT_RQPROVIDER(NUM_PROCESSES);\r\n    }\r\n\r\n    // invoke before a given thread can perform any rq_functions\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        threadData[tid].rq_lin_time = 0;\r\n        threadData[tid].currentSnapCollector = NULL;\r\n        threadData[tid].snapCollectorToRetire = NULL;\r\n        DEBUG_INIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke once a given thread will no longer perform any rq_ functions\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        DEBUG_DEINIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke whenever a new node is created/initialized\r\n    inline void init_node(const int tid, NodeType * const node) {}\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any initialization of addr\r\n    // with invocations of rq_write_addr\r\n    template <typename T>\r\n    inline void write_addr(const int tid, T volatile * const addr, const T val) {\r\n        *addr = val;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any reads of addr with\r\n    // invocations of rq_read_addr\r\n    template <typename T>\r\n    inline T read_addr(const int tid, T volatile * const addr) {\r\n        return *addr;\r\n    }\r\n\r\n    /**\r\n     * Added function only for Timnat's SnapCollector.\r\n     * This must be invoked just before the return statement of every search.\r\n     */\r\n    inline void search_report_target_key(const int tid, const K key, NodeType * const node) {\r\n        SnapCollector<NodeType,K> * sc = snapPointer;\r\n        if (sc->IsActive()) {\r\n            ReportType type = ds->isLogicallyDeleted(tid, node) ? ReportType::Remove : ReportType::Add;\r\n            sc->Report(tid, node, type, key, recmgr);\r\n        }\r\n        SOFTWARE_BARRIER;\r\n    }\r\n    \r\n    /**\r\n     * Added function only for Timnat's SnapCollector.\r\n     * This must be invoked just before the return statement of every insertion\r\n     *      that does not modify the data structure.\r\n     */\r\n    inline void insert_readonly_report_target_key(const int tid, NodeType * const node) {\r\n        SnapCollector<NodeType,K> * sc = snapPointer;\r\n        if (sc->IsActive()) {\r\n            if (!ds->isLogicallyDeleted(tid, node)) {\r\n                sc->Report(tid, node, ReportType::Add, node->key, recmgr);\r\n            }\r\n        }\r\n        SOFTWARE_BARRIER;\r\n    }\r\n    \r\n    /**\r\n     * Added function only for Timnat's SnapCollector.\r\n     * This can be invoked to determine if the current SnapCollector is active.\r\n     */\r\n    inline bool traversal_is_active(const int tid) {\r\n        return threadData[tid].currentSnapCollector->IsActive();\r\n    }\r\n    \r\nprivate:\r\n    inline void delete_report_target_key(const int tid, NodeType * const node) {\r\n        if (node) {\r\n            SnapCollector<NodeType,K> * sc = snapPointer;\r\n            if (sc->IsActive()) {\r\n                sc->Report(tid, node, ReportType::Remove, node->key, recmgr);\r\n            }\r\n            SOFTWARE_BARRIER;\r\n        }\r\n    }\r\n    \r\npublic:\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run some time BEFORE the physical deletion of a node\r\n    // whose key has ALREADY been logically deleted.\r\n    inline void announce_physical_deletion(const int tid, NodeType * const * const deletedNodes) {\r\n        assert(!deletedNodes[0] || !deletedNodes[1]);\r\n        delete_report_target_key(tid, deletedNodes[0]);\r\n    }\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node failed.\r\n    inline void physical_deletion_failed(const int tid, NodeType * const * const deletedNodes) {}\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node succeeded.\r\n    inline void physical_deletion_succeeded(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            recmgr->retire(tid, deletedNodes[i]);\r\n        }\r\n    }\r\n    \r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a WRITE\r\n    template <typename T>\r\n    inline T linearize_update_at_write(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n        \r\n        assert((insertedNodes[0] && !deletedNodes[0])\r\n                || (!insertedNodes[0] && deletedNodes[0]));\r\n\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        if (pthread_rwlock_rdlock(&rwlock)) error(\"could not read-lock rwlock\");\r\n        long long ts = timestamp;\r\n#else\r\n        long long ts = 1;\r\n#endif\r\n\r\n        *lin_addr = lin_newval; // original linearization point\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        if (pthread_rwlock_unlock(&rwlock)) error(\"could not read-unlock rwlock\");\r\n#endif\r\n        \r\n        if (insertedNodes[0]) insert_readonly_report_target_key(tid, insertedNodes[0]);\r\n        if (deletedNodes[0]) delete_report_target_key(tid, deletedNodes[0]);\r\n\r\n#if defined USE_RQ_DEBUGGING\r\n        DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        return lin_newval;\r\n    }\r\n    \r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a CAS\r\n    template <typename T>\r\n    inline T linearize_update_at_cas(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_oldval,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        assert((insertedNodes[0] && !deletedNodes[0])\r\n                || (!insertedNodes[0] && deletedNodes[0]));\r\n\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        if (pthread_rwlock_rdlock(&rwlock)) error(\"could not read-lock rwlock\");\r\n        long long ts = timestamp;\r\n#else\r\n        long long ts = 1;\r\n#endif\r\n        \r\n        T res = __sync_val_compare_and_swap(lin_addr, lin_oldval, lin_newval);\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        if (pthread_rwlock_unlock(&rwlock)) error(\"could not read-unlock rwlock\");\r\n#endif\r\n        \r\n        if (res == lin_oldval){\r\n            if (insertedNodes[0]) insert_readonly_report_target_key(tid, insertedNodes[0]);\r\n            if (deletedNodes[0]) delete_report_target_key(tid, deletedNodes[0]);\r\n\r\n#if defined USE_RQ_DEBUGGING\r\n            DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        }\r\n        return res;\r\n    }\r\n\r\n    // invoke at the start of each traversal\r\n    inline void traversal_start(const int tid) {\r\n#if !defined(RQ_USE_TIMESTAMPS)\r\n        threadData[tid].rq_lin_time = 1;\r\n#endif        \r\n\r\n        threadData[tid].currentSnapCollector = snapPointer;\r\n        SOFTWARE_BARRIER;\r\n        if (!threadData[tid].currentSnapCollector->IsActive()) {\r\n            SnapCollector<NodeType,K> * candidate = recmgr->template allocate<SnapCollector<NodeType,K> >(tid);\r\n#ifdef __HANDLE_STATS\r\n            GSTATS_APPEND(tid, extra_type1_allocated_addresses, ((long long) candidate)%(1<<12));\r\n#endif\r\n            candidate->init(tid, NUM_PROCESSES, recmgr, ds->KEY_MIN, ds->KEY_MAX+1);\r\n            if (__sync_bool_compare_and_swap(&snapPointer, threadData[tid].currentSnapCollector, candidate)) {\r\n                // delay retiring until later, because we've started accepting reports,\r\n                // and we don't want to waste time while we are accepting reports,\r\n                // because we don't want to receive many reports...\r\n                threadData[tid].snapCollectorToRetire = threadData[tid].currentSnapCollector;\r\n                threadData[tid].currentSnapCollector = candidate;\r\n            } else {\r\n                candidate->retire(tid, recmgr);\r\n                threadData[tid].currentSnapCollector = snapPointer;\r\n            }\r\n        }\r\n//        usleep(200000);\r\n    }\r\n\r\n    inline NodeType * traversal_try_add(const int tid, NodeType * const node, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        SnapCollector<NodeType,K> * sc = threadData[tid].currentSnapCollector;\r\n        return sc->AddNode(tid, node, node->key, recmgr);\r\n    }\r\n    \r\n    // invoke at the end of each traversal:\r\n    // any nodes that were deleted during the traversal,\r\n    // and were consequently missed during the traversal,\r\n    // are placed in rqResult[index]\r\n    void traversal_end(const int tid, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        SnapCollector<NodeType,K> * sc = threadData[tid].currentSnapCollector;\r\n\r\n        sc->BlockFurtherPointers(tid, recmgr);\r\n        SOFTWARE_BARRIER;\r\n        sc->Deactivate(NULL, NULL, NULL);\r\n        sc->BlockFurtherReports();\r\n        SOFTWARE_BARRIER;\r\n\r\n        sc->Prepare(tid, recmgr);\r\n        \r\n        NodeType * curr = NULL;\r\n        while ((curr = sc->GetNext(tid))) {\r\n            if (curr->key < lo) continue;\r\n            if (curr->key > hi) break;\r\n            rqResultKeys[*startIndex] = curr->key;\r\n            rqResultValues[*startIndex] = curr->val;\r\n            ++*startIndex;\r\n        }\r\n#if defined MICROBENCH\r\n        assert(*startIndex <= RQSIZE);\r\n#endif\r\n        \r\n#ifdef SNAPCOLLECTOR_PRINT_RQS\r\n//        for (int i=0;i<*startIndex;++i) {\r\n//            cout<<\" \"<<rqResultKeys[i];\r\n//        }\r\n//        cout<<endl;\r\n#endif\r\n        \r\n        DEBUG_RECORD_RQ_SIZE(*startIndex);\r\n        DEBUG_RECORD_RQ_CHECKSUM(tid, threadData[tid].rq_lin_time, rqResultKeys, *startIndex);\r\n\r\n        // retire any snap collector that we replaced in this RQ\r\n        if (threadData[tid].snapCollectorToRetire) {\r\n            threadData[tid].snapCollectorToRetire->retire(tid, recmgr);\r\n            threadData[tid].snapCollectorToRetire = NULL;\r\n        }\r\n    }\r\n};\r\n\r\n#endif\t/* RQ_RWLOCK_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/rq_unsafe.h",
    "content": "/* \r\n * File:   rq_unsafe.h\r\n * Author: trbot\r\n *\r\n * Created on May 15, 2017, 5:06 PM\r\n */\r\n\r\n#ifndef RQ_UNSAFE_H\r\n#define\tRQ_UNSAFE_H\r\n\r\n#include \"rq_debugging.h\"\r\n#include <rwlock.h>\r\n#include <pthread.h>\r\n\r\n#ifndef casword_t\r\n#define casword_t uintptr_t\r\n#endif\r\n\r\ntemplate <typename K, typename V, typename NodeType, typename DataStructure, typename RecordManager, bool logicalDeletion, bool canRetireNodesLogicallyDeletedByOtherProcesses>\r\nclass RQProvider {\r\nprivate:\r\n    struct __rq_thread_data {\r\n        #define __RQ_THREAD_DATA_SIZE 1024\r\n        union {\r\n            struct { // anonymous struct inside anonymous union means we don't need to type anything special to access these variables\r\n                long long rq_lin_time;\r\n            };\r\n            char bytes[__RQ_THREAD_DATA_SIZE]; // avoid false sharing\r\n        };\r\n    } __attribute__((aligned(__RQ_THREAD_DATA_SIZE)));\r\n\r\n    #define TIMESTAMP_NOT_SET 0\r\n    \r\n    const int NUM_PROCESSES;\r\n    volatile char padding0[PREFETCH_SIZE_BYTES];\r\n    volatile long long timestamp = 1;\r\n    volatile char padding1[PREFETCH_SIZE_BYTES];\r\n    RWLock rwlock;\r\n    volatile char padding2[PREFETCH_SIZE_BYTES];\r\n    __rq_thread_data * threadData;\r\n    \r\n    DataStructure * ds;\r\n    RecordManager * const recmgr;\r\n\r\n    int init[MAX_TID_POW2] = {0,};\r\n\r\npublic:\r\n    RQProvider(const int numProcesses, DataStructure * ds, RecordManager * recmgr) : NUM_PROCESSES(numProcesses), ds(ds), recmgr(recmgr) {\r\n        threadData = new __rq_thread_data[numProcesses];\r\n        DEBUG_INIT_RQPROVIDER(numProcesses);\r\n    }\r\n\r\n    ~RQProvider() {\r\n        delete[] threadData;\r\n        DEBUG_DEINIT_RQPROVIDER(NUM_PROCESSES);\r\n    }\r\n\r\n    // invoke before a given thread can perform any rq_functions\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        DEBUG_INIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke once a given thread will no longer perform any rq_ functions\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        DEBUG_DEINIT_THREAD(tid);\r\n    }\r\n\r\n    // invoke whenever a new node is created/initialized\r\n    inline void init_node(const int tid, NodeType * const node) {}\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any initialization of addr\r\n    // with invocations of rq_write_addr\r\n    template <typename T>\r\n    inline void write_addr(const int tid, T volatile * const addr, const T val) {\r\n        *addr = val;\r\n    }\r\n\r\n    // for each address addr that is modified by rq_linearize_update_at_write\r\n    // or rq_linearize_update_at_cas, you must replace any reads of addr with\r\n    // invocations of rq_read_addr\r\n    template <typename T>\r\n    inline T read_addr(const int tid, T volatile * const addr) {\r\n        return *addr;\r\n    }\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run some time BEFORE the physical deletion of a node\r\n    // whose key has ALREADY been logically deleted.\r\n    inline void announce_physical_deletion(const int tid, NodeType * const * const deletedNodes) {}\r\n\r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node failed.\r\n    inline void physical_deletion_failed(const int tid, NodeType * const * const deletedNodes) {}\r\n    \r\n    // IF DATA STRUCTURE PERFORMS LOGICAL DELETION\r\n    // run AFTER performing announce_physical_deletion,\r\n    // if the cas that was trying to physically delete node succeeded.\r\n    inline void physical_deletion_succeeded(const int tid, NodeType * const * const deletedNodes) {\r\n        int i;\r\n        for (i=0;deletedNodes[i];++i) {\r\n            recmgr->retire(tid, deletedNodes[i]);\r\n        }\r\n    }\r\n\r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a WRITE\r\n    template <typename T>\r\n    inline T linearize_update_at_write(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n#ifdef RQ_USE_TIMESTAMPS\r\n        rwlock.readLock();\r\n        long long ts = timestamp;\r\n#else\r\n        long long ts = 1;\r\n#endif\r\n\r\n        *lin_addr = lin_newval; // original linearization point\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        rwlock.readUnlock();\r\n#endif\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            physical_deletion_succeeded(tid, deletedNodes);\r\n        }\r\n        \r\n#if defined USE_RQ_DEBUGGING\r\n        DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        return lin_newval;\r\n    }\r\n\r\n    // replace the linearization point of an update that inserts or deletes nodes\r\n    // with an invocation of this function if the linearization point is a CAS\r\n    template <typename T>\r\n    inline T linearize_update_at_cas(\r\n            const int tid,\r\n            T volatile * const lin_addr,\r\n            const T& lin_oldval,\r\n            const T& lin_newval,\r\n            NodeType * const * const insertedNodes,\r\n            NodeType * const * const deletedNodes) {\r\n\r\n        if (!logicalDeletion) {\r\n            // physical deletion will happen at the same time as logical deletion\r\n            announce_physical_deletion(tid, deletedNodes);\r\n        }\r\n        \r\n#ifdef RQ_USE_TIMESTAMPS\r\n        rwlock.readLock();\r\n        long long ts = timestamp;\r\n#else\r\n        long long ts = 1;\r\n#endif\r\n        T res = __sync_val_compare_and_swap(lin_addr, lin_oldval, lin_newval); // original linearization point\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        rwlock.readUnlock();\r\n#endif\r\n\r\n        if (res == lin_oldval) {\r\n            if (!logicalDeletion) {\r\n                // physical deletion will happen at the same time as logical deletion\r\n                physical_deletion_succeeded(tid, deletedNodes);\r\n            }\r\n\r\n#if defined USE_RQ_DEBUGGING\r\n            DEBUG_RECORD_UPDATE_CHECKSUM<K,V>(tid, ts, insertedNodes, deletedNodes, ds);\r\n#endif\r\n        } else {\r\n            if (!logicalDeletion) {\r\n                // physical deletion will happen at the same time as logical deletion\r\n                physical_deletion_failed(tid, deletedNodes);\r\n            }\r\n        }\r\n        \r\n        return res;\r\n    }\r\n\r\n    // invoke at the start of each traversal\r\n    inline void traversal_start(const int tid) {\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        rwlock.writeLock();\r\n        threadData[tid].rq_lin_time = ++timestamp; // linearization point of range query (at the write to timestamp)\r\n        rwlock.writeUnlock();\r\n#endif\r\n    }\r\n\r\n    // invoke each time a traversal visits a node with a key in the desired range:\r\n    // if the node belongs in the range query, it will be placed in rqResult[index]\r\n    inline void traversal_try_add(const int tid, NodeType * const node, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        int start = (*startIndex);\r\n        int keysInNode = ds->getKeys(tid, node, rqResultKeys+start, rqResultValues+start);\r\n        assert(keysInNode < RQ_DEBUGGING_MAX_KEYS_PER_NODE);\r\n        if (keysInNode == 0) return;\r\n        int location = start; \r\n        for (int i=start;i<keysInNode+start;++i) {\r\n            if (ds->isInRange(rqResultKeys[i], lo, hi)){\r\n                rqResultKeys[location] = rqResultKeys[i];\r\n                rqResultValues[location] = rqResultValues[i];\r\n                ++location;\r\n            }   \r\n        }\r\n        *startIndex = location;\r\n#if defined MICROBENCH\r\n        assert(*startIndex <= RQSIZE);\r\n#endif\r\n    }\r\n\r\n    // invoke at the end of each traversal:\r\n    // any nodes that were deleted during the traversal,\r\n    // and were consequently missed during the traversal,\r\n    // are placed in rqResult[index]\r\n    inline void traversal_end(const int tid, K * const rqResultKeys, V * const rqResultValues, int * const startIndex, const K& lo, const K& hi) {\r\n        DEBUG_RECORD_RQ_SIZE(*startIndex);\r\n        DEBUG_RECORD_RQ_CHECKSUM(tid, threadData[tid].rq_lin_time, rqResultKeys, *startIndex);\r\n    }\r\n};\r\n\r\n#endif\t/* RQ_UNSAFE_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/snapcollector/reportitem.h",
    "content": "/* \r\n * File:   reportitem.h\r\n * Author: trbot\r\n *\r\n * Created on June 21, 2017, 4:47 PM\r\n */\r\n\r\n#ifndef REPORTITEM_H\r\n#define REPORTITEM_H\r\n\r\nenum ReportType {Add, Remove};\r\n\r\nstatic int getOrdinalForReportType(ReportType t) {\r\n    return (t == ReportType::Add);\r\n}\r\n\r\nclass ReportItem {\r\npublic:\r\n    void * node;\r\n    ReportType t;\r\n    ReportItem * volatile next;\r\n    int key;\r\n    int id;\r\n    \r\n    ReportItem() {}\r\n    void init(void * node, ReportType t, int key) {\r\n        this->node = node;\r\n        this->t = t;\r\n        next = NULL;\r\n        this->key = key;\r\n        id = 0;\r\n    }\r\n};\r\n\r\nclass CompactReportItem {\r\npublic:\r\n    void * node;\r\n    ReportType t;\r\n    int key;\r\n    int id;\r\n    \r\n    CompactReportItem() {}\r\n    void init(void * node, ReportType t, int key) {\r\n        this->node = node;\r\n        this->t = t;\r\n        this->key = key;\r\n        id = 0;\r\n    }\r\n};\r\n\r\nstruct {\r\n    bool operator()(CompactReportItem * a, CompactReportItem * b) const {\r\n        if (a->key != b->key) return a->key < b->key;\r\n        if (a->node != b->node) return (long long) a->node < (long long) b->node;\r\n        return getOrdinalForReportType(a->t) < getOrdinalForReportType(b->t);\r\n    }\r\n} compareCRI;\r\n\r\n#endif /* REPORTITEM_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/snapcollector/snapcollector.h",
    "content": "/* \r\n * File:   snapcollector.h\r\n * Author: trbot\r\n *\r\n * Created on June 21, 2017, 4:57 PM\r\n */\r\n\r\n#ifndef SNAPCOLLECTOR_H\r\n#define SNAPCOLLECTOR_H\r\n\r\n#include <limits>\r\n#include <vector>\r\n#include <algorithm>\r\n#include \"reportitem.h\"\r\n#include <plaf.h>\r\n\r\ntemplate <typename NodeType, typename K>\r\nclass SnapCollector {\r\npublic:\r\n    int NUM_THREADS;\r\n    \r\n    class NodeWrapper {\r\n    public:\r\n        NodeType * node;\r\n        NodeWrapper * volatile next;\r\n        K key;\r\n        \r\n        NodeWrapper() {}\r\n        void init(K key) {\r\n            this->node = NULL;\r\n            this->next = NULL;\r\n            this->key = key;\r\n        }\r\n        void init(NodeType * node, K key) {\r\n            this->node = node;\r\n            this->next = NULL;\r\n            this->key = key;\r\n        }\r\n    };\r\n    \r\nprivate:\r\n    ReportItem * volatile * reportHeads;\r\n    ReportItem * volatile * reportTails;\r\n    \r\n    NodeWrapper * volatile head;\r\n    NodeWrapper * volatile tail;\r\n    ReportItem * blocker;\r\n    volatile bool active;\r\n    \r\n    // variables used for aggregating reports after they are collected\r\n    void ** currLocations;\r\n    int * currRepLocations;\r\n    std::vector<CompactReportItem *> * volatile gAllReports;\r\n    \r\n    K KEY_MAX;\r\n    K KEY_MIN;\r\n\r\nprivate:\r\n    \r\n    inline bool isBlocker(NodeWrapper const * const wrapper) {\r\n        if (wrapper) {\r\n            K key = wrapper->key;\r\n            NodeType * node = wrapper->node;\r\n            K key2 = KEY_MAX;\r\n            return (key == key2 && node == NULL);\r\n        }\r\n        return false;\r\n    }\r\n    \r\n    template <typename RecordManager>\r\n    inline void __retireAllReports(const int tid, std::vector<CompactReportItem *> * v, RecordManager * recmgr) {\r\n        if (v == NULL) return;\r\n        for (auto it = v->begin(); it != v->end(); it++) {\r\n            // retire compact report items\r\n            recmgr->retire(tid, *it);\r\n        }\r\n    }\r\n    \r\n    template <typename RecordManager>\r\n    inline void __deallocateAllReports(const int tid, std::vector<CompactReportItem *> * v, RecordManager * recmgr) {\r\n        if (v == NULL) return;\r\n        for (auto it = v->begin(); it != v->end(); it++) {\r\n            // deallocate compact report items\r\n            recmgr->deallocate(tid, *it);\r\n        }\r\n        delete v;\r\n    }\r\n    \r\npublic:\r\n    \r\n    template <typename RecordManager>\r\n    void init(const int tid, const int numProcesses, RecordManager * const recmgr, const K _KEY_MIN, const K _KEY_MAX) {\r\n        this->KEY_MIN = _KEY_MIN;\r\n        this->KEY_MAX = _KEY_MAX;\r\n        \r\n        this->NUM_THREADS = numProcesses;\r\n        this->reportHeads = new ReportItem * volatile [NUM_THREADS*PREFETCH_SIZE_WORDS];\r\n        this->reportTails = new ReportItem * volatile [NUM_THREADS*PREFETCH_SIZE_WORDS];\r\n        // head = new NodeWrapper(std::numeric_limits<int>::min())\r\n        this->head = recmgr->template allocate<NodeWrapper>(tid);\r\n#ifdef __HANDLE_STATS\r\n        GSTATS_APPEND(tid, extra_type2_allocated_addresses, ((long long) head)%(1<<12));\r\n#endif\r\n        this->head->init(this->KEY_MIN);\r\n        this->tail = this->head;\r\n//        oldTail = NULL;\r\n        // blocker = new ReportItem(NULL, ReportType::Add, -1)\r\n        this->blocker = recmgr->template allocate<ReportItem>(tid);\r\n#ifdef __HANDLE_STATS\r\n        GSTATS_APPEND(tid, extra_type3_allocated_addresses, ((long long) blocker)%(1<<12));\r\n#endif\r\n        this->blocker->init(NULL, ReportType::Add, -1);\r\n        this->active = true;\r\n        this->currLocations = new void * [NUM_THREADS*PREFETCH_SIZE_WORDS];\r\n        this->currRepLocations = new int[NUM_THREADS*PREFETCH_SIZE_WORDS];\r\n        this->gAllReports = NULL;\r\n        for (int i=0;i<NUM_THREADS;++i) {\r\n            this->reportHeads[i*PREFETCH_SIZE_WORDS] = recmgr->template allocate<ReportItem>(tid);\r\n#ifdef __HANDLE_STATS\r\n            GSTATS_APPEND(tid, extra_type3_allocated_addresses, ((long long) reportHeads[i*PREFETCH_SIZE_WORDS])%(1<<12));\r\n#endif\r\n            this->reportHeads[i*PREFETCH_SIZE_WORDS]->init(NULL, ReportType::Add, -1); // sentinel head.\r\n            this->reportTails[i*PREFETCH_SIZE_WORDS] = this->reportHeads[i*PREFETCH_SIZE_WORDS];\r\n            \r\n            this->currLocations[i*PREFETCH_SIZE_WORDS] = NULL;\r\n            this->currRepLocations[i*PREFETCH_SIZE_WORDS] = 0;\r\n        }\r\n    }\r\n    \r\n    ~SnapCollector() {\r\n        if (reportHeads) delete[] reportHeads;\r\n        if (reportTails) delete[] reportTails;\r\n        if (currLocations) delete[] currLocations;\r\n        if (currRepLocations) delete[] currRepLocations;\r\n        if (gAllReports) delete gAllReports;\r\n    }\r\n    \r\n    template <typename RecordManager>\r\n    void retire(const int tid, RecordManager * recmgr) {\r\n        // retire report items\r\n        for (int i=0;i<NUM_THREADS;++i) {\r\n            ReportItem * curr = reportHeads[i*PREFETCH_SIZE_WORDS];\r\n            while (curr != NULL) {\r\n                if (curr != blocker) recmgr->retire(tid, curr); // blocker can exist in many per-thread lists, but we only want to retire it once, below.\r\n                curr = curr->next;\r\n            }\r\n        }\r\n        // retire blocker\r\n        recmgr->retire(tid, blocker);\r\n        // if a thread has changed tail to point to a \"blocker,\" then\r\n        // threads may have appended node wrappers to the blocker,\r\n        // so we have to retire any such node wrappers\r\n        NodeWrapper * curr = this->tail;\r\n        if (isBlocker(curr)) {\r\n            while (curr != NULL) {\r\n                recmgr->retire(tid, curr);\r\n                curr = curr->next;\r\n            }\r\n        }\r\n        // retire node wrappers\r\n        curr = head;\r\n        while (curr != NULL) { // && curr != tail /*&& curr != oldTail*/) {\r\n            recmgr->retire(tid, curr);\r\n            curr = curr->next;\r\n        }\r\n        // retire the contents of gAllReports\r\n        __retireAllReports(tid, gAllReports, recmgr);\r\n        // retire snap collector\r\n        recmgr->retire(tid, this);\r\n    }\r\n    \r\n    // TIMNAT: Implemented according to the optimization in A.3:\r\n    // TIMNAT: Only accept nodes whose key is higher than the last, and return the last node. \r\n    template <typename RecordManager>\r\n    NodeType * AddNode(const int tid, NodeType * node, K key, RecordManager * recmgr) {\r\n        NodeWrapper * last = tail;\r\n        if (last->key >= key) // TIMNAT: trying to add an out of place node.\r\n            return last->node;\r\n\r\n        // advance tail pointer if needed\r\n        if (last->next != NULL) {\r\n            if (last == tail) __sync_bool_compare_and_swap(&tail, last, last->next);\r\n            return tail->node;\r\n        }\r\n        \r\n        NodeWrapper * newNode = recmgr->template allocate<NodeWrapper>(tid);\r\n#ifdef __HANDLE_STATS\r\n        GSTATS_APPEND(tid, extra_type2_allocated_addresses, ((long long) newNode)%(1<<12));\r\n#endif\r\n        newNode->init(node, key);\r\n        if (__sync_bool_compare_and_swap(&last->next, NULL, newNode)) {\r\n            __sync_bool_compare_and_swap(&tail, last, newNode);\r\n            return node;\r\n        } else {\r\n            recmgr->deallocate(tid, newNode);\r\n            return tail->node;\r\n        }\r\n    }\r\n    \r\n    template <typename RecordManager>\r\n    void Report(int tid, NodeType * Node, ReportType t, K key, RecordManager * recmgr) {\r\n        ReportItem * reportTail = reportTails[tid*PREFETCH_SIZE_WORDS];\r\n        ReportItem * newItem = recmgr->template allocate<ReportItem>(tid);\r\n#ifdef __HANDLE_STATS\r\n        GSTATS_APPEND(tid, extra_type3_allocated_addresses, ((long long) newItem)%(1<<12));\r\n#endif\r\n        newItem->init(Node, t, key);\r\n        if (__sync_bool_compare_and_swap(&reportTail->next, NULL, newItem)) {\r\n            reportTails[tid*PREFETCH_SIZE_WORDS] = newItem;\r\n        } else {\r\n            recmgr->deallocate(tid, newItem);\r\n        }\r\n    }\r\n    \r\n    bool IsActive() {\r\n//        __sync_synchronize();\r\n//        SOFTWARE_BARRIER;\r\n        bool result = active;\r\n//        SOFTWARE_BARRIER;\r\n        return result;\r\n    }\r\n    \r\n    template <typename RecordManager>\r\n    void BlockFurtherPointers(const int tid, RecordManager * recmgr) {\r\n        NodeWrapper * blocker = recmgr->template allocate<NodeWrapper>(tid);\r\n#ifdef __HANDLE_STATS\r\n        GSTATS_APPEND(tid, extra_type2_allocated_addresses, ((long long) blocker)%(1<<12));\r\n#endif\r\n        blocker->init(NULL, KEY_MAX);\r\n        \r\n#if 1\r\n        while (true) {\r\n            NodeWrapper * old = this->tail;\r\n            if (isBlocker(old)) { // old is a blocker, so no need to add our own blocker\r\n                recmgr->deallocate(tid, blocker);\r\n                return;\r\n            }\r\n            if (__sync_bool_compare_and_swap(&this->tail, old, blocker)) {\r\n                return;\r\n            }\r\n        }\r\n#else\r\n        tail = blocker;\r\n#endif\r\n    }\r\n    \r\n    /**\r\n     * note: the parameters are used for the timestamping mechanism of the\r\n     *       test harness. they are NOT inherently needed by the snap collector.\r\n     */\r\n    void Deactivate(pthread_rwlock_t * const rwlock, volatile long long * timestamp, long long * rq_lin_time) {\r\n#ifdef RQ_USE_TIMESTAMPS\r\n        if (pthread_rwlock_wrlock(rwlock)) error(\"could not write-lock rwlock\");\r\n        active = false; // range query is linearized here\r\n        *timestamp = *timestamp + 1;\r\n        *rq_lin_time = *timestamp; //++(*timestamp);\r\n        //std::cout<<\"timestamp=\"<<*timestamp<<std::endl;\r\n        if (pthread_rwlock_unlock(rwlock)) error(\"could not write-unlock rwlock\");\r\n#else\r\n        active = false; // range query is linearized here (no memory barrier needed, since we don't care about read/write re-ordering--just when this hits main memory)\r\n        //__sync_synchronize();\r\n#endif\r\n    }\r\n\r\n    void BlockFurtherReports() {\r\n        for (int i = 0; i<NUM_THREADS; i++) {\r\n            ReportItem * reportTail = reportTails[i*PREFETCH_SIZE_WORDS];\r\n            \r\n            // TODO: SAVE OLD TAILS, HERE!!!\r\n            \r\n            if (reportTail->next == NULL)\r\n                __sync_bool_compare_and_swap(&reportTail->next, NULL, blocker);\r\n            // assert cas succeeded OR reportTail->next == blocker\r\n        }\r\n    }\r\n\r\nprivate:\r\n    \r\n    // TIMNAT: What follows is functions that are used to work with the snapshot while it is\r\n    // TIMNAT: already taken. These functions are used to iterate over the nodes of the snapshot.\r\n\r\n    template <typename RecordManager>\r\n    void AddReports(const int tid, std::vector<CompactReportItem *> * allReports, ReportItem * curr, RecordManager * recmgr) {\r\n        curr = curr->next;\r\n        while (curr != NULL && curr != blocker) {\r\n            CompactReportItem * newItem = recmgr->template allocate<CompactReportItem>(tid);\r\n#ifdef __HANDLE_STATS\r\n            GSTATS_APPEND(tid, extra_type4_allocated_addresses, ((long long) newItem)%(1<<12));\r\n#endif\r\n            newItem->init(curr->node, curr->t, curr->key);\r\n            allReports->push_back(newItem);\r\n            curr = curr->next;\r\n        }\r\n    }\r\n\r\npublic:\r\n    // An optimization: sort the reports and nodes.\r\n    template <typename RecordManager>\r\n    void Prepare(int tid, RecordManager * recmgr) {\r\n        currLocations[tid*PREFETCH_SIZE_WORDS] = head;\r\n        currRepLocations[tid*PREFETCH_SIZE_WORDS] = 0;\r\n        if (gAllReports != NULL) return;\r\n\r\n        std::vector<CompactReportItem *> * allReports = new std::vector<CompactReportItem *>();\r\n        for (int i = 0; i < NUM_THREADS; i++) {\r\n            AddReports(tid, allReports, reportHeads[i*PREFETCH_SIZE_WORDS], recmgr);\r\n            if (gAllReports != NULL) {\r\n                // failed to publish allReports -- clean it up\r\n                __deallocateAllReports(tid, allReports, recmgr);\r\n                return;\r\n            }\r\n        }\r\n        assert(!active);\r\n#ifdef SNAPCOLLECTOR_PRINT_RQS\r\n        std::cout<<\"this=\"<<(long long) this<<\" allReports size=\"<<allReports->size()<<std::endl;\r\n#endif\r\n        std::sort(allReports->begin(), allReports->end(), compareCRI);\r\n        if (__sync_bool_compare_and_swap(&gAllReports, NULL, allReports)) {\r\n            // published allReports\r\n        } else {\r\n            // failed to publish allReports -- clean it up\r\n            __deallocateAllReports(tid, allReports, recmgr);\r\n        }\r\n    }\r\n    \r\n    NodeType * GetNext(int tid) {\r\n        NodeWrapper * currLoc = (NodeWrapper *) currLocations[tid*PREFETCH_SIZE_WORDS];\r\n        int currRepLoc = currRepLocations[tid*PREFETCH_SIZE_WORDS];\r\n        std::vector<CompactReportItem *> * allReports = gAllReports;\r\n\r\n        while (true) {\r\n            CompactReportItem * rep = NULL;\r\n            K repKey = KEY_MAX;\r\n            if (allReports->size() > currRepLoc) {\r\n                rep = (*allReports)[currRepLoc];\r\n                repKey = rep->key;\r\n            }\r\n            K nodeKey = KEY_MAX;\r\n            NodeWrapper * next = currLoc->next;\r\n            if (next != NULL) {\r\n                nodeKey = next->key;\r\n            }\r\n\r\n            // Option 1: node key < rep key. Return node.\r\n            if (nodeKey < repKey) {\r\n                currLocations[tid*PREFETCH_SIZE_WORDS] = next;\r\n                currRepLocations[tid*PREFETCH_SIZE_WORDS] = currRepLoc;\r\n                return next->node;\r\n            }\r\n\r\n            // Option 2: node key == rep key \r\n            if (nodeKey == repKey) {\r\n                // 2.a - both are infinity - iteration done.\r\n                if (nodeKey == KEY_MAX) {\r\n                    currLocations[tid*PREFETCH_SIZE_WORDS] = currLoc;\r\n                    currRepLocations[tid*PREFETCH_SIZE_WORDS] = currRepLoc;\r\n                    return NULL;\r\n                }\r\n                // node and report with the same key ::\r\n\r\n                // skip not-needed reports\r\n                while (currRepLoc + 1 < allReports->size()) {\r\n                    CompactReportItem * nextRep = (*allReports)[currRepLoc + 1];\r\n                    // dismiss a duplicate, or an insert followed by a matching delete:\r\n                    if (rep->key == nextRep->key && rep->node == nextRep->node) {\r\n                        currRepLoc++;\r\n                        rep = nextRep;\r\n                    } else {\r\n                        break;\r\n                    }\r\n                }\r\n                // standing on an insert report to a node I am holding:\r\n                // 1. Return the current node.\r\n                // 2. Skip over rest of reports for that key.\r\n                if (rep->t == ReportType::Add && (NodeType *) rep->node == next->node) {\r\n                    while (currRepLoc < allReports->size()\r\n                            && (*allReports)[currRepLoc]->key == rep->key) {\r\n                        currRepLoc++;\r\n                    }\r\n                    currRepLocations[tid*PREFETCH_SIZE_WORDS] = currRepLoc;\r\n                    currLocations[tid*PREFETCH_SIZE_WORDS] = next;\r\n                    return next->node;\r\n                }\r\n                // standing on an insert report to a different node than I hold:\r\n                // 1. Return the reported node.\r\n                // 2. Skip over rest of reports for that key.\r\n                if (rep->t == ReportType::Add && (NodeType *) rep->node != next->node) {\r\n                    NodeType * returnValue = (NodeType *) rep->node;\r\n                    while (currRepLoc < allReports->size()\r\n                            && (*allReports)[currRepLoc]->key == rep->key) {\r\n                        currRepLoc++;\r\n                    }\r\n                    currRepLocations[tid*PREFETCH_SIZE_WORDS] = currRepLoc;\r\n                    currLocations[tid*PREFETCH_SIZE_WORDS] = next;\r\n                    return returnValue;\r\n                }\r\n                // standing on a delete report to a different node than I hold:\r\n                // skip over it and continue the big loop.\r\n                if (rep->t == ReportType::Remove && (NodeType *) rep->node != next->node) {\r\n                    currRepLoc++;\r\n                    continue;\r\n                }\r\n                // standing on a delete report to the node that I hold:\r\n                // 1. advance over the node that I hold.\r\n                // 2. advance with the report.\r\n                // 3. continue the bigloop\r\n                currLoc = next;\r\n                currRepLoc++;\r\n                continue;\r\n            }\r\n\r\n            // Option 3: node key > rep key\r\n            if (nodeKey > repKey) {\r\n                // skip not-needed reports\r\n                while (currRepLoc + 1 < allReports->size()) {\r\n                    CompactReportItem * nextRep = (*allReports)[currRepLoc + 1];\r\n                    // dismiss a duplicate, or an insert followed by a matching delete:\r\n                    if (rep->key == nextRep->key && rep->node == nextRep->node) {\r\n                        currRepLoc++;\r\n                        rep = nextRep;\r\n                    } else {\r\n                        break;\r\n                    }\r\n                }\r\n                // a delete report - skip over it.\r\n                if (rep->t == ReportType::Remove) {\r\n                    currRepLoc++;\r\n                    continue;\r\n                }\r\n\r\n                // an insert report:\r\n                // 1. skip over rest of the reports for the same key.\r\n                // 2. return the node.\r\n                if (rep->t == ReportType::Add) {\r\n                    NodeType * returnValue = (NodeType *) rep->node;\r\n                    while (currRepLoc < allReports->size()\r\n                            && (*allReports)[currRepLoc]->key == rep->key) {\r\n                        currRepLoc++;\r\n                    }\r\n                    currRepLocations[tid*PREFETCH_SIZE_WORDS] = currRepLoc;\r\n                    currLocations[tid*PREFETCH_SIZE_WORDS] = currLoc;\r\n                    return returnValue;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n};\r\n\r\n#endif /* SNAPCOLLECTOR_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rq/snapcollector/snapcollector_test.cpp",
    "content": "/* \r\n * File:   test.cpp\r\n * Author: trbot\r\n *\r\n * Created on June 21, 2017, 5:25 PM\r\n */\r\n\r\n#include <iostream>\r\n#include <cstdlib>\r\n#include <cassert>\r\n#include \"snapcollector.h\"\r\n#include \"rq_snapcollector.h\"\r\n\r\nusing namespace std;\r\n\r\nclass Node {\r\npublic:\r\n    int key;\r\n    \r\n    volatile bool marked;\r\n    volatile long long itime;\r\n    volatile long long dtime;\r\n    \r\n    Node(int key) : key(key) {}\r\n};\r\n\r\nclass DataStructure {\r\npublic:\r\n    inline bool isLogicallyDeleted(const int tid, Node * node) {\r\n        return node->marked;\r\n    }\r\n    \r\n    inline int getKeys(const int tid, Node * node, int * const outputKeys) {\r\n        outputKeys[0] = node->key;\r\n        return 1;\r\n    }\r\n    \r\n    bool isInRange(const int& key, const int& lo, const int& hi) {\r\n        return lo <= key && key <= hi;\r\n    }\r\n};\r\n\r\n/*\r\n * \r\n */\r\nint main(int argc, char** argv) {\r\n    DataStructure ds;\r\n    Node node (17);\r\n    const int numProcessors = 1;\r\n    SnapCollector<Node> sc (numProcessors);\r\n    sc.AddNode(&node, node.key);\r\n    \r\n    RQProvider<int, Node, DataStructure, true, true> prov (numProcessors, &ds);\r\n    Node * inserted[] = {NULL};\r\n    Node * deleted[] = {NULL};\r\n    prov.linearize_update_at_cas(1, &node.key, 17, 18, inserted, deleted, (void *) NULL);\r\n    \r\n    return 0;\r\n}\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/common/rwlock.h",
    "content": "/* \r\n * File:   rwlock.h\r\n * Author: trbot\r\n *\r\n * Created on June 29, 2017, 8:25 PM\r\n */\r\n\r\n#ifndef RWLOCK_H\r\n#define RWLOCK_H\r\n\r\n#ifdef RWLOCK_PTHREADS\r\n#elif defined RWLOCK_FAVOR_WRITERS\r\n#elif defined RWLOCK_FAVOR_READERS\r\n#else\r\n//    #warning \"No RWLOCK implementation specified... using default: favour READERS. See rwlock.h for options. Note that this setting only affects algorithms that use the lock-based range query provider in common/rq/rq_rwlock.h.\"\r\n    #define RWLOCK_FAVOR_READERS\r\n//    #error Must specify RWLOCK implementation; see rwlock.h\r\n#endif\r\n\r\n#ifdef RWLOCK_PTHREADS\r\n\r\nclass RWLock {\r\nprivate:\r\n    pthread_rwlock_t lock;\r\n    \r\npublic:\r\n    RWLock() {\r\n        if (pthread_rwlock_init(&lock, NULL)) error(\"could not init rwlock\");\r\n    }\r\n    ~RWLock() {\r\n        if (pthread_rwlock_destroy(&lock)) error(\"could not destroy rwlock\");\r\n    }\r\n    inline void readLock() {\r\n        if (pthread_rwlock_rdlock(&lock)) error(\"could not read-lock rwlock\");\r\n    }\r\n    inline void readUnlock() {\r\n        if (pthread_rwlock_unlock(&lock)) error(\"could not read-unlock rwlock\");\r\n    }\r\n    inline void writeLock() {\r\n        if (pthread_rwlock_wrlock(&lock)) error(\"could not write-lock rwlock\");\r\n    }\r\n    inline void writeUnlock() {\r\n        if (pthread_rwlock_unlock(&lock)) error(\"could not write-unlock rwlock\");\r\n    }\r\n    inline bool isWriteLocked() {\r\n        cout<<\"ERROR: isWriteLocked() is not implemented\"<<endl;\r\n        exit(-1);\r\n    }\r\n    inline bool isReadLocked() {\r\n        cout<<\"ERROR: isReadLocked() is not implemented\"<<endl;\r\n        exit(-1);\r\n    }\r\n    inline bool isLocked() {\r\n        cout<<\"ERROR: isReadLocked() is not implemented\"<<endl;\r\n        exit(-1);\r\n    }\r\n};\r\n\r\n#elif defined RWLOCK_FAVOR_WRITERS\r\n\r\nclass RWLock {\r\nprivate:\r\n    volatile long long lock; // two bit fields: [ number of readers ] [ writer bit ]\r\n    \r\npublic:\r\n    RWLock() {\r\n        lock = 0;\r\n    }\r\n    inline bool isWriteLocked() {\r\n        return lock & 1;\r\n    }\r\n    inline bool isReadLocked() {\r\n        return lock & ~1;\r\n    }\r\n    inline bool isLocked() {\r\n        return lock;\r\n    }\r\n    inline void readLock() {\r\n        while (1) {\r\n            while (isLocked()) {}\r\n            if ((__sync_add_and_fetch(&lock, 2) & 1) == 0) return; // when we tentatively read-locked, there was no writer\r\n            __sync_add_and_fetch(&lock, -2); // release our tentative read-lock\r\n        }\r\n    }\r\n    inline void readUnlock() {\r\n        __sync_add_and_fetch(&lock, -2);\r\n    }\r\n    inline void writeLock() {\r\n        while (1) {\r\n            long long v = lock;\r\n            if (__sync_bool_compare_and_swap(&lock, v & ~1, v | 1)) {\r\n                while (v & ~1) { // while there are still readers\r\n                    v = lock;\r\n                }\r\n                return;\r\n            }\r\n        }\r\n    }\r\n    inline void writeUnlock() {\r\n        __sync_add_and_fetch(&lock, -1);\r\n    }\r\n};\r\n\r\n#elif defined RWLOCK_FAVOR_READERS\r\n\r\nclass RWLock {\r\nprivate:\r\n    volatile long long lock; // two bit fields: [ number of readers ] [ writer bit ]\r\n    \r\npublic:\r\n    RWLock() {\r\n        lock = 0;\r\n    }\r\n    inline bool isWriteLocked() {\r\n        return lock & 1;\r\n    }\r\n    inline bool isReadLocked() {\r\n        return lock & ~1;\r\n    }\r\n    inline bool isLocked() {\r\n        return lock;\r\n    }\r\n    inline void readLock() {\r\n        while (1) {\r\n            __sync_add_and_fetch(&lock, 2);\r\n            while (isWriteLocked());\r\n            return;\r\n        }\r\n    }\r\n    inline void readUnlock() {\r\n        __sync_add_and_fetch(&lock, -2);\r\n    }\r\n    inline void writeLock() {\r\n        while (1) {\r\n            while (isLocked()) {}\r\n            if (__sync_bool_compare_and_swap(&lock, 0, 1)) {\r\n                return;\r\n            }\r\n        }\r\n    }\r\n    inline void writeUnlock() {\r\n        __sync_add_and_fetch(&lock, -1);\r\n    }\r\n};\r\n\r\n#endif\r\n\r\n#endif /* RWLOCK_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/ds/brown_ext_abtree_lf/brown_ext_abtree_lf.h",
    "content": "/**\r\n * Implementation of the dictionary ADT with a lock-free relaxed (a,b)-tree.\r\n * Copyright (C) 2016 Trevor Brown\r\n * Contact (me [at] tbrown [dot] pro) with questions or comments.\r\n *\r\n * Details of the algorithm appear in Trevor's thesis:\r\n *    Techniques for Constructing Efficient Lock-free Data Structures. 2017.\r\n * \r\n * The paper leaves it up to the implementer to decide when and how to perform\r\n * rebalancing steps. In this implementation, we keep track of violations and\r\n * fix them using a recursive cleanup procedure, which is designed as follows.\r\n * After performing a rebalancing step that replaced a set R of nodes,\r\n * recursive invocations are made for every violation that appears at a newly\r\n * created node. Thus, any violations that were present at nodes in R are either\r\n * eliminated by the rebalancing step, or will be fixed by recursive calls.\r\n * This way, if an invocation I of this cleanup procedure is trying to fix a\r\n * violation at a node that has been replaced by another invocation I' of\r\n * cleanup, then I can hand off responsibility for fixing the violation to I'.\r\n * Designing the rebalancing procedure to allow responsibility to be handed\r\n * off in this manner is not difficult; it simply requires going through each\r\n * rebalancing step S and determining which nodes involved in S can have\r\n * violations after S (and then making a recursive call for each violation).\r\n * \r\n * -----------------------------------------------------------------------------\r\n *\r\n * This program is free software: you can redistribute it and/or modify\r\n * it under the terms of the GNU General Public License as published by\r\n * the Free Software Foundation, either version 3 of the License, or\r\n * (at your option) any later version.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n * GNU General Public License for more details.\r\n *\r\n * You should have received a copy of the GNU General Public License\r\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n */\r\n\r\n#ifndef ABTREE_H\r\n#define\tABTREE_H\r\n\r\n#include <string>\r\n#include <cstring>\r\n#include <fstream>\r\n#include <iostream>\r\n#include <sstream>\r\n#include <set>\r\n#include <unistd.h>\r\n#include <sys/types.h>\r\n#include \"record_manager.h\"\r\n#include \"descriptors.h\"\r\n#include \"rq_provider.h\"\r\n\r\nnamespace abtree_ns {\r\n\r\n    #ifndef TRACE\r\n    #define TRACE if(0)\r\n    #endif\r\n    #ifndef DEBUG\r\n    #define DEBUG if(0)\r\n    #endif\r\n    #ifndef DEBUG1\r\n    #define DEBUG1 if(0)\r\n    #endif\r\n    #ifndef DEBUG2\r\n    #define DEBUG2 if(0)\r\n    #endif\r\n\r\n    #define ABTREE_ENABLE_DESTRUCTOR\r\n\r\n    using namespace std;\r\n    \r\n    template <int DEGREE, typename K>\r\n    struct Node;\r\n    \r\n    template <int DEGREE, typename K>\r\n    struct SCXRecord;\r\n    \r\n    template <int DEGREE, typename K>\r\n    class wrapper_info {\r\n    public:\r\n        const static int MAX_NODES = DEGREE+2;\r\n        Node<DEGREE,K> * nodes[MAX_NODES];\r\n        SCXRecord<DEGREE,K> * scxPtrs[MAX_NODES];\r\n        Node<DEGREE,K> * newNode;\r\n        Node<DEGREE,K> * volatile * field;\r\n        int state;\r\n        char numberOfNodes;\r\n        char numberOfNodesToFreeze;\r\n        char numberOfNodesAllocated;\r\n\r\n        // for rqProvider\r\n        Node<DEGREE,K> * insertedNodes[MAX_NODES+1];\r\n        Node<DEGREE,K> * deletedNodes[MAX_NODES+1];\r\n    };\r\n\r\n    template <int DEGREE, typename K>\r\n    struct SCXRecord {\r\n        const static int STATE_INPROGRESS = 0;\r\n        const static int STATE_COMMITTED = 1;\r\n        const static int STATE_ABORTED = 2;\r\n        union {\r\n            struct {\r\n                volatile mutables_t mutables;\r\n\r\n                int numberOfNodes;\r\n                int numberOfNodesToFreeze;\r\n\r\n                Node<DEGREE,K> * newNode;\r\n                Node<DEGREE,K> * volatile * field;\r\n                Node<DEGREE,K> * nodes[wrapper_info<DEGREE,K>::MAX_NODES];            // array of pointers to nodes\r\n                SCXRecord<DEGREE,K> * scxPtrsSeen[wrapper_info<DEGREE,K>::MAX_NODES]; // array of pointers to scx records\r\n\r\n                // for rqProvider\r\n                Node<DEGREE,K> * insertedNodes[wrapper_info<DEGREE,K>::MAX_NODES+1];\r\n                Node<DEGREE,K> * deletedNodes[wrapper_info<DEGREE,K>::MAX_NODES+1];\r\n            } __attribute__((packed)) c; // WARNING: be careful with atomicity because of packed attribute!!! (this means no atomic vars smaller than word size, and all atomic vars must start on a word boundary when fields are packed tightly)\r\n            char bytes[2*PREFETCH_SIZE_BYTES];\r\n        };\r\n        const static int size = sizeof(c);\r\n    };\r\n        \r\n    template <int DEGREE, typename K>\r\n    struct Node {\r\n        SCXRecord<DEGREE,K> * volatile scxPtr;\r\n        int leaf; // 0 or 1\r\n        volatile int marked; // 0 or 1\r\n        int weight; // 0 or 1\r\n        int size; // degree of node\r\n        K searchKey;\r\n#if defined(RQ_LOCKFREE) || defined(RQ_RWLOCK) || defined(HTM_RQ_RWLOCK)\r\n        volatile long long itime; // for use by range query algorithm\r\n        volatile long long dtime; // for use by range query algorithm\r\n#endif\r\n        K keys[DEGREE];\r\n        Node<DEGREE,K> * volatile ptrs[DEGREE];\r\n\r\n        inline bool isLeaf() {\r\n            return leaf;\r\n        }\r\n        inline int getKeyCount() {\r\n            return isLeaf() ? size : size-1;\r\n        }\r\n        inline int getABDegree() {\r\n            return size;\r\n        }\r\n        template <class Compare>\r\n        inline int getChildIndex(const K& key, Compare cmp) {\r\n            int nkeys = getKeyCount();\r\n            int retval = 0;\r\n            while (retval < nkeys && !cmp(key, (const K&) keys[retval])) {\r\n                ++retval;\r\n            }\r\n            return retval;\r\n        }\r\n        template <class Compare>\r\n        inline int getKeyIndex(const K& key, Compare cmp) {\r\n            int nkeys = getKeyCount();\r\n            int retval = 0;\r\n            while (retval < nkeys && cmp((const K&) keys[retval], key)) {\r\n                ++retval;\r\n            }\r\n            return retval;\r\n        }\r\n    };\r\n\r\n    template <int DEGREE, typename K, class Compare, class RecManager>\r\n    class abtree {\r\n\r\n        // the following bool determines whether the optimization to guarantee\r\n        // amortized constant rebalancing (at the cost of decreasing average degree\r\n        // by at most one) is used.\r\n        // if it is false, then an amortized logarithmic number of rebalancing steps\r\n        // may be performed per operation, but average degree increases slightly.\r\n        char padding0[PREFETCH_SIZE_BYTES];\r\n        const bool ALLOW_ONE_EXTRA_SLACK_PER_NODE;\r\n\r\n        const int b;\r\n        const int a;\r\n\r\n        RecManager * const recordmgr;\r\n        RQProvider<K, void *, Node<DEGREE,K>, abtree<DEGREE,K,Compare,RecManager>, RecManager, false, false> * const rqProvider;\r\n        char padding1[PREFETCH_SIZE_BYTES];\r\n        Compare cmp;\r\n\r\n        // descriptor reduction algorithm\r\n        #ifndef comma\r\n            #define comma ,\r\n        #endif\r\n        #define DESC1_ARRAY records\r\n        #define DESC1_T SCXRecord<DEGREE comma K>\r\n        #define MUTABLES1_OFFSET_ALLFROZEN 0\r\n        #define MUTABLES1_OFFSET_STATE 1\r\n        #define MUTABLES1_MASK_ALLFROZEN 0x1\r\n        #define MUTABLES1_MASK_STATE 0x6\r\n        #define MUTABLES1_NEW(mutables) \\\r\n            ((((mutables)&MASK1_SEQ)+(1<<OFFSET1_SEQ)) \\\r\n            | (SCXRecord<DEGREE comma K>::STATE_INPROGRESS<<MUTABLES1_OFFSET_STATE))\r\n        #define MUTABLES1_INIT_DUMMY SCXRecord<DEGREE comma K>::STATE_COMMITTED<<MUTABLES1_OFFSET_STATE | MUTABLES1_MASK_ALLFROZEN<<MUTABLES1_OFFSET_ALLFROZEN\r\n        #include \"../descriptors/descriptors_impl.h\"\r\n        char __padding_desc[PREFETCH_SIZE_BYTES];\r\n        DESC1_T DESC1_ARRAY[LAST_TID1+1] __attribute__ ((aligned(64)));\r\n\r\n        char padding2[PREFETCH_SIZE_BYTES];\r\n        Node<DEGREE,K> * entry;\r\n        char padding3[PREFETCH_SIZE_BYTES];\r\n\r\n        #define DUMMY       ((SCXRecord<DEGREE,K>*) (void*) TAGPTR1_STATIC_DESC(0))\r\n        #define FINALIZED   ((SCXRecord<DEGREE,K>*) (void*) TAGPTR1_DUMMY_DESC(1))\r\n        #define FAILED      ((SCXRecord<DEGREE,K>*) (void*) TAGPTR1_DUMMY_DESC(2))\r\n\r\n        #define arraycopy(src, srcStart, dest, destStart, len) \\\r\n            for (int ___i=0;___i<(len);++___i) { \\\r\n                (dest)[(destStart)+___i] = (src)[(srcStart)+___i]; \\\r\n            }\r\n        #define arraycopy_ptrs(src, srcStart, dest, destStart, len) \\\r\n            for (int ___i=0;___i<(len);++___i) { \\\r\n                rqProvider->write_addr(tid, &(dest)[(destStart)+___i], \\\r\n                        rqProvider->read_addr(tid, &(src)[(srcStart)+___i])); \\\r\n            }\r\n\r\n    private:\r\n        void* doInsert(const int tid, const K& key, void * const value, const bool replace);\r\n\r\n        // returns true if the invocation of this method\r\n        // (and not another invocation of a method performed by this method)\r\n        // performed an scx, and false otherwise\r\n        bool fixWeightViolation(const int tid, Node<DEGREE,K>* viol);\r\n\r\n        // returns true if the invocation of this method\r\n        // (and not another invocation of a method performed by this method)\r\n        // performed an scx, and false otherwise\r\n        bool fixDegreeViolation(const int tid, Node<DEGREE,K>* viol);\r\n\r\n        bool llx(const int tid, Node<DEGREE,K>* r, Node<DEGREE,K> ** snapshot, const int i, SCXRecord<DEGREE,K> ** ops, Node<DEGREE,K> ** nodes);\r\n        SCXRecord<DEGREE,K>* llx(const int tid, Node<DEGREE,K>* r, Node<DEGREE,K> ** snapshot);\r\n        bool scx(const int tid, wrapper_info<DEGREE,K> * info);\r\n        void helpOther(const int tid, tagptr_t tagptr);\r\n        int help(const int tid, const tagptr_t tagptr, SCXRecord<DEGREE,K> const * const snap, const bool helpingOther);\r\n\r\n        SCXRecord<DEGREE,K>* createSCXRecord(const int tid, wrapper_info<DEGREE,K> * info);\r\n        Node<DEGREE,K>* allocateNode(const int tid);\r\n\r\n        void freeSubtree(Node<DEGREE,K>* node, int* nodes) {\r\n            const int tid = 0;\r\n            if (node == NULL) return;\r\n            if (!node->isLeaf()) {\r\n                for (int i=0;i<node->getABDegree();++i) {\r\n                    freeSubtree(node->ptrs[i], nodes);\r\n                }\r\n            }\r\n            ++(*nodes);\r\n            recordmgr->retire(tid, node);\r\n        }\r\n\r\n        int init[MAX_TID_POW2] = {0,};\r\npublic:\r\n        void * const NO_VALUE;\r\n        const int NUM_PROCESSES;\r\n    #ifdef USE_DEBUGCOUNTERS\r\n        debugCounters * const counters; // debug info\r\n    #endif\r\n\r\n        /**\r\n         * This function must be called once by each thread that will\r\n         * invoke any functions on this class.\r\n         * \r\n         * It must be okay that we do this with the main thread and later with another thread!\r\n         */\r\n        void initThread(const int tid) {\r\n            if (init[tid]) return; else init[tid] = !init[tid];\r\n            \r\n            recordmgr->initThread(tid);\r\n            rqProvider->initThread(tid);\r\n        }\r\n        void deinitThread(const int tid) {\r\n            if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n            rqProvider->deinitThread(tid);\r\n            recordmgr->deinitThread(tid);\r\n        }\r\n\r\n        /**\r\n         * Creates a new relaxed (a,b)-tree wherein: <br>\r\n         *      each internal node has up to <code>DEGREE</code> child pointers, and <br>\r\n         *      each leaf has up to <code>DEGREE</code> key/value pairs, and <br>\r\n         *      keys are ordered according to the provided comparator.\r\n         */\r\n        abtree(const int numProcesses, \r\n                const K anyKey,\r\n                int suspectedCrashSignal = SIGQUIT)\r\n        : ALLOW_ONE_EXTRA_SLACK_PER_NODE(true)\r\n        , b(DEGREE)\r\n        , a(DEGREE/2 - 2)\r\n        , recordmgr(new RecManager(numProcesses, suspectedCrashSignal))\r\n        , rqProvider(new RQProvider<K, void *, Node<DEGREE,K>, abtree<DEGREE,K,Compare,RecManager>, RecManager, false, false>(numProcesses, this, recordmgr))\r\n        , NO_VALUE((void *) -1LL)\r\n        , NUM_PROCESSES(numProcesses) \r\n        {\r\n            cmp = Compare();\r\n            \r\n            const int tid = 0;\r\n            initThread(tid);\r\n\r\n            recordmgr->enterQuiescentState(tid);\r\n            \r\n            DESC1_INIT_ALL(numProcesses);\r\n\r\n            SCXRecord<DEGREE,K> *dummy = TAGPTR1_UNPACK_PTR(DUMMY);\r\n            dummy->c.mutables = MUTABLES1_INIT_DUMMY;\r\n            TRACE COUTATOMICTID(\"DUMMY mutables=\"<<dummy->c.mutables<<endl);\r\n\r\n            // initial tree: entry is a sentinel node (with one pointer and no keys)\r\n            //               that points to an empty node (no pointers and no keys)\r\n            Node<DEGREE,K>* _entryLeft = allocateNode(tid);\r\n            _entryLeft->scxPtr = DUMMY;\r\n            _entryLeft->leaf = true;\r\n            _entryLeft->marked = false;\r\n            _entryLeft->weight = true;\r\n            _entryLeft->size = 0;\r\n            _entryLeft->searchKey = anyKey;\r\n\r\n            Node<DEGREE,K>* _entry = allocateNode(tid);\r\n            _entry = allocateNode(tid);\r\n            _entry->scxPtr = DUMMY;\r\n            _entry->leaf = false;\r\n            _entry->marked = false;\r\n            _entry->weight = true;\r\n            _entry->size = 1;\r\n            _entry->searchKey = anyKey;\r\n            _entry->ptrs[0] = _entryLeft;\r\n            \r\n            // need to simulate real insertion of root and the root's child,\r\n            // since range queries will actually try to add these nodes,\r\n            // and we don't want blocking rq providers to spin forever\r\n            // waiting for their itimes to be set to a positive number.\r\n            Node<DEGREE,K>* insertedNodes[] = {_entry, _entryLeft, NULL};\r\n            Node<DEGREE,K>* deletedNodes[] = {NULL};\r\n            rqProvider->linearize_update_at_write(tid, &entry, _entry, insertedNodes, deletedNodes);\r\n        }\r\n\r\n    #ifdef ABTREE_ENABLE_DESTRUCTOR    \r\n        ~abtree() {\r\n            int nodes = 0;\r\n            freeSubtree(entry, &nodes);\r\n//            COUTATOMIC(\"main thread: deleted tree containing \"<<nodes<<\" nodes\"<<endl);\r\n            delete rqProvider;\r\n//            recordmgr->printStatus();\r\n            delete recordmgr;\r\n        }\r\n    #endif\r\n\r\n        Node<DEGREE,K> * debug_getEntryPoint() { return entry; }\r\n\r\n    private:\r\n        /*******************************************************************\r\n         * Utility functions for integration with the test harness\r\n         *******************************************************************/\r\n\r\n        int sequentialSize(Node<DEGREE,K>* node) {\r\n            if (node->isLeaf()) {\r\n                return node->getKeyCount();\r\n            }\r\n            int retval = 0;\r\n            for (int i=0;i<node->getABDegree();++i) {\r\n                Node<DEGREE,K>* child = node->ptrs[i];\r\n                retval += sequentialSize(child);\r\n            }\r\n            return retval;\r\n        }\r\n        int sequentialSize() {\r\n            return sequentialSize(entry->ptrs[0]);\r\n        }\r\n\r\n        int getNumberOfLeaves(Node<DEGREE,K>* node) {\r\n            if (node == NULL) return 0;\r\n            if (node->isLeaf()) return 1;\r\n            int result = 0;\r\n            for (int i=0;i<node->getABDegree();++i) {\r\n                result += getNumberOfLeaves(node->ptrs[i]);\r\n            }\r\n            return result;\r\n        }\r\n        const int getNumberOfLeaves() {\r\n            return getNumberOfLeaves(entry->ptrs[0]);\r\n        }\r\n        int getNumberOfInternals(Node<DEGREE,K>* node) {\r\n            if (node == NULL) return 0;\r\n            if (node->isLeaf()) return 0;\r\n            int result = 1;\r\n            for (int i=0;i<node->getABDegree();++i) {\r\n                result += getNumberOfInternals(node->ptrs[i]);\r\n            }\r\n            return result;\r\n        }\r\n        const int getNumberOfInternals() {\r\n            return getNumberOfInternals(entry->ptrs[0]);\r\n        }\r\n        const int getNumberOfNodes() {\r\n            return getNumberOfLeaves() + getNumberOfInternals();\r\n        }\r\n\r\n        int getSumOfKeyDepths(Node<DEGREE,K>* node, int depth) {\r\n            if (node == NULL) return 0;\r\n            if (node->isLeaf()) return depth * node->getKeyCount();\r\n            int result = 0;\r\n            for (int i=0;i<node->getABDegree();i++) {\r\n                result += getSumOfKeyDepths(node->ptrs[i], 1+depth);\r\n            }\r\n            return result;\r\n        }\r\n        const int getSumOfKeyDepths() {\r\n            return getSumOfKeyDepths(entry->ptrs[0], 0);\r\n        }\r\n        const double getAverageKeyDepth() {\r\n            long sz = sequentialSize();\r\n            return (sz == 0) ? 0 : getSumOfKeyDepths() / sz;\r\n        }\r\n\r\n        int getHeight(Node<DEGREE,K>* node, int depth) {\r\n            if (node == NULL) return 0;\r\n            if (node->isLeaf()) return 0;\r\n            int result = 0;\r\n            for (int i=0;i<node->getABDegree();i++) {\r\n                int retval = getHeight(node->ptrs[i], 1+depth);\r\n                if (retval > result) result = retval;\r\n            }\r\n            return result+1;\r\n        }\r\n        const int getHeight() {\r\n            return getHeight(entry->ptrs[0], 0);\r\n        }\r\n\r\n        int getKeyCount(Node<DEGREE,K>* entry) {\r\n            if (entry == NULL) return 0;\r\n            if (entry->isLeaf()) return entry->getKeyCount();\r\n            int sum = 0;\r\n            for (int i=0;i<entry->getABDegree();++i) {\r\n                sum += getKeyCount(entry->ptrs[i]);\r\n            }\r\n            return sum;\r\n        }\r\n        int getTotalDegree(Node<DEGREE,K>* entry) {\r\n            if (entry == NULL) return 0;\r\n            int sum = entry->getKeyCount();\r\n            if (entry->isLeaf()) return sum;\r\n            for (int i=0;i<entry->getABDegree();++i) {\r\n                sum += getTotalDegree(entry->ptrs[i]);\r\n            }\r\n            return 1+sum; // one more children than keys\r\n        }\r\n        int getNodeCount(Node<DEGREE,K>* entry) {\r\n            if (entry == NULL) return 0;\r\n            if (entry->isLeaf()) return 1;\r\n            int sum = 1;\r\n            for (int i=0;i<entry->getABDegree();++i) {\r\n                sum += getNodeCount(entry->ptrs[i]);\r\n            }\r\n            return sum;\r\n        }\r\n        double getAverageDegree() {\r\n            return getTotalDegree(entry) / (double) getNodeCount(entry);\r\n        }\r\n        double getSpacePerKey() {\r\n            return getNodeCount(entry)*2*b / (double) getKeyCount(entry);\r\n        }\r\n\r\n        long long getSumOfKeys(Node<DEGREE,K>* node) {\r\n            TRACE COUTATOMIC(\"  getSumOfKeys(\"<<node<<\"): isLeaf=\"<<node->isLeaf()<<endl);\r\n            long long sum = 0;\r\n            if (node->isLeaf()) {\r\n                TRACE COUTATOMIC(\"      leaf sum +=\");\r\n                for (int i=0;i<node->getKeyCount();++i) {\r\n                    sum += (long long) node->keys[i];\r\n                    TRACE COUTATOMIC(node->keys[i]);\r\n                }\r\n                TRACE COUTATOMIC(endl);\r\n            } else {\r\n                for (int i=0;i<node->getABDegree();++i) {\r\n                    sum += getSumOfKeys(node->ptrs[i]);\r\n                }\r\n            }\r\n            TRACE COUTATOMIC(\"  getSumOfKeys(\"<<node<<\"): sum=\"<<sum<<endl);\r\n            return sum;\r\n        }\r\n        long long getSumOfKeys() {\r\n            TRACE COUTATOMIC(\"getSumOfKeys()\"<<endl);\r\n            return getSumOfKeys(entry);\r\n        }\r\n\r\n        void abtree_error(string s) {\r\n            cerr<<\"ERROR: \"<<s<<endl;\r\n            exit(-1);\r\n        }\r\n\r\n        void debugPrint() {\r\n            cout<<\"averageDegree=\"<<getAverageDegree()<<endl;\r\n            cout<<\"averageDepth=\"<<getAverageKeyDepth()<<endl;\r\n            cout<<\"height=\"<<getHeight()<<endl;\r\n            cout<<\"internalNodes=\"<<getNumberOfInternals()<<endl;\r\n            cout<<\"leafNodes=\"<<getNumberOfLeaves()<<endl;\r\n        }\r\n\r\n    public:\r\n        void * const insert(const int tid, const K& key, void * const val) {\r\n            return doInsert(tid, key, val, true);\r\n        }\r\n        void * const insertIfAbsent(const int tid, const K& key, void * const val) {\r\n            return doInsert(tid, key, val, false);\r\n        }\r\n        const pair<void*,bool> erase(const int tid, const K& key);\r\n        const pair<void*,bool> find(const int tid, const K& key);\r\n        bool contains(const int tid, const K& key);\r\n        int rangeQuery(const int tid, const K& low, const K& hi, K * const resultKeys, void ** const resultValues);\r\n        bool validate(const long long keysum, const bool checkkeysum) {\r\n            if (checkkeysum) {\r\n                long long treekeysum = getSumOfKeys();\r\n                if (treekeysum != keysum) {\r\n                    cerr<<\"ERROR: tree keysum \"<<treekeysum<<\" did not match thread keysum \"<<keysum<<endl;\r\n                    return false;\r\n                }\r\n            }\r\n            return true;\r\n        }\r\n\r\n        /**\r\n         * BEGIN FUNCTIONS FOR RANGE QUERY SUPPORT\r\n         */\r\n\r\n        inline bool isLogicallyDeleted(const int tid, Node<DEGREE,K> * node) {\r\n            return false;\r\n        }\r\n\r\n        inline int getKeys(const int tid, Node<DEGREE,K> * node, K * const outputKeys, void ** const outputValues) {\r\n            if (node->isLeaf()) {\r\n                // leaf ==> its keys are in the set.\r\n                const int sz = node->getKeyCount();\r\n                for (int i=0;i<sz;++i) {\r\n                    outputKeys[i] = node->keys[i];\r\n                    outputValues[i] = (void *) node->ptrs[i];\r\n                }\r\n                return sz;\r\n            }\r\n            // note: internal ==> its keys are NOT in the set\r\n            return 0;\r\n        }\r\n\r\n        bool isInRange(const K& key, const K& lo, const K& hi) {\r\n            return (!cmp(key, lo) && !cmp(hi, key));\r\n        }\r\n\r\n        /**\r\n         * END FUNCTIONS FOR RANGE QUERY SUPPORT\r\n         */\r\n\r\n        long long getSizeInNodes() {\r\n            return getNumberOfNodes();\r\n        }\r\n        string getSizeString() {\r\n            stringstream ss;\r\n            int preallocated = wrapper_info<DEGREE,K>::MAX_NODES * recordmgr->NUM_PROCESSES;\r\n            ss<<getSizeInNodes()<<\" nodes in tree\";\r\n            return ss.str();\r\n        }\r\n        long long getSize(Node<DEGREE,K> * node) {\r\n            return sequentialSize(node);\r\n        }\r\n        long long getSize() {\r\n            return sequentialSize();\r\n        }\r\n        RecManager * const debugGetRecMgr() {\r\n            return recordmgr;\r\n        }\r\n        long long debugKeySum() {\r\n            return getSumOfKeys();\r\n        }\r\n    };\r\n} // namespace\r\n\r\n#endif\t/* ABTREE_H */\r\n\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/ds/brown_ext_abtree_lf/brown_ext_abtree_lf_adapter.h",
    "content": "/* \r\n * File:   bst_adapter.h\r\n * Author: trbot\r\n *\r\n * Created on August 31, 2017, 6:53 PM\r\n */\r\n\r\n#ifndef BST_ADAPTER_H\r\n#define BST_ADAPTER_H\r\n\r\n#include <iostream>\r\n#include \"brown_ext_abtree_lf_impl.h\"\r\n#include \"errors.h\"\r\nusing namespace abtree_ns;\r\n\r\n#define RECORD_MANAGER_T record_manager<Reclaim, Alloc, Pool, Node<DEGREE, K>>\r\n#define DATA_STRUCTURE_T abtree<DEGREE, K, std::less<K>, RECORD_MANAGER_T>\r\n\r\ntemplate <int DEGREE, typename K, class Reclaim = reclaimer_debra<K>, class Alloc = allocator_new<K>, class Pool = pool_none<K>>\r\nclass ds_adapter {\r\nprivate:\r\n    const void * NO_VALUE;\r\n    DATA_STRUCTURE_T * const ds;\r\n\r\npublic:\r\n    ds_adapter(const int numThreads, const K ANY_KEY)\r\n    : ds(new DATA_STRUCTURE_T(numThreads, ANY_KEY))\r\n    {}\r\n    ~ds_adapter() {\r\n        delete ds;\r\n    }\r\n    \r\n    void * getNoValue() {\r\n        return ds->NO_VALUE;\r\n    }\r\n    \r\n    void initThread(const int tid) {\r\n        ds->initThread(tid);\r\n    }\r\n    void deinitThread(const int tid) {\r\n        ds->deinitThread(tid);\r\n    }\r\n\r\n    bool contains(const int tid, const K& key) {\r\n        return ds->contains(tid, key);\r\n    }\r\n    void * const insert(const int tid, const K& key, void * const val) {\r\n        return ds->insert(tid, key, val);\r\n    }\r\n    void * const insertIfAbsent(const int tid, const K& key, void * const val) {\r\n        return ds->insertIfAbsent(tid, key, val);\r\n    }\r\n    void * const erase(const int tid, const K& key) {\r\n        return ds->erase(tid, key).first;\r\n    }\r\n    void * find(const int tid, const K& key) {\r\n        return ds->find(tid, key).first;\r\n    }\r\n    int rangeQuery(const int tid, const K& lo, const K& hi, K * const resultKeys, void ** const resultValues) {\r\n        return ds->rangeQuery(tid, lo, hi, resultKeys, resultValues);\r\n    }\r\n    /**\r\n     * Sequential operation to get the number of keys in the set\r\n     */\r\n    int getSize() {\r\n        return ds->getSize();\r\n    }\r\n    void printSummary() {\r\n        stringstream ss;\r\n        ss<<ds->getSizeInNodes()<<\" nodes in tree\";\r\n        cout<<ss.str()<<endl;\r\n        \r\n        auto recmgr = ds->debugGetRecMgr();\r\n        recmgr->printStatus();\r\n    }\r\n    long long getKeyChecksum() {\r\n        return ds->debugKeySum();\r\n    }\r\n    bool validateStructure() {\r\n        return true;\r\n    }\r\n    void printObjectSizes() {\r\n        std::cout<<\"sizes: node=\"\r\n                 <<(sizeof(Node<DEGREE, K>))\r\n                 <<\" descriptor=\"<<(sizeof(SCXRecord<DEGREE, K>))<<\" (statically allocated)\"\r\n                 <<std::endl;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/ds/brown_ext_abtree_lf/brown_ext_abtree_lf_impl.h",
    "content": "/**\r\n * Implementation of the dictionary ADT with a lock-free relaxed (a,b)-tree.\r\n * Copyright (C) 2016 Trevor Brown\r\n * Contact (me [at] tbrown [dot] pro) with questions or comments.\r\n *\r\n * Details of the algorithm appear in Trevor's thesis:\r\n *    Techniques for Constructing Efficient Lock-free Data Structures. 2017.\r\n * \r\n * The paper leaves it up to the implementer to decide when and how to perform\r\n * rebalancing steps. In this implementation, we keep track of violations and\r\n * fix them using a recursive cleanup procedure, which is designed as follows.\r\n * After performing a rebalancing step that replaced a set R of nodes,\r\n * recursive invocations are made for every violation that appears at a newly\r\n * created node. Thus, any violations that were present at nodes in R are either\r\n * eliminated by the rebalancing step, or will be fixed by recursive calls.\r\n * This way, if an invocation I of this cleanup procedure is trying to fix a\r\n * violation at a node that has been replaced by another invocation I' of\r\n * cleanup, then I can hand off responsibility for fixing the violation to I'.\r\n * Designing the rebalancing procedure to allow responsibility to be handed\r\n * off in this manner is not difficult; it simply requires going through each\r\n * rebalancing step S and determining which nodes involved in S can have\r\n * violations after S (and then making a recursive call for each violation).\r\n * \r\n * -----------------------------------------------------------------------------\r\n *\r\n * This program is free software: you can redistribute it and/or modify\r\n * it under the terms of the GNU General Public License as published by\r\n * the Free Software Foundation, either version 3 of the License, or\r\n * (at your option) any later version.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n * GNU General Public License for more details.\r\n *\r\n * You should have received a copy of the GNU General Public License\r\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n */\r\n\r\n/**\r\n * Implementation note:\r\n * The ptrs arrays of internal nodes may be modified by calls to\r\n * rqProvider->linearize_update_at_cas or ->linearize_update_at_write.\r\n * Consequently, we must access access entries in the ptrs arrays of INTERNAL\r\n * nodes by performing calls to read_addr and write_addr (and linearize_...).\r\n * \r\n * However, the ptrs arrays of leaves represent fundamentally different data:\r\n * specifically values, or pointers to values, and NOT pointers to nodes.\r\n * Thus, the ptrs arrays of leaves CANNOT be modified by such calls.\r\n * So, we do NOT use these functions to access entries in leaves' ptrs arrays.\r\n */\r\n\r\n#ifndef ABTREE_IMPL_H\r\n#define\tABTREE_IMPL_H\r\n\r\n#include \"brown_ext_abtree_lf.h\"\r\n\r\n#define eassert(x, y) if ((x) != (y)) { cout<<\"ERROR: \"<<#x<<\" != \"<<#y<<\" :: \"<<#x<<\"=\"<<x<<\" \"<<#y<<\"=\"<<y<<endl; exit(-1); }\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nabtree_ns::SCXRecord<DEGREE,K> * abtree_ns::abtree<DEGREE,K,Compare,RecManager>::createSCXRecord(const int tid, wrapper_info<DEGREE,K> * info) {\r\n    \r\n    SCXRecord<DEGREE,K> * result = DESC1_NEW(tid);\r\n    result->c.newNode = info->newNode;\r\n    for (int i=0;i<info->numberOfNodes;++i) {\r\n        result->c.nodes[i] = info->nodes[i];\r\n    }\r\n    for (int i=0;i<info->numberOfNodesToFreeze;++i) {\r\n        result->c.scxPtrsSeen[i] = info->scxPtrs[i];\r\n    }\r\n    \r\n    int i;\r\n    for (i=0;info->insertedNodes[i];++i) result->c.insertedNodes[i] = info->insertedNodes[i];\r\n    result->c.insertedNodes[i] = NULL;\r\n    for (i=0;info->deletedNodes[i];++i) result->c.deletedNodes[i] = info->deletedNodes[i];\r\n    result->c.deletedNodes[i] = NULL;\r\n    \r\n    result->c.field = info->field;\r\n    result->c.numberOfNodes = info->numberOfNodes;\r\n    result->c.numberOfNodesToFreeze = info->numberOfNodesToFreeze;\r\n    DESC1_INITIALIZED(tid);\r\n    return result;\r\n}\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nabtree_ns::Node<DEGREE,K> * abtree_ns::abtree<DEGREE,K,Compare,RecManager>::allocateNode(const int tid) {\r\n    Node<DEGREE,K> *newnode = recordmgr->template allocate<Node<DEGREE,K> >(tid);\r\n    if (newnode == NULL) {\r\n        COUTATOMICTID(\"ERROR: could not allocate node\"<<endl);\r\n        exit(-1);\r\n    }\r\n    rqProvider->init_node(tid, newnode);\r\n#ifdef __HANDLE_STATS\r\n    GSTATS_APPEND(tid, node_allocated_addresses, ((long long) newnode)%(1<<12));\r\n#endif\r\n    return newnode;\r\n}\r\n\r\n/**\r\n * Returns the value associated with key, or NULL if key is not present.\r\n */\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nconst pair<void*,bool> abtree_ns::abtree<DEGREE,K,Compare,RecManager>::find(const int tid, const K& key) {\r\n    pair<void*,bool> result;\r\n    this->recordmgr->leaveQuiescentState(tid);\r\n    Node<DEGREE,K> * l = rqProvider->read_addr(tid, &entry->ptrs[0]);\r\n    while (!l->isLeaf()) {\r\n        int ix = l->getChildIndex(key, cmp);\r\n        l = rqProvider->read_addr(tid, &l->ptrs[ix]);\r\n    }\r\n    int index = l->getKeyIndex(key, cmp);\r\n    if (index < l->getKeyCount() && l->keys[index] == key) {\r\n        result.first = l->ptrs[index]; // this is a value, not a pointer, so it cannot be modified by rqProvider->linearize_update_at_..., so we do not use read_addr\r\n        result.second = true;\r\n    } else {\r\n        result.first = NO_VALUE;\r\n        result.second = false;\r\n    }\r\n    this->recordmgr->enterQuiescentState(tid);\r\n    return result;\r\n}\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nbool abtree_ns::abtree<DEGREE,K,Compare,RecManager>::contains(const int tid, const K& key) {\r\n    return find(tid, key).second;\r\n}\r\n\r\ntemplate<int DEGREE, typename K, class Compare, class RecManager>\r\nint abtree_ns::abtree<DEGREE,K,Compare,RecManager>::rangeQuery(const int tid, const K& lo, const K& hi, K * const resultKeys, void ** const resultValues) {\r\n    block<Node<DEGREE,K>> stack (NULL);\r\n    recordmgr->leaveQuiescentState(tid);\r\n    rqProvider->traversal_start(tid);\r\n\r\n    // depth first traversal (of interesting subtrees)\r\n    int size = 0;\r\n    TRACE COUTATOMICTID(\"rangeQuery(lo=\"<<lo<<\", hi=\"<<hi<<\", size=\"<<(hi-lo+1)<<\")\"<<endl);\r\n\r\n    stack.push(entry);\r\n    while (!stack.isEmpty()) {\r\n        Node<DEGREE,K> * node = stack.pop();\r\n        assert(node);\r\n        \r\n        // if leaf node, check if we should add its keys to the traversal\r\n        if (node->isLeaf()) {\r\n            rqProvider->traversal_try_add(tid, node, resultKeys, resultValues, &size, lo, hi);\r\n            \r\n        // else if internal node, explore its children\r\n        } else {\r\n            // find right-most sub-tree that could contain a key in [lo, hi]\r\n            int nkeys = node->getKeyCount();\r\n            int r = nkeys;\r\n            while (r > 0 && cmp(hi, (const K&) node->keys[r-1])) --r;           // subtree rooted at node->ptrs[r] contains only keys > hi\r\n\r\n            // find left-most sub-tree that could contain a key in [lo, hi]\r\n            int l = 0;\r\n            while (l < nkeys && !cmp(lo, (const K&) node->keys[l])) ++l;        // subtree rooted at node->ptrs[l] contains only keys < lo\r\n\r\n            // perform DFS from left to right (so push onto stack from right to left)\r\n            for (int i=r;i>=l; --i) stack.push(rqProvider->read_addr(tid, &node->ptrs[i]));\r\n\r\n//            // simply explore EVERYTHING\r\n//            for (int i=0;i<node->getABDegree();++i) {\r\n//                stack.push(rqProvider->read_addr(tid, &node->ptrs[i]));\r\n//            }\r\n        }\r\n    }\r\n    \r\n    // success\r\n    rqProvider->traversal_end(tid, resultKeys, resultValues, &size, lo, hi);\r\n    recordmgr->enterQuiescentState(tid);\r\n    return size;\r\n}\r\n\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nvoid* abtree_ns::abtree<DEGREE,K,Compare,RecManager>::doInsert(const int tid, const K& key, void * const value, const bool replace) {\r\n    wrapper_info<DEGREE,K> _info;\r\n    wrapper_info<DEGREE,K>* info = &_info;\r\n    while (true) {\r\n        /**\r\n         * search\r\n         */\r\n        this->recordmgr->leaveQuiescentState(tid);\r\n        Node<DEGREE,K>* gp = NULL;\r\n        Node<DEGREE,K>* p = entry;\r\n        Node<DEGREE,K>* l = rqProvider->read_addr(tid, &p->ptrs[0]);\r\n        int ixToP = -1;\r\n        int ixToL = 0;\r\n        while (!l->isLeaf()) {\r\n            ixToP = ixToL;\r\n            ixToL = l->getChildIndex(key, cmp);\r\n            gp = p;\r\n            p = l;\r\n            l = rqProvider->read_addr(tid, &l->ptrs[ixToL]);\r\n        }\r\n\r\n        /**\r\n         * do the update\r\n         */\r\n        int keyIndex = l->getKeyIndex(key, cmp);\r\n        if (keyIndex < l->getKeyCount() && l->keys[keyIndex] == key) {\r\n            /**\r\n             * if l already contains key, replace the existing value\r\n             */\r\n            void* const oldValue = l->ptrs[keyIndex]; // this is a value, not a pointer, so it cannot be modified by rqProvider->linearize_update_at_..., so we do not use read_addr\r\n            if (!replace) {\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                return oldValue;\r\n            }\r\n            \r\n            // perform LLXs\r\n            if (!llx(tid, p, NULL, 0, info->scxPtrs, info->nodes)\r\n                     || rqProvider->read_addr(tid, &p->ptrs[ixToL]) != l) {\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                continue;    // retry the search\r\n            }\r\n            info->nodes[1] = l;\r\n            \r\n            // create new node(s)\r\n            Node<DEGREE,K>* n = allocateNode(tid);\r\n            arraycopy(l->keys, 0, n->keys, 0, l->getKeyCount());\r\n            arraycopy(l->ptrs, 0, n->ptrs, 0, l->getABDegree());    // although we are copying l->ptrs, since l is a leaf, l->ptrs CANNOT contain modified by rqProvider->linearize_update_at_..., so we do not use arraycopy_ptrs.\r\n            n->ptrs[keyIndex] = (Node<DEGREE,K>*) value;            // similarly, we don't use write_addr here\r\n            n->leaf = true;\r\n            n->marked = false;\r\n            n->scxPtr = DUMMY;\r\n            n->searchKey = l->searchKey;\r\n            n->size = l->size;\r\n            n->weight = true;\r\n            \r\n            // construct info record to pass to SCX\r\n            info->numberOfNodes = 2;\r\n            info->numberOfNodesAllocated = 1;\r\n            info->numberOfNodesToFreeze = 1;\r\n            info->field = &p->ptrs[ixToL];\r\n            info->newNode = n;\r\n            info->insertedNodes[0] = n;\r\n            info->insertedNodes[1] = NULL;\r\n            info->deletedNodes[0] = l;\r\n            info->deletedNodes[1] = NULL;\r\n\r\n            if (scx(tid, info)) {\r\n                TRACE COUTATOMICTID(\"replace pair (\"<<key<<\", \"<<value<<\"): SCX succeeded\"<<endl);\r\n                fixDegreeViolation(tid, n);\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                return oldValue;\r\n            }\r\n            TRACE COUTATOMICTID(\"replace pair (\"<<key<<\", \"<<value<<\"): SCX FAILED\"<<endl);\r\n            this->recordmgr->enterQuiescentState(tid);\r\n            this->recordmgr->deallocate(tid, n);\r\n\r\n        } else {\r\n            /**\r\n             * if l does not contain key, we have to insert it\r\n             */\r\n\r\n            // perform LLXs\r\n            if (!llx(tid, p, NULL, 0, info->scxPtrs, info->nodes) || rqProvider->read_addr(tid, &p->ptrs[ixToL]) != l) {\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                continue;    // retry the search\r\n            }\r\n            info->nodes[1] = l;\r\n            \r\n            if (l->getKeyCount() < b) {\r\n                /**\r\n                 * Insert pair\r\n                 */\r\n                \r\n                // create new node(s)\r\n                Node<DEGREE,K>* n = allocateNode(tid);\r\n                arraycopy(l->keys, 0, n->keys, 0, keyIndex);\r\n                arraycopy(l->keys, keyIndex, n->keys, keyIndex+1, l->getKeyCount()-keyIndex);\r\n                n->keys[keyIndex] = key;\r\n                arraycopy(l->ptrs, 0, n->ptrs, 0, keyIndex); // although we are copying the ptrs array, since the source node is a leaf, ptrs CANNOT contain modified by rqProvider->linearize_update_at_..., so we do not use arraycopy_ptrs.\r\n                arraycopy(l->ptrs, keyIndex, n->ptrs, keyIndex+1, l->getABDegree()-keyIndex);\r\n                n->ptrs[keyIndex] = (Node<DEGREE,K>*) value; // similarly, we don't use write_addr here\r\n                n->leaf = l->leaf;\r\n                n->marked = false;\r\n                n->scxPtr = DUMMY;\r\n                n->searchKey = l->searchKey;\r\n                n->size = l->size+1;\r\n                n->weight = l->weight;\r\n\r\n                // construct info record to pass to SCX\r\n                info->numberOfNodes = 2;\r\n                info->numberOfNodesAllocated = 1;\r\n                info->numberOfNodesToFreeze = 1;\r\n                info->field = &p->ptrs[ixToL];\r\n                info->newNode = n;\r\n                info->insertedNodes[0] = n;\r\n                info->insertedNodes[1] = NULL;\r\n                info->deletedNodes[0] = l;\r\n                info->deletedNodes[1] = NULL;\r\n                \r\n                if (scx(tid, info)) {\r\n                    TRACE COUTATOMICTID(\"insert pair (\"<<key<<\", \"<<value<<\"): SCX succeeded\"<<endl);\r\n                    fixDegreeViolation(tid, n);\r\n                    this->recordmgr->enterQuiescentState(tid);\r\n                    return NO_VALUE;\r\n                }\r\n                TRACE COUTATOMICTID(\"insert pair (\"<<key<<\", \"<<value<<\"): SCX FAILED\"<<endl);\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                this->recordmgr->deallocate(tid, n);\r\n                \r\n            } else { // assert: l->getKeyCount() == DEGREE == b)\r\n                /**\r\n                 * Overflow\r\n                 */\r\n                \r\n                // first, we create a pair of large arrays\r\n                // containing too many keys and pointers to fit in a single node\r\n                K keys[DEGREE+1];\r\n                Node<DEGREE,K>* ptrs[DEGREE+1];\r\n                arraycopy(l->keys, 0, keys, 0, keyIndex);\r\n                arraycopy(l->keys, keyIndex, keys, keyIndex+1, l->getKeyCount()-keyIndex);\r\n                keys[keyIndex] = key;\r\n                arraycopy(l->ptrs, 0, ptrs, 0, keyIndex); // although we are copying the ptrs array, since the source node is a leaf, ptrs CANNOT contain modified by rqProvider->linearize_update_at_..., so we do not use arraycopy_ptrs.\r\n                arraycopy(l->ptrs, keyIndex, ptrs, keyIndex+1, l->getABDegree()-keyIndex);\r\n                ptrs[keyIndex] = (Node<DEGREE,K>*) value;\r\n\r\n                // create new node(s):\r\n                // since the new arrays are too big to fit in a single node,\r\n                // we replace l by a new subtree containing three new nodes:\r\n                // a parent, and two leaves;\r\n                // the array contents are then split between the two new leaves\r\n\r\n                const int size1 = (DEGREE+1)/2;\r\n                Node<DEGREE,K>* left = allocateNode(tid);\r\n                arraycopy(keys, 0, left->keys, 0, size1);\r\n                arraycopy(ptrs, 0, left->ptrs, 0, size1); // although we are copying the ptrs array, since the node is a leaf, ptrs CANNOT contain modified by rqProvider->linearize_update_at_..., so we do not use arraycopy_ptrs.\r\n                left->leaf = true;\r\n                left->marked = false;\r\n                left->scxPtr = DUMMY;\r\n                left->searchKey = keys[0];\r\n                left->size = size1;\r\n                left->weight = true;\r\n\r\n                const int size2 = (DEGREE+1) - size1;\r\n                Node<DEGREE,K>* right = allocateNode(tid);\r\n                arraycopy(keys, size1, right->keys, 0, size2);\r\n                arraycopy(ptrs, size1, right->ptrs, 0, size2); // although we are copying the ptrs array, since the node is a leaf, ptrs CANNOT contain modified by rqProvider->linearize_update_at_..., so we do not use arraycopy_ptrs.\r\n                right->leaf = true;\r\n                right->marked = false;\r\n                right->scxPtr = DUMMY;\r\n                right->searchKey = keys[size1];\r\n                right->size = size2;\r\n                right->weight = true;\r\n                \r\n                Node<DEGREE,K>* n = allocateNode(tid);\r\n                n->keys[0] = keys[size1];\r\n                rqProvider->write_addr(tid, &n->ptrs[0], left);\r\n                rqProvider->write_addr(tid, &n->ptrs[1], right);\r\n                n->leaf = false;\r\n                n->marked = false;\r\n                n->scxPtr = DUMMY;\r\n                n->searchKey = keys[size1];\r\n                n->size = 2;\r\n                n->weight = p == entry;\r\n                \r\n                // note: weight of new internal node n will be zero,\r\n                //       unless it is the root; this is because we test\r\n                //       p == entry, above; in doing this, we are actually\r\n                //       performing Root-Zero at the same time as this Overflow\r\n                //       if n will become the root (of the B-slack tree)\r\n                \r\n                // construct info record to pass to SCX\r\n                info->numberOfNodes = 2;\r\n                info->numberOfNodesAllocated = 3;\r\n                info->numberOfNodesToFreeze = 1;\r\n                info->field = &p->ptrs[ixToL];\r\n                info->newNode = n;\r\n                info->insertedNodes[0] = n;\r\n                info->insertedNodes[1] = left;\r\n                info->insertedNodes[2] = right;\r\n                info->insertedNodes[3] = NULL;\r\n                info->deletedNodes[0] = l;\r\n                info->deletedNodes[1] = NULL;\r\n\r\n                if (scx(tid, info)) {\r\n                    TRACE COUTATOMICTID(\"insert overflow (\"<<key<<\", \"<<value<<\"): SCX succeeded\"<<endl);\r\n\r\n                    // after overflow, there may be a weight violation at n,\r\n                    // and there may be a slack violation at p\r\n                    fixWeightViolation(tid, n);\r\n                    this->recordmgr->enterQuiescentState(tid);\r\n                    return NO_VALUE;\r\n                }\r\n                TRACE COUTATOMICTID(\"insert overflow (\"<<key<<\", \"<<value<<\"): SCX FAILED\"<<endl);\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                this->recordmgr->deallocate(tid, n);\r\n                this->recordmgr->deallocate(tid, left);\r\n                this->recordmgr->deallocate(tid, right);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nconst pair<void*,bool> abtree_ns::abtree<DEGREE,K,Compare,RecManager>::erase(const int tid, const K& key) {\r\n    wrapper_info<DEGREE,K> _info;\r\n    wrapper_info<DEGREE,K>* info = &_info;\r\n    while (true) {\r\n        /**\r\n         * search\r\n         */\r\n        this->recordmgr->leaveQuiescentState(tid);\r\n        Node<DEGREE,K>* gp = NULL;\r\n        Node<DEGREE,K>* p = entry;\r\n        Node<DEGREE,K>* l = rqProvider->read_addr(tid, &p->ptrs[0]);\r\n        int ixToP = -1;\r\n        int ixToL = 0;\r\n        while (!l->isLeaf()) {\r\n            ixToP = ixToL;\r\n            ixToL = l->getChildIndex(key, cmp);\r\n            gp = p;\r\n            p = l;\r\n            l = rqProvider->read_addr(tid, &l->ptrs[ixToL]);\r\n        }\r\n\r\n        /**\r\n         * do the update\r\n         */\r\n        const int keyIndex = l->getKeyIndex(key, cmp);\r\n        if (keyIndex == l->getKeyCount() || l->keys[keyIndex] != key) {\r\n            /**\r\n             * if l does not contain key, we are done.\r\n             */\r\n            this->recordmgr->enterQuiescentState(tid);\r\n            return pair<void*,bool>(NO_VALUE,false);\r\n        } else {\r\n            /**\r\n             * if l contains key, replace l by a new copy that does not contain key.\r\n             */\r\n\r\n            // perform LLXs\r\n            if (!llx(tid, p, NULL, 0, info->scxPtrs, info->nodes) || rqProvider->read_addr(tid, &p->ptrs[ixToL]) != l) {\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                continue;    // retry the search\r\n            }\r\n            info->nodes[1] = l;\r\n            // create new node(s)\r\n            Node<DEGREE,K>* n = allocateNode(tid);\r\n            //printf(\"keyIndex=%d getABDegree-keyIndex=%d\\n\", keyIndex, l->getABDegree()-keyIndex);\r\n            arraycopy(l->keys, 0, n->keys, 0, keyIndex);\r\n            arraycopy(l->keys, keyIndex+1, n->keys, keyIndex, l->getKeyCount()-(keyIndex+1));\r\n            arraycopy(l->ptrs, 0, n->ptrs, 0, keyIndex); // although we are copying the ptrs array, since the node is a leaf, ptrs CANNOT contain modified by rqProvider->linearize_update_at_..., so we do not use arraycopy_ptrs.\r\n            arraycopy(l->ptrs, keyIndex+1, n->ptrs, keyIndex, l->getABDegree()-(keyIndex+1));\r\n            n->leaf = true;\r\n            n->marked = false;\r\n            n->scxPtr = DUMMY;\r\n            n->searchKey = l->keys[0]; // NOTE: WE MIGHT BE DELETING l->keys[0], IN WHICH CASE newL IS EMPTY. HOWEVER, newL CAN STILL BE LOCATED BY SEARCHING FOR l->keys[0], SO WE USE THAT AS THE searchKey FOR newL.\r\n            n->size = l->size-1;\r\n            n->weight = true;\r\n\r\n            // construct info record to pass to SCX\r\n            info->numberOfNodes = 2;\r\n            info->numberOfNodesAllocated = 1;\r\n            info->numberOfNodesToFreeze = 1;\r\n            info->field = &p->ptrs[ixToL];\r\n            info->newNode = n;\r\n            info->insertedNodes[0] = n;\r\n            info->insertedNodes[1] = NULL;\r\n            info->deletedNodes[0] = l;\r\n            info->deletedNodes[1] = NULL;\r\n\r\n            void* oldValue = l->ptrs[keyIndex]; // since the node is a leaf, ptrs is not modified by any call to rqProvider->linearize_update_at_..., so we do not need to use read_addr to access it\r\n            if (scx(tid, info)) {\r\n                TRACE COUTATOMICTID(\"delete pair (\"<<key<<\", \"<<oldValue<<\"): SCX succeeded\"<<endl);\r\n\r\n                /**\r\n                 * Compress may be needed at p after removing key from l.\r\n                 */\r\n                fixDegreeViolation(tid, n);\r\n                this->recordmgr->enterQuiescentState(tid);\r\n                return pair<void*,bool>(oldValue, true);\r\n            }\r\n            TRACE COUTATOMICTID(\"delete pair (\"<<key<<\", \"<<oldValue<<\"): SCX FAILED\"<<endl);\r\n            this->recordmgr->enterQuiescentState(tid);\r\n            this->recordmgr->deallocate(tid, n);\r\n        }\r\n    }\r\n}\r\n\r\n/**\r\n * \r\n * \r\n * IMPLEMENTATION OF REBALANCING\r\n * \r\n * \r\n */\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nbool abtree_ns::abtree<DEGREE,K,Compare,RecManager>::fixWeightViolation(const int tid, Node<DEGREE,K>* viol) {\r\n    if (viol->weight) return false;\r\n\r\n    // assert: viol is internal (because leaves always have weight = 1)\r\n    // assert: viol is not entry or root (because both always have weight = 1)\r\n\r\n    // do an optimistic check to see if viol was already removed from the tree\r\n    if (llx(tid, viol, NULL) == FINALIZED) {\r\n        // recall that nodes are finalized precisely when\r\n        // they are removed from the tree\r\n        // we hand off responsibility for any violations at viol to the\r\n        // process that removed it.\r\n        return false;\r\n    }\r\n\r\n    wrapper_info<DEGREE,K> _info;\r\n    wrapper_info<DEGREE,K>* info = &_info;\r\n\r\n    // try to locate viol, and fix any weight violation at viol\r\n    while (true) {\r\n\r\n        const K k = viol->searchKey;\r\n        Node<DEGREE,K>* gp = NULL;\r\n        Node<DEGREE,K>* p = entry;\r\n        Node<DEGREE,K>* l = rqProvider->read_addr(tid, &p->ptrs[0]);\r\n        int ixToP = -1;\r\n        int ixToL = 0;\r\n        while (!l->isLeaf() && l != viol) {\r\n            ixToP = ixToL;\r\n            ixToL = l->getChildIndex(k, cmp);\r\n            gp = p;\r\n            p = l;\r\n            l = rqProvider->read_addr(tid, &l->ptrs[ixToL]);\r\n        }\r\n\r\n        if (l != viol) {\r\n            // l was replaced by another update.\r\n            // we hand over responsibility for viol to that update.\r\n            return false;\r\n        }\r\n\r\n        // we cannot apply this update if p has a weight violation\r\n        // so, we check if this is the case, and, if so, try to fix it\r\n        if (!p->weight) {\r\n            fixWeightViolation(tid, p);\r\n            continue;\r\n        }\r\n        \r\n        // perform LLXs\r\n        if (!llx(tid, gp, NULL, 0, info->scxPtrs, info->nodes) || rqProvider->read_addr(tid, &gp->ptrs[ixToP]) != p) continue;    // retry the search\r\n        if (!llx(tid, p, NULL, 1, info->scxPtrs, info->nodes) || rqProvider->read_addr(tid, &p->ptrs[ixToL]) != l) continue;      // retry the search\r\n        if (!llx(tid, l, NULL, 2, info->scxPtrs, info->nodes)) continue;                             // retry the search\r\n\r\n        const int c = p->getABDegree() + l->getABDegree();\r\n        const int size = c-1;\r\n\r\n        if (size <= b) {\r\n            /**\r\n             * Absorb\r\n             */\r\n\r\n            // create new node(s)\r\n            // the new arrays are small enough to fit in a single node,\r\n            // so we replace p by a new internal node.\r\n            Node<DEGREE,K>* n = allocateNode(tid);\r\n            arraycopy_ptrs(p->ptrs, 0, n->ptrs, 0, ixToL); // p and l are both internal, so we use arraycopy_ptrs\r\n            arraycopy_ptrs(l->ptrs, 0, n->ptrs, ixToL, l->getABDegree());\r\n            arraycopy_ptrs(p->ptrs, ixToL+1, n->ptrs, ixToL+l->getABDegree(), p->getABDegree()-(ixToL+1));\r\n            arraycopy(p->keys, 0, n->keys, 0, ixToL);\r\n            arraycopy(l->keys, 0, n->keys, ixToL, l->getKeyCount());\r\n            arraycopy(p->keys, ixToL, n->keys, ixToL+l->getKeyCount(), p->getKeyCount()-ixToL);\r\n            n->leaf = false; assert(!l->isLeaf());\r\n            n->marked = false;\r\n            n->scxPtr = DUMMY;\r\n            n->searchKey = n->keys[0];\r\n            n->size = size;\r\n            n->weight = true;\r\n            \r\n            // construct info record to pass to SCX\r\n            info->numberOfNodes = 3;\r\n            info->numberOfNodesAllocated = 1;\r\n            info->numberOfNodesToFreeze = 3;\r\n            info->field = &gp->ptrs[ixToP];\r\n            info->newNode = n;\r\n//            info->insertedNodes[0] = info->deletedNodes[0] = NULL;\r\n            info->insertedNodes[0] = n;\r\n            info->insertedNodes[1] = NULL;\r\n            info->deletedNodes[0] = p;\r\n            info->deletedNodes[1] = l;\r\n            info->deletedNodes[2] = NULL;\r\n            \r\n            if (scx(tid, info)) {\r\n                TRACE COUTATOMICTID(\"absorb: SCX succeeded\"<<endl);\r\n\r\n                //    absorb [check: slack@n]\r\n                //        no weight at pi(u)\r\n                //        degree at pi(u) -> eliminated\r\n                //        slack at pi(u) -> eliminated or slack at n\r\n                //        weight at u -> eliminated\r\n                //        no degree at u\r\n                //        slack at u -> slack at n\r\n\r\n                /**\r\n                 * Compress may be needed at the new internal node we created\r\n                 * (since we move grandchildren from two parents together).\r\n                 */\r\n                fixDegreeViolation(tid, n);\r\n                return true;\r\n            }\r\n            TRACE COUTATOMICTID(\"absorb: SCX FAILED\"<<endl);\r\n            this->recordmgr->deallocate(tid, n);\r\n\r\n        } else {\r\n            /**\r\n             * Split\r\n             */\r\n\r\n            // merge keys of p and l into one big array (and similarly for children)\r\n            // (we essentially replace the pointer to l with the contents of l)\r\n            K keys[2*DEGREE];\r\n            Node<DEGREE,K>* ptrs[2*DEGREE];\r\n            arraycopy_ptrs(p->ptrs, 0, ptrs, 0, ixToL); // p and l are both internal, so we use arraycopy_ptrs\r\n            arraycopy_ptrs(l->ptrs, 0, ptrs, ixToL, l->getABDegree());\r\n            arraycopy_ptrs(p->ptrs, ixToL+1, ptrs, ixToL+l->getABDegree(), p->getABDegree()-(ixToL+1));\r\n            arraycopy(p->keys, 0, keys, 0, ixToL);\r\n            arraycopy(l->keys, 0, keys, ixToL, l->getKeyCount());\r\n            arraycopy(p->keys, ixToL, keys, ixToL+l->getKeyCount(), p->getKeyCount()-ixToL);\r\n\r\n            // the new arrays are too big to fit in a single node,\r\n            // so we replace p by a new internal node and two new children.\r\n            //\r\n            // we take the big merged array and split it into two arrays,\r\n            // which are used to create two new children u and v.\r\n            // we then create a new internal node (whose weight will be zero\r\n            // if it is not the root), with u and v as its children.\r\n            \r\n            // create new node(s)\r\n            const int size1 = size / 2;\r\n            Node<DEGREE,K>* left = allocateNode(tid);\r\n            arraycopy(keys, 0, left->keys, 0, size1-1);\r\n            arraycopy_ptrs(ptrs, 0, left->ptrs, 0, size1);\r\n            left->leaf = false; assert(!l->isLeaf());\r\n            left->marked = false;\r\n            left->scxPtr = DUMMY;\r\n            left->searchKey = keys[0];\r\n            left->size = size1;\r\n            left->weight = true;\r\n\r\n            const int size2 = size - size1;\r\n            Node<DEGREE,K>* right = allocateNode(tid);\r\n            arraycopy(keys, size1, right->keys, 0, size2-1);\r\n            arraycopy_ptrs(ptrs, size1, right->ptrs, 0, size2);\r\n            right->leaf = false;\r\n            right->marked = false;\r\n            right->scxPtr = DUMMY;\r\n            right->searchKey = keys[size1];\r\n            right->size = size2;\r\n            right->weight = true;\r\n\r\n            Node<DEGREE,K>* n = allocateNode(tid);\r\n            n->keys[0] = keys[size1-1];\r\n            rqProvider->write_addr(tid, &n->ptrs[0], left);\r\n            rqProvider->write_addr(tid, &n->ptrs[1], right);\r\n            n->leaf = false;\r\n            n->marked = false;\r\n            n->scxPtr = DUMMY;\r\n            n->searchKey = keys[size1-1]; // note: should be the same as n->keys[0]\r\n            n->size = 2;\r\n            n->weight = (gp == entry);\r\n\r\n            // note: weight of new internal node n will be zero,\r\n            //       unless it is the root; this is because we test\r\n            //       gp == entry, above; in doing this, we are actually\r\n            //       performing Root-Zero at the same time as this Overflow\r\n            //       if n will become the root (of the B-slack tree)\r\n\r\n            // construct info record to pass to SCX\r\n            info->numberOfNodes = 3;\r\n            info->numberOfNodesAllocated = 3;\r\n            info->numberOfNodesToFreeze = 3;\r\n            info->field = &gp->ptrs[ixToP];\r\n            info->newNode = n;\r\n//            info->insertedNodes[0] = info->deletedNodes[0] = NULL;\r\n            info->insertedNodes[0] = n;\r\n            info->insertedNodes[1] = left;\r\n            info->insertedNodes[2] = right;\r\n            info->insertedNodes[3] = NULL;\r\n            info->deletedNodes[0] = p;\r\n            info->deletedNodes[1] = l;\r\n            info->deletedNodes[2] = NULL;\r\n\r\n            if (scx(tid, info)) {\r\n                TRACE COUTATOMICTID(\"split: SCX succeeded\"<<endl);\r\n\r\n                fixWeightViolation(tid, n);\r\n                fixDegreeViolation(tid, n);\r\n                return true;\r\n            }\r\n            TRACE COUTATOMICTID(\"split: SCX FAILED\"<<endl);\r\n            this->recordmgr->deallocate(tid, n);\r\n            this->recordmgr->deallocate(tid, left);\r\n            this->recordmgr->deallocate(tid, right);\r\n        }\r\n    }\r\n}\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nbool abtree_ns::abtree<DEGREE,K,Compare,RecManager>::fixDegreeViolation(const int tid, Node<DEGREE,K>* viol) {\r\n    if (viol->getABDegree() >= a || viol == entry || viol == rqProvider->read_addr(tid, &entry->ptrs[0])) {\r\n        return false; // no degree violation at viol\r\n    }\r\n    \r\n    // do an optimistic check to see if viol was already removed from the tree\r\n    if (llx(tid, viol, NULL) == FINALIZED) {\r\n        // recall that nodes are finalized precisely when\r\n        // they are removed from the tree.\r\n        // we hand off responsibility for any violations at viol to the\r\n        // process that removed it.\r\n        return false;\r\n    }\r\n\r\n    wrapper_info<DEGREE,K> _info;\r\n    wrapper_info<DEGREE,K>* info = &_info;\r\n\r\n    // we search for viol and try to fix any violation we find there\r\n    // this entails performing AbsorbSibling or Distribute.\r\n    while (true) {\r\n        /**\r\n         * search for viol\r\n         */\r\n        const K k = viol->searchKey;\r\n        Node<DEGREE,K>* gp = NULL;\r\n        Node<DEGREE,K>* p = entry;\r\n        Node<DEGREE,K>* l = rqProvider->read_addr(tid, &p->ptrs[0]);\r\n        int ixToP = -1;\r\n        int ixToL = 0;\r\n        while (!l->isLeaf() && l != viol) {\r\n            ixToP = ixToL;\r\n            ixToL = l->getChildIndex(k, cmp);\r\n            gp = p;\r\n            p = l;\r\n            l = rqProvider->read_addr(tid, &l->ptrs[ixToL]);\r\n        }\r\n\r\n        if (l != viol) {\r\n            // l was replaced by another update.\r\n            // we hand over responsibility for viol to that update.\r\n            return false;\r\n        }\r\n        \r\n        // assert: gp != NULL (because if AbsorbSibling or Distribute can be applied, then p is not the root)\r\n        \r\n        // perform LLXs\r\n        if (!llx(tid, gp, NULL, 0, info->scxPtrs, info->nodes)\r\n                 || rqProvider->read_addr(tid, &gp->ptrs[ixToP]) != p) continue;   // retry the search\r\n        if (!llx(tid, p, NULL, 1, info->scxPtrs, info->nodes) \r\n                 || rqProvider->read_addr(tid, &p->ptrs[ixToL]) != l) continue;     // retry the search\r\n\r\n        int ixToS = (ixToL > 0 ? ixToL-1 : 1);\r\n        Node<DEGREE,K>* s = rqProvider->read_addr(tid, &p->ptrs[ixToS]);\r\n        \r\n        // we can only apply AbsorbSibling or Distribute if there are no\r\n        // weight violations at p, l or s.\r\n        // so, we first check for any weight violations,\r\n        // and fix any that we see.\r\n        bool foundWeightViolation = false;\r\n        if (!p->weight) {\r\n            foundWeightViolation = true;\r\n            fixWeightViolation(tid, p);\r\n        }\r\n        if (!l->weight) {\r\n            foundWeightViolation = true;\r\n            fixWeightViolation(tid, l);\r\n        }\r\n        if (!s->weight) {\r\n            foundWeightViolation = true;\r\n            fixWeightViolation(tid, s);\r\n        }\r\n        // if we see any weight violations, then either we fixed one,\r\n        // removing one of these nodes from the tree,\r\n        // or one of the nodes has been removed from the tree by another\r\n        // rebalancing step, so we retry the search for viol\r\n        if (foundWeightViolation) continue;\r\n\r\n        // assert: there are no weight violations at p, l or s\r\n        // assert: l and s are either both leaves or both internal nodes\r\n        //         (because there are no weight violations at these nodes)\r\n        \r\n        // also note that p->size >= a >= 2\r\n        \r\n        Node<DEGREE,K>* left;\r\n        Node<DEGREE,K>* right;\r\n        int leftindex;\r\n        int rightindex;\r\n\r\n        if (ixToL < ixToS) {\r\n            if (!llx(tid, l, NULL, 2, info->scxPtrs, info->nodes)) continue; // retry the search\r\n            if (!llx(tid, s, NULL, 3, info->scxPtrs, info->nodes)) continue; // retry the search\r\n            left = l;\r\n            right = s;\r\n            leftindex = ixToL;\r\n            rightindex = ixToS;\r\n        } else {\r\n            if (!llx(tid, s, NULL, 2, info->scxPtrs, info->nodes)) continue; // retry the search\r\n            if (!llx(tid, l, NULL, 3, info->scxPtrs, info->nodes)) continue; // retry the search\r\n            left = s;\r\n            right = l;\r\n            leftindex = ixToS;\r\n            rightindex = ixToL;\r\n        }\r\n        \r\n        int sz = left->getABDegree() + right->getABDegree();\r\n        assert(left->weight && right->weight);\r\n        \r\n        if (sz < 2*a) {\r\n            /**\r\n             * AbsorbSibling\r\n             */\r\n            \r\n            // create new node(s))\r\n            Node<DEGREE,K>* newl = allocateNode(tid);\r\n            int k1=0, k2=0;\r\n            for (int i=0;i<left->getKeyCount();++i) {\r\n                newl->keys[k1++] = left->keys[i];\r\n            }\r\n            for (int i=0;i<left->getABDegree();++i) {\r\n                if (left->isLeaf()) {\r\n                    newl->ptrs[k2++] = left->ptrs[i];\r\n                } else {\r\n                    //assert(left->getKeyCount() != left->getABDegree());\r\n                    rqProvider->write_addr(tid, &newl->ptrs[k2++], rqProvider->read_addr(tid, &left->ptrs[i]));\r\n                }\r\n            }\r\n            if (!left->isLeaf()) newl->keys[k1++] = p->keys[leftindex];\r\n            for (int i=0;i<right->getKeyCount();++i) {\r\n                newl->keys[k1++] = right->keys[i];\r\n            }\r\n            for (int i=0;i<right->getABDegree();++i) {\r\n                if (right->isLeaf()) {\r\n                    newl->ptrs[k2++] = right->ptrs[i];\r\n                } else {\r\n                    rqProvider->write_addr(tid, &newl->ptrs[k2++], rqProvider->read_addr(tid, &right->ptrs[i]));\r\n                }\r\n            }\r\n            newl->leaf = left->isLeaf();\r\n            newl->marked = false;\r\n            newl->scxPtr = DUMMY;\r\n            newl->searchKey = l->searchKey;\r\n            newl->size = l->getABDegree() + s->getABDegree();\r\n            newl->weight = true; assert(left->weight && right->weight && p->weight);\r\n            \r\n            // now, we atomically replace p and its children with the new nodes.\r\n            // if appropriate, we perform RootAbsorb at the same time.\r\n            if (gp == entry && p->getABDegree() == 2) {\r\n            \r\n                // construct info record to pass to SCX\r\n                info->numberOfNodes = 4; // gp + p + l + s\r\n                info->numberOfNodesAllocated = 1; // newl\r\n                info->numberOfNodesToFreeze = 4; // gp + p + l + s\r\n                info->field = &gp->ptrs[ixToP];\r\n                info->newNode = newl;\r\n                info->insertedNodes[0] = newl;\r\n                info->insertedNodes[1] = NULL;\r\n                info->deletedNodes[0] = p;\r\n                info->deletedNodes[1] = l;\r\n                info->deletedNodes[2] = s;\r\n                info->deletedNodes[3] = NULL;\r\n                \r\n                if (scx(tid, info)) {\r\n                    TRACE COUTATOMICTID(\"absorbsibling AND rootabsorb: SCX succeeded\"<<endl);\r\n\r\n                    fixDegreeViolation(tid, newl);\r\n                    return true;\r\n                }\r\n                TRACE COUTATOMICTID(\"absorbsibling AND rootabsorb: SCX FAILED\"<<endl);\r\n                this->recordmgr->deallocate(tid, newl);\r\n                \r\n            } else {\r\n                assert(gp != entry || p->getABDegree() > 2);\r\n                \r\n                // create n from p by:\r\n                // 1. skipping the key for leftindex and child pointer for ixToS\r\n                // 2. replacing l with newl\r\n                Node<DEGREE,K>* n = allocateNode(tid);\r\n                for (int i=0;i<leftindex;++i) {\r\n                    n->keys[i] = p->keys[i];\r\n                }\r\n                for (int i=0;i<ixToS;++i) {\r\n                    rqProvider->write_addr(tid, &n->ptrs[i], rqProvider->read_addr(tid, &p->ptrs[i]));      // n and p are internal, so their ptrs arrays might have entries that are being modified by rqProvider->linearize_update_at_..., so we use read_addr and write_addr\r\n                }\r\n                for (int i=leftindex+1;i<p->getKeyCount();++i) {\r\n                    n->keys[i-1] = p->keys[i];\r\n                }\r\n                for (int i=ixToL+1;i<p->getABDegree();++i) {\r\n                    rqProvider->write_addr(tid, &n->ptrs[i-1], rqProvider->read_addr(tid, &p->ptrs[i]));    // n and p are internal, so their ptrs arrays might have entries that are being modified by rqProvider->linearize_update_at_..., so we use read_addr and write_addr\r\n                }\r\n                // replace l with newl\r\n                rqProvider->write_addr(tid, &n->ptrs[ixToL - (ixToL > ixToS)], newl);\r\n                n->leaf = false;\r\n                n->marked = false;\r\n                n->scxPtr = DUMMY;\r\n                n->searchKey = p->searchKey;\r\n                n->size = p->getABDegree()-1;\r\n                n->weight = true;\r\n\r\n                // construct info record to pass to SCX\r\n                info->numberOfNodes = 4; // gp + p + l + s\r\n                info->numberOfNodesAllocated = 2; // n + newl\r\n                info->numberOfNodesToFreeze = 4; // gp + p + l + s\r\n                info->field = &gp->ptrs[ixToP];\r\n                info->newNode = n;\r\n                info->insertedNodes[0] = n;\r\n                info->insertedNodes[1] = newl;\r\n                info->insertedNodes[2] = NULL;\r\n                info->deletedNodes[0] = p;\r\n                info->deletedNodes[1] = l;\r\n                info->deletedNodes[2] = s;\r\n                info->deletedNodes[3] = NULL;\r\n                \r\n                if (scx(tid, info)) {\r\n                    TRACE COUTATOMICTID(\"absorbsibling: SCX succeeded\"<<endl);\r\n\r\n                    fixDegreeViolation(tid, newl);\r\n                    fixDegreeViolation(tid, n);\r\n                    return true;\r\n                }\r\n                TRACE COUTATOMICTID(\"absorbsibling: SCX FAILED\"<<endl);\r\n                this->recordmgr->deallocate(tid, newl);\r\n                this->recordmgr->deallocate(tid, n);\r\n            }\r\n            \r\n        } else {\r\n            /**\r\n             * Distribute\r\n             */\r\n            \r\n            int leftsz = sz/2;\r\n            int rightsz = sz-leftsz;\r\n            \r\n            // create new node(s))\r\n            Node<DEGREE,K>* n = allocateNode(tid);\r\n            Node<DEGREE,K>* newleft = allocateNode(tid);\r\n            Node<DEGREE,K>* newright = allocateNode(tid);\r\n            \r\n            // combine the contents of l and s (and one key from p if l and s are internal)\r\n            K keys[2*DEGREE];\r\n            Node<DEGREE,K>* ptrs[2*DEGREE];\r\n            int k1=0, k2=0;\r\n            for (int i=0;i<left->getKeyCount();++i) {\r\n                keys[k1++] = left->keys[i];\r\n            }\r\n            for (int i=0;i<left->getABDegree();++i) {\r\n                if (left->isLeaf()) {\r\n                    ptrs[k2++] = left->ptrs[i];\r\n                } else {\r\n                    ptrs[k2++] = rqProvider->read_addr(tid, &left->ptrs[i]);\r\n                }\r\n            }\r\n            if (!left->isLeaf()) keys[k1++] = p->keys[leftindex];\r\n            for (int i=0;i<right->getKeyCount();++i) {\r\n                keys[k1++] = right->keys[i];\r\n            }\r\n            for (int i=0;i<right->getABDegree();++i) {\r\n                if (right->isLeaf()) {\r\n                    ptrs[k2++] = right->ptrs[i];\r\n                } else {\r\n                    ptrs[k2++] = rqProvider->read_addr(tid, &right->ptrs[i]);\r\n                }\r\n            }\r\n            \r\n            // distribute contents between newleft and newright\r\n            k1=0;\r\n            k2=0;\r\n            for (int i=0;i<leftsz - !left->isLeaf();++i) {\r\n                newleft->keys[i] = keys[k1++];\r\n            }\r\n            for (int i=0;i<leftsz;++i) {\r\n                if (left->isLeaf()) {\r\n                    newleft->ptrs[i] = ptrs[k2++];\r\n                } else {\r\n                    rqProvider->write_addr(tid, &newleft->ptrs[i], ptrs[k2++]);\r\n                }\r\n            }\r\n            newleft->leaf = left->isLeaf();\r\n            newleft->marked = false;\r\n            newleft->scxPtr = DUMMY;\r\n            newleft->searchKey = newleft->keys[0];\r\n            newleft->size = leftsz;\r\n            newleft->weight = true;\r\n            \r\n            // reserve one key for the parent (to go between newleft and newright)\r\n            K keyp = keys[k1];\r\n            if (!left->isLeaf()) ++k1;\r\n            for (int i=0;i<rightsz - !left->isLeaf();++i) {\r\n                newright->keys[i] = keys[k1++];\r\n            }\r\n            for (int i=0;i<rightsz;++i) {\r\n                if (right->isLeaf()) {\r\n                    newright->ptrs[i] = ptrs[k2++];\r\n                } else {\r\n                    rqProvider->write_addr(tid, &newright->ptrs[i], ptrs[k2++]);\r\n                }\r\n            }\r\n            newright->leaf = right->isLeaf();\r\n            newright->marked = false;\r\n            newright->scxPtr = DUMMY;\r\n            newright->searchKey = newright->keys[0];\r\n            newright->size = rightsz;\r\n            newright->weight = true;\r\n            \r\n            // create n from p by replacing left with newleft and right with newright,\r\n            // and replacing one key (between these two pointers)\r\n            for (int i=0;i<p->getKeyCount();++i) {\r\n                n->keys[i] = p->keys[i];\r\n            }\r\n            for (int i=0;i<p->getABDegree();++i) {\r\n                rqProvider->write_addr(tid, &n->ptrs[i], rqProvider->read_addr(tid, &p->ptrs[i])); // n and p are internal, so their ptrs arrays might have entries that are being modified by rqProvider->linearize_update_at_..., so we use read_addr and write_addr\r\n            }\r\n            n->keys[leftindex] = keyp;\r\n            rqProvider->write_addr(tid, &n->ptrs[leftindex], newleft);\r\n            rqProvider->write_addr(tid, &n->ptrs[rightindex], newright);\r\n            n->leaf = false;\r\n            n->marked = false;\r\n            n->scxPtr = DUMMY;\r\n            n->searchKey = p->searchKey;\r\n            n->size = p->size;\r\n            n->weight = true;\r\n            \r\n            // construct info record to pass to SCX\r\n            info->numberOfNodes = 4; // gp + p + l + s\r\n            info->numberOfNodesAllocated = 3; // n + newleft + newright\r\n            info->numberOfNodesToFreeze = 4; // gp + p + l + s\r\n            info->field = &gp->ptrs[ixToP];\r\n            info->newNode = n;\r\n            info->insertedNodes[0] = n;\r\n            info->insertedNodes[1] = newleft;\r\n            info->insertedNodes[2] = newright;\r\n            info->insertedNodes[3] = NULL;\r\n            info->deletedNodes[0] = p;\r\n            info->deletedNodes[1] = l;\r\n            info->deletedNodes[2] = s;\r\n            info->deletedNodes[3] = NULL;\r\n            \r\n            if (scx(tid, info)) {\r\n                TRACE COUTATOMICTID(\"distribute: SCX succeeded\"<<endl);\r\n\r\n                fixDegreeViolation(tid, n);\r\n                return true;\r\n            }\r\n            TRACE COUTATOMICTID(\"distribute: SCX FAILED\"<<endl);\r\n            this->recordmgr->deallocate(tid, n);\r\n            this->recordmgr->deallocate(tid, newleft);\r\n            this->recordmgr->deallocate(tid, newright);\r\n        }\r\n    }\r\n}\r\n\r\n/**\r\n * \r\n * IMPLEMENTATION OF LLX AND SCX\r\n * \r\n * \r\n */\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nbool abtree_ns::abtree<DEGREE,K,Compare,RecManager>::llx(const int tid, Node<DEGREE,K>* r, Node<DEGREE,K> ** snapshot, const int i, SCXRecord<DEGREE,K> ** ops, Node<DEGREE,K> ** nodes) {\r\n    SCXRecord<DEGREE,K>* result = llx(tid, r, snapshot);\r\n    if (result == FAILED || result == FINALIZED) return false;\r\n    ops[i] = result;\r\n    nodes[i] = r;\r\n    return true;\r\n}\r\n\r\ntemplate <int DEGREE, typename K, class Compare, class RecManager>\r\nabtree_ns::SCXRecord<DEGREE,K>* abtree_ns::abtree<DEGREE,K,Compare,RecManager>::llx(const int tid, Node<DEGREE,K>* r, Node<DEGREE,K> ** snapshot) {\r\n    const bool marked = r->marked;\r\n    SOFTWARE_BARRIER;\r\n    tagptr_t tagptr = (tagptr_t) r->scxPtr;\r\n    \r\n    // read mutable state field of descriptor\r\n    bool succ;\r\n    TRACE COUTATOMICTID(\"tagged ptr seq=\"<<UNPACK1_SEQ(tagptr)<<\" descriptor seq=\"<<UNPACK1_SEQ(TAGPTR1_UNPACK_PTR(tagptr)->c.mutables)<<endl);\r\n    int state = DESC1_READ_FIELD(succ, TAGPTR1_UNPACK_PTR(tagptr)->c.mutables, tagptr, MUTABLES1_MASK_STATE, MUTABLES1_OFFSET_STATE);\r\n    if (!succ) state = SCXRecord<DEGREE,K>::STATE_COMMITTED;\r\n    TRACE { mutables_t debugmutables = TAGPTR1_UNPACK_PTR(tagptr)->c.mutables; COUTATOMICTID(\"llx scxrecord succ=\"<<succ<<\" state=\"<<state<<\" mutables=\"<<debugmutables<<\" desc-seq=\"<<UNPACK1_SEQ(debugmutables)<<endl); }\r\n    // note: special treatment for alg in the case where the descriptor has already been reallocated (impossible before the transformation, assuming safe memory reclamation)\r\n    SOFTWARE_BARRIER;\r\n    \r\n    if (state == SCXRecord<DEGREE,K>::STATE_ABORTED || ((state == SCXRecord<DEGREE,K>::STATE_COMMITTED) && !r->marked)) {\r\n        // read snapshot fields\r\n        if (snapshot != NULL) {\r\n            if (r->isLeaf()) {\r\n                arraycopy(r->ptrs, 0, snapshot, 0, r->getABDegree());\r\n            } else {\r\n                arraycopy_ptrs(r->ptrs, 0, snapshot, 0, r->getABDegree());\r\n            }\r\n        }\r\n        if ((tagptr_t) r->scxPtr == tagptr) return (SCXRecord<DEGREE,K> *) tagptr; // we have a snapshot\r\n    }\r\n\r\n    if (state == SCXRecord<DEGREE,K>::STATE_INPROGRESS) {\r\n        helpOther(tid, tagptr);\r\n    }\r\n    return (marked ? FINALIZED : FAILED);\r\n}\r\n\r\ntemplate<int DEGREE, typename K, class Compare, class RecManager>\r\nbool abtree_ns::abtree<DEGREE,K,Compare,RecManager>::scx(const int tid, wrapper_info<DEGREE,K> * info) {\r\n    const int init_state = SCXRecord<DEGREE,K>::STATE_INPROGRESS;\r\n    SCXRecord<DEGREE,K> * newdesc = createSCXRecord(tid, info);\r\n    tagptr_t tagptr = TAGPTR1_NEW(tid, newdesc->c.mutables);\r\n    info->state = help(tid, tagptr, newdesc, false);\r\n    return info->state & SCXRecord<DEGREE,K>::STATE_COMMITTED;\r\n}\r\n\r\n// returns true if we executed help, and false otherwise\r\ntemplate<int DEGREE, typename K, class Compare, class RecManager>\r\nvoid abtree_ns::abtree<DEGREE,K,Compare,RecManager>::helpOther(const int tid, tagptr_t tagptr) {\r\n    if ((void*) tagptr == DUMMY) {\r\n        return; // deal with the dummy descriptor\r\n    }\r\n    SCXRecord<DEGREE,K> snap;\r\n    if (DESC1_SNAPSHOT(&snap, tagptr, SCXRecord<DEGREE comma K>::size)) {\r\n        help(tid, tagptr, &snap, true);\r\n    }\r\n}\r\n\r\ntemplate<int DEGREE, typename K, class Compare, class RecManager>\r\nint abtree_ns::abtree<DEGREE,K,Compare,RecManager>::help(const int tid, const tagptr_t tagptr, SCXRecord<DEGREE,K> const * const snap, const bool helpingOther) {\r\n#ifdef NO_HELPING\r\n    int IGNORED_RETURN_VALUE = -1;\r\n    if (helpingOther) return IGNORED_RETURN_VALUE;\r\n#endif\r\n//    TRACE COUTATOMICTID(\"help \"<<tagptrToString(tagptr)<<\" helpingOther=\"<<helpingOther<<\" numNodes=\"<<snap->c.numberOfNodes<<\" numToFreeze=\"<<snap->c.numberOfNodesToFreeze<<endl);\r\n    SCXRecord<DEGREE,K> *ptr = TAGPTR1_UNPACK_PTR(tagptr);\r\n    //if (helpingOther) { eassert(UNPACK1_SEQ(snap->c.mutables), UNPACK1_SEQ(tagptr)); /*assert(UNPACK1_SEQ(snap->c.mutables) == UNPACK1_SEQ(tagptr));*/ }\r\n    // freeze sub-tree\r\n    for (int i=helpingOther; i<snap->c.numberOfNodesToFreeze; ++i) {\r\n        if (snap->c.nodes[i]->isLeaf()) {\r\n            TRACE COUTATOMICTID((helpingOther?\"    \":\"\")<<\"help \"<<\"nodes[\"<<i<<\"]@\"<<\"0x\"<<((uintptr_t)(snap->c.nodes[i]))<<\" is a leaf\\n\");\r\n            assert(i > 0); // nodes[0] cannot be a leaf...\r\n            continue; // do not freeze leaves\r\n        }\r\n        \r\n        bool successfulCAS = __sync_bool_compare_and_swap(&snap->c.nodes[i]->scxPtr, snap->c.scxPtrsSeen[i], tagptr);\r\n        SCXRecord<DEGREE,K> *exp = snap->c.nodes[i]->scxPtr;\r\n//        TRACE if (successfulCAS) COUTATOMICTID((helpingOther?\"    \":\"\")<<\"help froze nodes[\"<<i<<\"]@0x\"<<((uintptr_t)snap->c.nodes[i])<<\" with tagptr=\"<<tagptrToString((tagptr_t) snap->c.nodes[i]->scxPtr)<<endl);\r\n        if (successfulCAS || exp == (void*) tagptr) continue; // if node is already frozen for our operation\r\n\r\n        // note: we can get here only if:\r\n        // 1. the state is inprogress, and we just failed a cas, and every helper will fail that cas (or an earlier one), so the scx must abort, or\r\n        // 2. the state is committed or aborted\r\n        // (this suggests that it might be possible to get rid of the allFrozen bit)\r\n        \r\n        // read mutable allFrozen field of descriptor\r\n        bool succ;\r\n        bool allFrozen = DESC1_READ_FIELD(succ, ptr->c.mutables, tagptr, MUTABLES1_MASK_ALLFROZEN, MUTABLES1_OFFSET_ALLFROZEN);\r\n        if (!succ) return SCXRecord<DEGREE,K>::STATE_ABORTED;\r\n        \r\n        if (allFrozen) {\r\n            TRACE COUTATOMICTID((helpingOther?\"    \":\"\")<<\"help return state \"<<SCXRecord<DEGREE comma K>::STATE_COMMITTED<<\" after failed freezing cas on nodes[\"<<i<<\"]\"<<endl);\r\n            return SCXRecord<DEGREE,K>::STATE_COMMITTED;\r\n        } else {\r\n            const int newState = SCXRecord<DEGREE,K>::STATE_ABORTED;\r\n            TRACE COUTATOMICTID((helpingOther?\"    \":\"\")<<\"help return state \"<<newState<<\" after failed freezing cas on nodes[\"<<i<<\"]\"<<endl);\r\n            MUTABLES1_WRITE_FIELD(ptr->c.mutables, snap->c.mutables, newState, MUTABLES1_MASK_STATE, MUTABLES1_OFFSET_STATE);\r\n            return newState;\r\n        }\r\n    }\r\n    \r\n    MUTABLES1_WRITE_BIT(ptr->c.mutables, snap->c.mutables, MUTABLES1_MASK_ALLFROZEN);\r\n    SOFTWARE_BARRIER;\r\n    for (int i=1; i<snap->c.numberOfNodesToFreeze; ++i) {\r\n        if (snap->c.nodes[i]->isLeaf()) continue; // do not mark leaves\r\n        snap->c.nodes[i]->marked = true; // finalize all but first node\r\n    }\r\n\r\n    // CAS in the new sub-tree (update CAS)\r\n    rqProvider->linearize_update_at_cas(tid, snap->c.field, snap->c.nodes[1], snap->c.newNode, snap->c.insertedNodes, snap->c.deletedNodes);\r\n//    __sync_bool_compare_and_swap(snap->c.field, snap->c.nodes[1], snap->c.newNode);\r\n    TRACE COUTATOMICTID((helpingOther?\"    \":\"\")<<\"help CAS'ed to newNode@0x\"<<((uintptr_t)snap->c.newNode)<<endl);\r\n\r\n    MUTABLES1_WRITE_FIELD(ptr->c.mutables, snap->c.mutables, SCXRecord<DEGREE comma K>::STATE_COMMITTED, MUTABLES1_MASK_STATE, MUTABLES1_OFFSET_STATE);\r\n    \r\n    TRACE COUTATOMICTID((helpingOther?\"    \":\"\")<<\"help return COMMITTED after performing update cas\"<<endl);\r\n    return SCXRecord<DEGREE,K>::STATE_COMMITTED; // success\r\n}\r\n\r\n#endif\t/* ABTREE_IMPL_H */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_abtree/minimal_example.cpp",
    "content": "/**\r\n * Author: Trevor Brown (me [at] tbrown [dot] pro).\r\n * Copyright 2018.\r\n * \r\n * This program is free software; you can redistribute it and/or\r\n * modify it under the terms of the GNU General Public License\r\n * as published by the Free Software Foundation, version 2\r\n * of the License.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n * GNU General Public License for more details.\r\n */\r\n\r\n#include <iostream>\r\n#include <limits>\r\n#include <cassert>\r\n\r\n#include \"brown_ext_abtree_lf_adapter.h\"\r\n\r\nint main(int argc, char** argv) {\r\n\r\n    const int NODE_DEGREE = 16;\r\n    const int ANY_KEY = 0;\r\n    const int NUM_THREADS = 1;\r\n    \r\n    auto tree = new ds_adapter<NODE_DEGREE, int>(NUM_THREADS, ANY_KEY);\r\n    \r\n    const int threadID = 0;\r\n\r\n    tree->initThread(threadID);\r\n    \r\n    void * oldVal = tree->insertIfAbsent(threadID, 7, (void *) 1020);\r\n    assert(oldVal == tree->getNoValue());\r\n    \r\n    bool result = tree->contains(threadID, 7);\r\n    assert(result);\r\n    \r\n    result = tree->contains(threadID, 8);\r\n    assert(!result);\r\n    \r\n    void * val = tree->find(threadID, 7);\r\n    assert(val == (void *) 1020);\r\n    \r\n    val = tree->erase(threadID, 7);\r\n    assert(val == (void *) 1020);\r\n    \r\n    result = tree->contains(threadID, 7);\r\n    assert(!result);\r\n    \r\n    tree->deinitThread(threadID);\r\n    \r\n    delete tree;\r\n    \r\n    std::cout<<\"Passed quick tests.\"<<std::endl;\r\n            \r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "datastructures/trevor_brown_natarajan/TrevorBrownNatarajanTree.hpp",
    "content": "#ifndef _TREVOR_BROWN_NATARAJAN_TREE_HP_H_\r\n#define _TREVOR_BROWN_NATARAJAN_TREE_HP_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n#include <limits>\r\n#include \"common/ThreadRegistry.hpp\"\r\n#include \"ds/natarajan_ext_bst_lf/natarajan_ext_bst_lf_adapter.h\"\r\n\r\n/*\r\n * This is a wrapper to Trevor Brown's implementation of Naratajan's lock=free Tree so we can use it in our benchmarks\r\n */\r\n\r\ntemplate<typename K>\r\nclass TrevorBrownNatarajanTree {\r\n    const int NUM_THREADS = 128;\r\n    //ds_adapter<K, K, reclaimer_hazardptr<K>>* tree;\r\n    ds_adapter<K, K>* tree;\r\n\r\npublic:\r\n    TrevorBrownNatarajanTree(int numThreads) {\r\n        const int minValue = 0;\r\n        const int maxValue = std::numeric_limits<int>::max();\r\n        const int noValue = -1;\r\n        //tree = new ds_adapter<K, K, reclaimer_hazardptr<K>>(minValue, maxValue, noValue, NUM_THREADS);\r\n        tree = new ds_adapter<K, K>(minValue, maxValue, noValue, NUM_THREADS);\r\n    }\r\n\r\n    ~TrevorBrownNatarajanTree() {\r\n        // TODO: deinit threads?\r\n        delete tree;\r\n    }\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(K key, const int tid=0) {\r\n        int threadID = tl_tcico.tid;\r\n        if (threadID == ThreadCheckInCheckOut::NOT_ASSIGNED) {\r\n            threadID = ThreadRegistry::getTID();\r\n            tree->initThread(threadID);\r\n        }\r\n        return tree->insertIfAbsent(threadID, key, 1) != tree->getNoValue();\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K key, const int tid=0) {\r\n        int threadID = tl_tcico.tid;\r\n        if (threadID == ThreadCheckInCheckOut::NOT_ASSIGNED) {\r\n            threadID = ThreadRegistry::getTID();\r\n            tree->initThread(threadID);\r\n        }\r\n        return tree->erase(threadID, key) != tree->getNoValue();\r\n    }\r\n\r\n    bool contains(K key, const int tid=0) {\r\n        int threadID = tl_tcico.tid;\r\n        if (threadID == ThreadCheckInCheckOut::NOT_ASSIGNED) {\r\n            threadID = ThreadRegistry::getTID();\r\n            tree->initThread(threadID);\r\n        }\r\n        return tree->contains(threadID, key);\r\n    }\r\n\r\n    // This is not fully transactionally but it's ok because we use it only on initialization.\r\n    // We could make it fully transactionally, but we would have to increase the size of allocation/store logs.\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return \"TrevorBrown-Natarajan-Tree\"; }\r\n\r\n};\r\n\r\n#endif   // _TREVOR_BROWN_NATARAJAN_TREE_HP_H_\r\n"
  },
  {
    "path": "datastructures/trevor_brown_natarajan/ds/natarajan_ext_bst_lf/natarajan_ext_bst_lf_adapter.h",
    "content": "/* \r\n * Implementation of the lock-free tree of Natarajan and Mittal.\r\n * \r\n * Heavily edited by Trevor Brown (me [at] tbrown [dot] pro).\r\n * (Late 2017, early 2018.)\r\n * \r\n * Notable changes:\r\n * - Converted original implementation to a class.\r\n * - Fixed a bug: atomic_ops types don't contain \"volatile,\" so the original\r\n *       implementation behaved erroneously under high contention.\r\n * - Fixed the original implementation's erroneous memory reclamation,\r\n *       which would leak many nodes.\r\n * \r\n * This program is free software; you can redistribute it and/or\r\n * modify it under the terms of the GNU General Public License\r\n * as published by the Free Software Foundation, version 2\r\n * of the License.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n * GNU General Public License for more details.\r\n *\r\n * Created on August 31, 2017, 6:22 PM\r\n */\r\n\r\n#ifndef NATARAJAN_EXT_BST_LF_ADAPTER_H\r\n#define NATARAJAN_EXT_BST_LF_ADAPTER_H\r\n\r\n#include <iostream>\r\n#include \"errors.h\"\r\n#include \"natarajan_ext_bst_lf_stage2_impl.h\"\r\n\r\n#define RECORD_MANAGER_T record_manager<Reclaim, Alloc, Pool, node_t<K, V>>\r\n#define DATA_STRUCTURE_T natarajan_ext_bst_lf<K, V, RECORD_MANAGER_T>\r\n\r\ntemplate <class K, class V, class Reclaim = reclaimer_debra<K>, class Alloc = allocator_new<K>, class Pool = pool_none<K>>\r\nclass ds_adapter {\r\nprivate:\r\n    const V NO_VALUE;\r\n    DATA_STRUCTURE_T * const tree;\r\n\r\npublic:\r\n    ds_adapter(const K& MIN_KEY, const K& MAX_KEY, const V& _NO_VALUE, const int numThreads)\r\n    : NO_VALUE(_NO_VALUE)\r\n    , tree(new DATA_STRUCTURE_T(MAX_KEY, NO_VALUE, numThreads))\r\n    {}\r\n    ~ds_adapter() {\r\n        delete tree;\r\n    }\r\n    \r\n    V getNoValue() {\r\n        return NO_VALUE;\r\n    }\r\n    \r\n    void initThread(const int tid) {\r\n        tree->initThread(tid);\r\n    }\r\n    void deinitThread(const int tid) {\r\n        tree->deinitThread(tid);\r\n    }\r\n\r\n    bool contains(const int tid, const K& key) {\r\n        return tree->find(tid, key) != getNoValue();\r\n    }\r\n    V insert(const int tid, const K& key, const V& val) {\r\n        error(\"insert-replace not implemented for this data structure\");\r\n    }\r\n    V insertIfAbsent(const int tid, const K& key, const V& val) {\r\n        return tree->insertIfAbsent(tid, key, val);\r\n    }\r\n    V erase(const int tid, const K& key) {\r\n        return tree->erase(tid, key);\r\n    }\r\n    V find(const int tid, const K& key) {\r\n        return tree->find(tid, key);\r\n    }\r\n    int rangeQuery(const int tid, const K& lo, const K& hi, K * const resultKeys, V * const resultValues) {\r\n        error(\"rangeQuery not implemented for this data structure\");\r\n    }\r\n    /**\r\n     * Sequential operation to get the number of keys in the set\r\n     */\r\n    int getSize() {\r\n        return tree->getSize();\r\n    }\r\n    void printSummary() {\r\n        tree->printSummary();\r\n    }\r\n    long long getKeyChecksum() {\r\n        return tree->getKeyChecksum();\r\n    }\r\n    bool validateStructure() {\r\n        return tree->validateStructure();\r\n    }\r\n    void printObjectSizes() {\r\n        std::cout<<\"sizes: node=\"\r\n                 <<(sizeof(node_t<K, V>))\r\n                 <<std::endl;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "datastructures/trevor_brown_natarajan/ds/natarajan_ext_bst_lf/natarajan_ext_bst_lf_stage1.h",
    "content": "/*A Lock Free Binary Search Tree\r\n \r\n * File:\r\n *   wfrbt.cpp\r\n * Author(s):\r\n *   Aravind Natarajan <natarajan.aravind@gmail.com>\r\n * Description:\r\n *   A Lock Free Binary Search Tree\r\n *\r\n * Copyright (c) 2013-2014.\r\n *\r\n * This program is free software; you can redistribute it and/or\r\n * modify it under the terms of the GNU General Public License\r\n * as published by the Free Software Foundation, version 2\r\n * of the License.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n * GNU General Public License for more details.\r\n\r\nPlease cite our PPoPP 2014 paper - Fast Concurrent Lock-Free Binary Search Trees by Aravind Natarajan and Neeraj Mittal if you use our code in your experiments\t\r\n\r\nFeatures:\r\n1. Insert operations directly install their window without injecting the operation into the tree. They help any conflicting operation at the injection point, \r\nbefore executing their window txn.\r\n2. Delete operations are the same as that of the original algorithm.\r\n \r\n */\r\n\r\n/* \r\n * File:   wfrbt.h\r\n * Author: Maya Arbel-Raviv\r\n *\r\n * Created on June 8, 2017, 10:45 AM\r\n */\r\n\r\n/*\r\n * Heavily edited by Trevor Brown (me [at] tbrown [dot] pro).\r\n * (Late 2017, early 2018.)\r\n * \r\n * - Converted to a class and added proper memory reclamation.\r\n * - Fixed a bug: atomic_ops types don't contain \"volatile,\" so the original\r\n *       implementation behaved erroneously under high contention.\r\n * - Fixed the original implementation's erroneous memory reclamation,\r\n *       which would leak many nodes.\r\n */\r\n\r\n#ifndef NATARAJAN_EXT_BST_LF_H\r\n#define NATARAJAN_EXT_BST_LF_H\r\n\r\n#include \"errors.h\"\r\n#include \"record_manager.h\"\r\n#include \"atomic_ops.h\"\r\n\r\n#if     (INDEX_STRUCT == IDX_NATARAJAN_EXT_BST_LF) \r\n#elif   (INDEX_STRUCT == IDX_NATARAJAN_EXT_BST_LF_BASELINE)\r\n#error cannot support baseline with int keys and no value.  \r\n#else\r\n#error\r\n#endif\r\n\r\n// Most of these macros are not used in this algorithm\r\n\r\n#define MARK_BIT 1\r\n#define FLAG_BIT 0\r\n\r\n#define atomic_cas_full(addr, old_val, new_val) __sync_bool_compare_and_swap(addr, old_val, new_val);\r\n#define create_child_word(addr, mark, flag) (((uintptr_t) addr << 2) + (mark << 1) + (flag))\r\n#define is_marked(x) ( ((x >> 1) & 1)  == 1 ? true:false)\r\n#define is_flagged(x) ( (x & 1 )  == 1 ? true:false)\r\n#define get_addr(x) (x >> 2)\r\n#define add_mark_bit(x) (x + 4UL)\r\n#define is_free(x) (((x) & 3) == 0? true:false)\r\n\r\nenum {\r\n    INSERT, DELETE\r\n};\r\n\r\nenum {\r\n    UNMARK, MARK\r\n};\r\n\r\nenum {\r\n    UNFLAG, FLAG\r\n};\r\n\r\ntypedef uintptr_t Word;\r\n\r\ntemplate <typename skey_t, typename sval_t>\r\nstruct node_t {\r\n    union {\r\n        struct {\r\n            skey_t key;\r\n            sval_t value;\r\n            volatile AO_double_t child;\r\n        };\r\n#ifdef MIN_NODE_SIZE\r\n        char bytes[MIN_NODE_SIZE];\r\n#endif\r\n    };\r\n};\r\n\r\n\r\ntemplate <typename skey_t, typename sval_t>\r\nstruct seekRecord_t {\r\n    skey_t leafKey;\r\n    sval_t leafValue;\r\n    struct node_t<skey_t, sval_t>* leaf;\r\n    struct node_t<skey_t, sval_t>* parent;\r\n    AO_t pL;\r\n    bool isLeftL; // is L the left child of P?\r\n    struct node_t<skey_t, sval_t>* lum;\r\n    AO_t lumC;\r\n    bool isLeftUM; // is  last unmarked node's child on access path the left child of  the last unmarked node?\r\n};\r\n\r\ntemplate <typename skey_t, typename sval_t>\r\nstruct thread_data_t {\r\n    int id;\r\n    struct node_t<skey_t, sval_t>* rootOfTree;\r\n    seekRecord_t<skey_t, sval_t>* sr; // seek record\r\n    seekRecord_t<skey_t, sval_t> * ssr; // secondary seek record\r\n};\r\n\r\n//static __thread thread_data_t<skey_t, sval_t> * data = NULL;\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare = less<skey_t> >\r\nclass natarajan_ext_bst_lf {\r\nprivate:\r\n    RecMgr * const recmgr;\r\n    Compare cmp;\r\n    node_t<skey_t, sval_t> * root;\r\n\r\n    seekRecord_t<skey_t, sval_t>* insseek(thread_data_t<skey_t, sval_t>* data, skey_t key, int op);\r\n    seekRecord_t<skey_t, sval_t>* delseek(thread_data_t<skey_t, sval_t>* data, skey_t key, int op);\r\n    seekRecord_t<skey_t, sval_t>* secondary_seek(thread_data_t<skey_t, sval_t>* data, skey_t key, seekRecord_t<skey_t, sval_t>* sr);\r\n    sval_t delete_node(thread_data_t<skey_t, sval_t>* data, skey_t key);\r\n    sval_t insertIfAbsent(thread_data_t<skey_t, sval_t>* data, skey_t key, sval_t value);\r\n    sval_t search(thread_data_t<skey_t, sval_t>* data, skey_t key);\r\n    int help_conflicting_operation (thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R);\r\n    int inject(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R, int op);\r\n    int perform_one_delete_window_operation(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R, skey_t key);\r\n    int perform_one_insert_window_operation(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R, skey_t newKey, sval_t value);\r\n\r\n    void retireDeletedNodes(thread_data_t<skey_t, sval_t>* data, node_t<skey_t, sval_t> * node, node_t<skey_t, sval_t> * targetNode, bool pointerFlagged = false);\r\n    \r\n    int init[MAX_TID_POW2] = {0,};\r\npublic:\r\n    const skey_t MAX_KEY;\r\n    const sval_t NO_VALUE;\r\n    const int NUM_PROCESSES;\r\n\r\n    natarajan_ext_bst_lf(const skey_t& _MAX_KEY, const sval_t& _NO_VALUE, const int numProcesses)\r\n    : MAX_KEY(_MAX_KEY)\r\n    , NO_VALUE(_NO_VALUE)\r\n    , NUM_PROCESSES(numProcesses)\r\n    , recmgr(new RecMgr(numProcesses, SIGQUIT)) {\r\n        const int tid = 0;\r\n        initThread(tid);\r\n        \r\n        cmp = Compare();\r\n\r\n        recmgr->enterQuiescentState(tid); // block crash recovery signal for this thread, and enter an initial quiescent state.\r\n\r\n        root = recmgr->template allocate<node_t<skey_t, sval_t>>(tid);\r\n        node_t<skey_t, sval_t> * newLC = recmgr->template allocate<node_t<skey_t, sval_t>>(tid);\r\n        node_t<skey_t, sval_t> * newRC = recmgr->template allocate<node_t<skey_t, sval_t>>(tid);\r\n\r\n        memset(newLC, 0, sizeof (struct node_t<skey_t, sval_t>));\r\n        memset(newRC, 0, sizeof (struct node_t<skey_t, sval_t>));\r\n\r\n        root->key =  _MAX_KEY;\r\n        newLC->key = _MAX_KEY - 1;\r\n        newRC->key = _MAX_KEY;\r\n\r\n        root->value = NO_VALUE;\r\n        newLC->value = NO_VALUE;\r\n        newRC->value = NO_VALUE;\r\n\r\n        root->child.AO_val1 = create_child_word(newLC, UNMARK, UNFLAG);\r\n        root->child.AO_val2 = create_child_word(newRC, UNMARK, UNFLAG);\r\n    }\r\n\r\n    void freeSubtree(node_t<skey_t, sval_t> * curr) {\r\n        const int tid = 0;\r\n        if (curr == NULL) return;\r\n        node_t<skey_t, sval_t> * left = get_left(curr);\r\n        node_t<skey_t, sval_t> * right = get_right(curr);\r\n        recmgr->deallocate(tid, curr);\r\n        freeSubtree(left);\r\n        freeSubtree(right);\r\n    }\r\n    \r\n    ~natarajan_ext_bst_lf() {\r\n        freeSubtree(root);\r\n        delete recmgr;\r\n    }\r\n\r\n    void initThread(const int tid) {\r\n        if (init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        recmgr->initThread(tid);\r\n    }\r\n\r\n    void deinitThread(const int tid) {\r\n        if (!init[tid]) return; else init[tid] = !init[tid];\r\n\r\n        recmgr->deinitThread(tid);\r\n    }\r\n\r\n    sval_t insertIfAbsent(const int tid, skey_t key, sval_t item) { \r\n        assert(cmp(key, MAX_KEY-1));\r\n        thread_data_t<skey_t, sval_t> data; \r\n        seekRecord_t<skey_t, sval_t> sr; \r\n        seekRecord_t<skey_t, sval_t> ssr; \r\n        data.id = tid;\r\n        data.sr = &sr;\r\n        data.ssr = &ssr;\r\n        data.rootOfTree = root; \r\n        return insertIfAbsent(&data,key,item);\r\n    }\r\n\r\n    sval_t erase(const int tid, skey_t key) { \r\n        assert(cmp(key, MAX_KEY-1));\r\n        thread_data_t<skey_t, sval_t> data; \r\n        seekRecord_t<skey_t, sval_t> sr; \r\n        seekRecord_t<skey_t, sval_t> ssr; \r\n        data.id = tid;\r\n        data.sr = &sr;\r\n        data.ssr = &ssr;\r\n        data.rootOfTree = root;\r\n        return delete_node(&data,key);\r\n    }\r\n\r\n    sval_t find(const int tid, skey_t key) {\r\n        thread_data_t<skey_t, sval_t> data; \r\n        seekRecord_t<skey_t, sval_t> sr; \r\n        seekRecord_t<skey_t, sval_t> ssr; \r\n        data.id = tid;\r\n        data.sr = &sr;\r\n        data.ssr = &ssr;\r\n        data.rootOfTree = root;\r\n        return search(&data,key);\r\n    }\r\n\r\n    node_t<skey_t, sval_t> * get_root() {\r\n        return root;\r\n    }\r\n\r\n    node_t<skey_t, sval_t> * get_left(node_t<skey_t, sval_t> * curr) {\r\n        return (node_t<skey_t, sval_t> *)get_addr(curr->child.AO_val1); \r\n    }\r\n\r\n    node_t<skey_t, sval_t> * get_right(node_t<skey_t, sval_t> * curr) {\r\n        return (node_t<skey_t, sval_t> *)get_addr(curr->child.AO_val2); \r\n    }\r\n    \r\n    long long getKeyChecksum(node_t<skey_t, sval_t> * curr) {\r\n        if (curr == NULL) return 0;\r\n        node_t<skey_t, sval_t> * left = get_left(curr);\r\n        node_t<skey_t, sval_t> * right = get_right(curr);\r\n        if (!left && !right) return (long long) curr->key; // leaf\r\n        return getKeyChecksum(left) + getKeyChecksum(right);\r\n    }\r\n    \r\n    long long getKeyChecksum() {\r\n        return getKeyChecksum(get_left(get_left(root)));\r\n    }\r\n    \r\n    long long getSize(node_t<skey_t, sval_t> * curr) {\r\n        if (curr == NULL) return 0;\r\n        node_t<skey_t, sval_t> * left = get_left(curr);\r\n        node_t<skey_t, sval_t> * right = get_right(curr);\r\n        if (!left && !right) return 1; // leaf\r\n        return getSize(left) + getSize(right);\r\n    }\r\n    \r\n    bool validateStructure() {\r\n        return true;\r\n    }\r\n    \r\n    long long getSize() {\r\n        return getSize(get_left(get_left(root)));\r\n    }\r\n    \r\n    long long getSizeInNodes(node_t<skey_t, sval_t> * const curr) {\r\n        if (curr == NULL) return 0;\r\n        return 1 + getSizeInNodes(get_left(curr))\r\n                 + getSizeInNodes(get_right(curr));\r\n    }\r\n    \r\n    long long getSizeInNodes() {\r\n        return getSizeInNodes(root);\r\n    }    \r\n\r\n    void printSummary() {\r\n        stringstream ss;\r\n        ss<<getSizeInNodes()<<\" nodes in tree\";\r\n        std::cout<<ss.str()<<std::endl;\r\n\r\n        recmgr->printStatus();\r\n    }\r\n};\r\n#endif /* NATARAJAN_EXT_BST_LF_H */\r\n"
  },
  {
    "path": "datastructures/trevor_brown_natarajan/ds/natarajan_ext_bst_lf/natarajan_ext_bst_lf_stage2_impl.h",
    "content": "/*A Lock Free Binary Search Tree\r\n \r\n * File:\r\n *   wfrbt.cpp\r\n * Author(s):\r\n *   Aravind Natarajan <natarajan.aravind@gmail.com>\r\n * Description:\r\n *   A Lock Free Binary Search Tree\r\n *\r\n * Copyright (c) 2013-2014.\r\n *\r\n * This program is free software; you can redistribute it and/or\r\n * modify it under the terms of the GNU General Public License\r\n * as published by the Free Software Foundation, version 2\r\n * of the License.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n * GNU General Public License for more details.\r\n\r\nPlease cite our PPoPP 2014 paper - Fast Concurrent Lock-Free Binary Search Trees by Aravind Natarajan and Neeraj Mittal if you use our code in your experiments\t\r\n\r\nFeatures:\r\n1. Insert operations directly install their window without injecting the operation into the tree. They help any conflicting operation at the injection point, \r\nbefore executing their window txn.\r\n2. Delete operations are the same as that of the original algorithm.\r\n \r\n */\r\n\r\n/* \r\n * File:   wfrbt_impl.h\r\n * Author: Maya Arbel-Raviv\r\n *\r\n * Created on June 8, 2017, 10:45 AM\r\n */\r\n\r\n/*\r\n * Heavily edited by Trevor Brown (me [at] tbrown [dot] pro).\r\n * (Late 2017, early 2018.)\r\n * \r\n * - Converted to a class and added proper memory reclamation.\r\n * - Fixed a bug: atomic_ops types don't contain \"volatile,\" so the original\r\n *       implementation behaved erroneously under high contention.\r\n * - Fixed the original implementation's erroneous memory reclamation,\r\n *       which would leak many nodes.\r\n */\r\n\r\n#ifndef NATARAJAN_EXT_BST_LF_IMPL_H\r\n#define NATARAJAN_EXT_BST_LF_IMPL_H\r\n\r\n#include \"natarajan_ext_bst_lf_stage1.h\"\r\n\r\nstatic inline bool SetBit(volatile size_t *array, int bit) {\r\n    bool flag;\r\n    __asm__ __volatile__(\"lock bts %2,%1; setb %0\" : \"=q\" (flag) : \"m\" (*array), \"r\" (bit));\r\n    return flag;\r\n}\r\n\r\nstatic bool mark_Node(volatile AO_t * word) {\r\n    return (SetBit(word, MARK_BIT));\r\n}\r\n\r\nstatic volatile AO_t stop = 0;\r\nstatic volatile AO_t stop2 = 0;\r\n\r\n//long total_insert = 0;\r\n\r\n/* STRUCTURES */\r\nenum {\r\n    Front, Back\r\n};\r\n\r\n//long blackCount = -1;\r\n//long leafNodes = 0;\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nseekRecord_t<skey_t, sval_t>* natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::insseek(thread_data_t<skey_t, sval_t>* data, skey_t key, int op) {\r\n\r\n    node_t<skey_t, sval_t> * gpar = NULL; // last node (ancestor of parent on access path) whose child pointer field is unmarked\r\n    node_t<skey_t, sval_t> * par = data->rootOfTree;\r\n    node_t<skey_t, sval_t> * leaf;\r\n    node_t<skey_t, sval_t> * leafchild;\r\n\r\n\r\n    AO_t parentPointerWord = (size_t) NULL; // contents in gpar\r\n    AO_t leafPointerWord = par->child.AO_val1; // contents in par. Tree has two imaginary keys \\inf_{1} and \\inf_{2} which are larger than all other keys. \r\n    AO_t leafchildPointerWord; // contents in leaf\r\n\r\n    bool isparLC = false; // is par the left child of gpar\r\n    bool isleafLC = true; // is leaf the left child of par\r\n    bool isleafchildLC; // is leafchild the left child of leaf\r\n\r\n\r\n    leaf = (node_t<skey_t, sval_t> *)get_addr(leafPointerWord);\r\n    if (cmp(key, leaf->key)) {\r\n        leafchildPointerWord = leaf->child.AO_val1;\r\n        isleafchildLC = true;\r\n\r\n    } else {\r\n        leafchildPointerWord = leaf->child.AO_val2;\r\n        isleafchildLC = false;\r\n    }\r\n\r\n    leafchild = (node_t<skey_t, sval_t> *)get_addr(leafchildPointerWord);\r\n\r\n\r\n\r\n    while (leafchild != NULL) {\r\n\r\n\r\n\r\n        if (!is_marked(leafPointerWord)) {\r\n            gpar = par;\r\n            parentPointerWord = leafPointerWord;\r\n            isparLC = isleafLC;\r\n        }\r\n\r\n        par = leaf;\r\n        leafPointerWord = leafchildPointerWord;\r\n        isleafLC = isleafchildLC;\r\n\r\n        leaf = leafchild;\r\n\r\n\r\n        if (cmp(key, leaf->key)) {\r\n            leafchildPointerWord = leaf->child.AO_val1;\r\n            isleafchildLC = true;\r\n        } else {\r\n            leafchildPointerWord = leaf->child.AO_val2;\r\n            isleafchildLC = false;\r\n        }\r\n\r\n        leafchild = (node_t<skey_t, sval_t> *)get_addr(leafchildPointerWord);\r\n\r\n    }\r\n\r\n//    if (key == leaf->key) {\r\n//        // key matches that being inserted\t\r\n//        return NULL;\r\n//    }\r\n\r\n    seekRecord_t<skey_t, sval_t>* R = data->sr;\r\n    R->leafKey = leaf->key;\r\n    R->leafValue = leaf->value;\r\n    R->parent = par;\r\n    R->pL = leafPointerWord;\r\n    R->isLeftL = isleafLC;\r\n    R->lum = gpar;\r\n    R->lumC = parentPointerWord;\r\n    R->isLeftUM = isparLC;\r\n    return R;\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nseekRecord_t<skey_t, sval_t>* natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::delseek(thread_data_t<skey_t, sval_t>* data, skey_t key, int op) {\r\n    node_t<skey_t, sval_t> * gpar = NULL; // last node (ancestor of parent on access path) whose child pointer field is unmarked\r\n    node_t<skey_t, sval_t> * par = data->rootOfTree;\r\n    node_t<skey_t, sval_t> * leaf;\r\n    node_t<skey_t, sval_t> * leafchild;\r\n\r\n\r\n    AO_t parentPointerWord = (AO_t) NULL; // contents in gpar\r\n    AO_t leafPointerWord = par->child.AO_val1; // contents in par. Tree has two imaginary keys \\inf_{1} and \\inf_{2} which are larger than all other keys. \r\n    AO_t leafchildPointerWord; // contents in leaf\r\n\r\n    bool isparLC = false; // is par the left child of gpar\r\n    bool isleafLC = true; // is leaf the left child of par\r\n    bool isleafchildLC; // is leafchild the left child of leaf\r\n\r\n\r\n    leaf = (node_t<skey_t, sval_t> *)get_addr(leafPointerWord);\r\n    if (cmp(key, leaf->key)) {\r\n        leafchildPointerWord = leaf->child.AO_val1;\r\n        isleafchildLC = true;\r\n\r\n    } else {\r\n        leafchildPointerWord = leaf->child.AO_val2;\r\n        isleafchildLC = false;\r\n    }\r\n\r\n    leafchild = (node_t<skey_t, sval_t> *)get_addr(leafchildPointerWord);\r\n\r\n\r\n\r\n    while (leafchild != NULL) {\r\n\r\n\r\n\r\n        if (!is_marked(leafPointerWord)) {\r\n            gpar = par;\r\n            parentPointerWord = leafPointerWord;\r\n            isparLC = isleafLC;\r\n        }\r\n\r\n        par = leaf;\r\n        leafPointerWord = leafchildPointerWord;\r\n        isleafLC = isleafchildLC;\r\n\r\n        leaf = leafchild;\r\n\r\n\r\n        if (cmp(key, leaf->key)) {\r\n            leafchildPointerWord = leaf->child.AO_val1;\r\n            isleafchildLC = true;\r\n        } else {\r\n            leafchildPointerWord = leaf->child.AO_val2;\r\n            isleafchildLC = false;\r\n        }\r\n\r\n        leafchild = (node_t<skey_t, sval_t> *)get_addr(leafchildPointerWord);\r\n\r\n    }\r\n\r\n    // op = DELETE\r\n    if (key != leaf->key) {\r\n        // key is not found in the tree.\r\n        return NULL;\r\n    }\r\n\r\n    seekRecord_t<skey_t, sval_t>* R = data->sr;\r\n    R->leafKey = leaf->key;\r\n    R->leafValue = leaf->value;\r\n    R->parent = par;\r\n    R->leaf = leaf;\r\n    R->pL = leafPointerWord;\r\n    R->isLeftL = isleafLC;\r\n    R->lum = gpar;\r\n    R->lumC = parentPointerWord;\r\n    R->isLeftUM = isparLC;\r\n\r\n\r\n\r\n    return R;\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nseekRecord_t<skey_t, sval_t>* natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::secondary_seek(thread_data_t<skey_t, sval_t>* data, skey_t key, seekRecord_t<skey_t, sval_t>* sr) {\r\n\r\n    //std::cout << \"sseek\" << std::endl;\r\n    node_t<skey_t, sval_t> * flaggedLeaf = (node_t<skey_t, sval_t> *)get_addr(sr->pL);\r\n    node_t<skey_t, sval_t> * gpar = NULL; // last node (ancestor of parent on access path) whose child pointer field is unmarked\r\n    node_t<skey_t, sval_t> * par = data->rootOfTree;\r\n    node_t<skey_t, sval_t> * leaf;\r\n    node_t<skey_t, sval_t> * leafchild;\r\n\r\n\r\n    AO_t parentPointerWord = (AO_t) NULL; // contents in gpar\r\n    AO_t leafPointerWord = par->child.AO_val1; // contents in par. Tree has two imaginary keys \\inf_{1} and \\inf_{2} which are larger than all other keys. \r\n    AO_t leafchildPointerWord; // contents in leaf\r\n\r\n    bool isparLC = false; // is par the left child of gpar\r\n    bool isleafLC = true; // is leaf the left child of par\r\n    bool isleafchildLC; // is leafchild the left child of leaf\r\n\r\n\r\n    leaf = (node_t<skey_t, sval_t> *)get_addr(leafPointerWord);\r\n    if (cmp(key, leaf->key)) {\r\n        leafchildPointerWord = leaf->child.AO_val1;\r\n        isleafchildLC = true;\r\n\r\n    } else {\r\n        leafchildPointerWord = leaf->child.AO_val2;\r\n        isleafchildLC = false;\r\n    }\r\n\r\n    leafchild = (node_t<skey_t, sval_t> *)get_addr(leafchildPointerWord);\r\n\r\n\r\n\r\n    while (leafchild != NULL) {\r\n\r\n\r\n\r\n        if (!is_marked(leafPointerWord)) {\r\n            gpar = par;\r\n            parentPointerWord = leafPointerWord;\r\n            isparLC = isleafLC;\r\n        }\r\n\r\n        par = leaf;\r\n        leafPointerWord = leafchildPointerWord;\r\n        isleafLC = isleafchildLC;\r\n\r\n        leaf = leafchild;\r\n\r\n\r\n        if (cmp(key, leaf->key)) {\r\n            leafchildPointerWord = leaf->child.AO_val1;\r\n            isleafchildLC = true;\r\n        } else {\r\n            leafchildPointerWord = leaf->child.AO_val2;\r\n            isleafchildLC = false;\r\n        }\r\n\r\n        leafchild = (node_t<skey_t, sval_t> *)get_addr(leafchildPointerWord);\r\n\r\n    }\r\n\r\n\r\n\r\n    if (!is_flagged(leafPointerWord) || (leaf != flaggedLeaf)) {\r\n        // operation has been completed by another process.\r\n        return NULL;\r\n    }\r\n\r\n    seekRecord_t<skey_t, sval_t>* R = data->ssr;\r\n\r\n    R->leafKey = leaf->key;\r\n    R->parent = par;\r\n    R->pL = leafPointerWord;\r\n    R->isLeftL = isleafLC;\r\n    R->lum = gpar;\r\n    R->lumC = parentPointerWord;\r\n    R->isLeftUM = isparLC;\r\n    return R;\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nsval_t natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::search(thread_data_t<skey_t, sval_t>* data, skey_t key) {\r\n    recmgr->leaveQuiescentState(data->id);\r\n    node_t<skey_t, sval_t> * cur = (node_t<skey_t, sval_t> *)get_addr(data->rootOfTree->child.AO_val1);\r\n    skey_t lastKey = 0; \r\n    node_t<skey_t, sval_t> * lastNode = NULL;\r\n    while (cur != NULL) {\r\n        lastKey = cur->key;\r\n        lastNode = cur;\r\n        cur = (cmp(key, lastKey) ? (node_t<skey_t, sval_t> *)get_addr(cur->child.AO_val1) : (node_t<skey_t, sval_t> *)get_addr(cur->child.AO_val2));\r\n    }\r\n    if (key == lastKey) {\r\n        recmgr->enterQuiescentState(data->id);\r\n        return lastNode->value;\r\n    }\r\n    recmgr->enterQuiescentState(data->id);\r\n    return NO_VALUE;\r\n}\r\n\r\n//-------------------------------------------------------------------------------------------------------------------------------------------------------\r\n//-------------------------------------------------------------------------------------------------------------------------------------------------------\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nvoid natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::retireDeletedNodes(thread_data_t<skey_t, sval_t>* data, node_t<skey_t, sval_t> * node, node_t<skey_t, sval_t> * targetNode, bool pointerFlagged) {\r\n    // traverse from node, retiring everything we deleted\r\n    // (that is: every leaf pointed to by a flagged pointer,\r\n    //  and every internal node with a flagged pointer.)\r\n    if (node == NULL) return;\r\n    if (node == targetNode) return; // we reached the end of the nodes we deleted\r\n    if ((node_t<skey_t, sval_t> *) node->child.AO_val1 == NULL) {\r\n        // node is a leaf\r\n        if (pointerFlagged) {\r\n            recmgr->retire(data->id, node);\r\n        }\r\n        return;\r\n    }\r\n    // node is internal\r\n    if (is_flagged(node->child.AO_val1) || is_flagged(node->child.AO_val2)) {\r\n        recmgr->retire(data->id, node);\r\n        if (!is_free(node->child.AO_val1)) retireDeletedNodes(data, (node_t<skey_t, sval_t> *) get_addr(node->child.AO_val1), targetNode, is_flagged(node->child.AO_val1));\r\n        if (!is_free(node->child.AO_val2)) retireDeletedNodes(data, (node_t<skey_t, sval_t> *) get_addr(node->child.AO_val2), targetNode, is_flagged(node->child.AO_val2));\r\n    }\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nint natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::help_conflicting_operation(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R) {\r\n    int result;\r\n    node_t<skey_t, sval_t> * target = NULL;\r\n    if (is_flagged(R->pL)) {\r\n        // leaf node is flagged for deletion by another process.\r\n\r\n        //1. mark sibling of leaf node for deletion and then read its contents.\r\n\r\n        AO_t pS;\r\n\r\n        if (R->isLeftL) {\r\n            // L is the left child of P\r\n            mark_Node(&R->parent->child.AO_val2);\r\n            pS = R->parent->child.AO_val2;\r\n\r\n        } else {\r\n            mark_Node(&R->parent->child.AO_val1);\r\n            pS = R->parent->child.AO_val1;\r\n        }\r\n\r\n        // 2. Execute cas on the last unmarked node to remove the \r\n        // if pS is flagged, propagate it. \r\n        AO_t newWord;\r\n\r\n        if (is_flagged(pS)) {\r\n            newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(pS), UNMARK, FLAG);\r\n        } else {\r\n            newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(pS), UNMARK, UNFLAG);\r\n        }\r\n        target = (node_t<skey_t, sval_t> *) get_addr(pS);\r\n\r\n        if (R->isLeftUM) {\r\n            result = atomic_cas_full(&R->lum->child.AO_val1, R->lumC, newWord);\r\n        } else {\r\n            result = atomic_cas_full(&R->lum->child.AO_val2, R->lumC, newWord);\r\n        }\r\n\r\n    } else {\r\n        // leaf node is marked for deletion by another process.\r\n        // Note that leaf is not flagged, as it will be taken care of in the above case.\r\n\r\n        AO_t newWord;\r\n\r\n        if (is_flagged(R->pL)) {\r\n            newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(R->pL), UNMARK, FLAG);\r\n        } else {\r\n            newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(R->pL), UNMARK, UNFLAG);\r\n        }\r\n\r\n        target = (node_t<skey_t, sval_t> *) get_addr(R->pL);\r\n\r\n        if (R->isLeftUM) {\r\n            result = atomic_cas_full(&R->lum->child.AO_val1, R->lumC, newWord);\r\n        } else {\r\n            result = atomic_cas_full(&R->lum->child.AO_val2, R->lumC, newWord);\r\n        }\r\n    }\r\n\r\n    if (result) {\r\n        retireDeletedNodes(data, (node_t<skey_t, sval_t> *) get_addr(R->lumC), target);\r\n    }\r\n    \r\n    return result;    \r\n}\r\n\r\n//-------------------------------------------------------------------------------------------------------------------------------------------------------\r\n//-------------------------------------------------------------------------------------------------------------------------------------------------------\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nint natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::inject(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R, int op) {\r\n\r\n    // pL is free\t\t\r\n    //1. Flag L\t\t\r\n    AO_t newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(R->pL), UNMARK, FLAG);\r\n    int result;\r\n    if (R->isLeftL) {\r\n        result = atomic_cas_full(&R->parent->child.AO_val1, R->pL, newWord);\r\n\r\n    } else {\r\n        result = atomic_cas_full(&R->parent->child.AO_val2, R->pL, newWord);\r\n    }\r\n    return result;\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nsval_t natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::insertIfAbsent(thread_data_t<skey_t, sval_t>* data, skey_t key, sval_t value) {\r\n    int injectResult;\r\n//    int fasttry = 0;\r\n    while (true) {\r\n        recmgr->leaveQuiescentState(data->id);\r\n        seekRecord_t<skey_t, sval_t>* R = insseek(data, key, INSERT);\r\n//        fasttry++;\r\n        if (R->leafKey == key) {\r\n//            if (fasttry == 1) {\r\n                return R->leafValue;\r\n//            } else {\r\n//                return NO_VALUE;\r\n//            }\r\n        }\r\n        if (!is_free(R->pL)) {\r\n            help_conflicting_operation(data, R);\r\n\r\n            recmgr->enterQuiescentState(data->id);\r\n            continue;\r\n        }\r\n        // key not present in the tree. Insert\t\t\r\n        injectResult = perform_one_insert_window_operation(data, R, key, value);\r\n        if (injectResult == 1) {\r\n            // Operation injected and executed\t\t\t\r\n            recmgr->enterQuiescentState(data->id);\r\n            return NO_VALUE;\r\n        }\r\n        recmgr->enterQuiescentState(data->id);\r\n    }\r\n    // execute insert window operation.\t\t\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nsval_t natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::delete_node(thread_data_t<skey_t, sval_t>* data, skey_t key) {\r\n\r\n    int injectResult;\r\n    sval_t retval = NO_VALUE;\r\n    while (true) {\r\n        recmgr->leaveQuiescentState(data->id);\r\n        seekRecord_t<skey_t, sval_t>* R = delseek(data, key, DELETE);\r\n        if (R == NULL) {\r\n            recmgr->enterQuiescentState(data->id);\r\n            return retval;\r\n        }\r\n        // key is present in the tree. Inject operation into the tree\t\t\r\n        if (!is_free(R->pL)) {\r\n\r\n            help_conflicting_operation(data, R);\r\n\r\n            recmgr->enterQuiescentState(data->id);\r\n            continue;\r\n        }\r\n        injectResult = inject(data, R, DELETE);\r\n        if (injectResult == 1) {\r\n            retval = R->leafValue;\r\n//            recmgr->retire(data->id, R->leaf); // if we won consensus and injected the operation, we retire the replaced leaf. (the replaced parent is retired by the guy who marks the sibling pointer in the parent.)\r\n            // Operation injected\r\n            //data->numActualDelete++;\r\n            int res = perform_one_delete_window_operation(data, R, key);\r\n            if (res == 1) {\r\n                // operation successfully executed.\r\n                recmgr->enterQuiescentState(data->id);\r\n                return retval;\r\n            } else {\r\n                // window transaction could not be executed.\r\n                // perform secondary seek.\t\t\t\t\r\n                while (true) {\r\n                    R = secondary_seek(data, key, R);\r\n                    if (R == NULL) {\r\n                        // flagged leaf not found. Operation has been executed by some other process.\r\n                        recmgr->enterQuiescentState(data->id);\r\n                        return retval;\r\n                    }\r\n                    res = perform_one_delete_window_operation(data, R, key);\r\n                    if (res == 1) {\r\n                        recmgr->enterQuiescentState(data->id);\r\n                        return retval;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        recmgr->enterQuiescentState(data->id);\r\n        // otherwise, operation was not injected. Restart.\r\n    }\r\n}\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nint natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::perform_one_insert_window_operation(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R, skey_t newKey, sval_t value) {\r\n    node_t<skey_t, sval_t> * newInt;\r\n    node_t<skey_t, sval_t> * newLeaf;\r\n    //\t\tif(data->recycledNodes.empty()){\t\t\r\n//    node_t<skey_t, sval_t> * allocedNodeArr = (node_t<skey_t, sval_t> *)malloc(2 * sizeof (struct node_t<skey_t, sval_t>)); // new pointerNode_t[2];\r\n//    newInt = &allocedNodeArr[0];\r\n//    newLeaf = &allocedNodeArr[1];\r\n    newInt = recmgr->template allocate<node_t<skey_t, sval_t>>(data->id);\r\n    if (newInt == NULL) {\r\n        error(\"out of memory\");\r\n    }\r\n#ifdef __HANDLE_STATS\r\n    GSTATS_APPEND(data->id, node_allocated_addresses, (long long) newInt);\r\n#endif\r\n    newLeaf = recmgr->template allocate<node_t<skey_t, sval_t>>(data->id);\r\n    if (newLeaf == NULL) {\r\n        error(\"out of memory\");\r\n    }\r\n#ifdef __HANDLE_STATS\r\n    GSTATS_APPEND(data->id, node_allocated_addresses, (long long) newLeaf);\r\n#endif\r\n\r\n    /*\t\t}\t\r\n                    else{\r\n                            // reuse memory of previously allocated nodes.\r\n                            newInt = data->recycledNodes.back();\r\n                            data->recycledNodes.pop_back();\t\t\t\r\n                            newLeaf = data->recycledNodes.back();\r\n                            data->recycledNodes.pop_back();\r\n                    }\r\n     */\r\n    newLeaf->child.AO_val1 = (size_t) NULL;\r\n    newLeaf->child.AO_val2 = (size_t) NULL;\r\n    newLeaf->key = newKey;\r\n    newLeaf->value = value;\r\n    node_t<skey_t, sval_t> * existLeaf = (node_t<skey_t, sval_t> *)get_addr(R->pL);\r\n\r\n    skey_t existKey = R->leafKey;\r\n\r\n\r\n    if (cmp(newKey, existKey)) {\r\n        // key is to be inserted on lchild\r\n        newInt->key = existKey;\r\n        newInt->child.AO_val1 = create_child_word(newLeaf, 0, 0);\r\n        newInt->child.AO_val2 = create_child_word(existLeaf, 0, 0);\r\n\r\n    } else {\r\n        // key is to be inserted on rchild\r\n        newInt->key = newKey;\r\n        newInt->child.AO_val2 = create_child_word(newLeaf, 0, 0);\r\n        newInt->child.AO_val1 = create_child_word(existLeaf, 0, 0);\r\n\r\n    }\r\n\r\n    // cas to replace window\t\t\r\n    AO_t newCasField;\r\n    newCasField = create_child_word(newInt, UNMARK, UNFLAG);\r\n    int result;\r\n\r\n    if (R->isLeftL) {\r\n        result = atomic_cas_full(&R->parent->child.AO_val1, R->pL, newCasField);\r\n    } else {\r\n        result = atomic_cas_full(&R->parent->child.AO_val2, R->pL, newCasField);\r\n    }\r\n    if (result == 1) {\r\n        // successfully inserted.\t\t\t\r\n        //data->numInsert++;\r\n        return 1;\r\n    } else {\r\n        // reuse data and pointer nodes\t\t\t\t\r\n        recmgr->deallocate(data->id, newInt);\r\n        recmgr->deallocate(data->id, newLeaf);\r\n        //data->recycledNodes.push_back(newInt);\r\n        //data->recycledNodes.push_back(newLeaf);\r\n        return 0;\r\n\r\n    }\r\n\r\n}\r\n\r\n/*************************************************************************************************/\r\n\r\ntemplate <typename skey_t, typename sval_t, class RecMgr, class Compare>\r\nint natarajan_ext_bst_lf<skey_t, sval_t, RecMgr, Compare>::perform_one_delete_window_operation(thread_data_t<skey_t, sval_t>* data, seekRecord_t<skey_t, sval_t>* R, skey_t key) {\r\n    // mark sibling.\r\n    AO_t pS;\r\n    bool markResult = 0;\r\n    if (R->isLeftL) {\r\n        // L is the left child of P\r\n        markResult = mark_Node(&R->parent->child.AO_val2);\r\n        pS = R->parent->child.AO_val2;\r\n\r\n    } else {\r\n        markResult = mark_Node(&R->parent->child.AO_val1);\r\n        pS = R->parent->child.AO_val1;\r\n    }\r\n    //cout<<\"key=\"<<R->leafKey<<\" markResult=\"<<markResult<<std::endl;\r\n//    if (!markResult) {\r\n//        // if we won the marking test&set, then we retire R->parent\r\n//        recmgr->retire(data->id, R->parent);\r\n//    }\r\n\r\n    AO_t newWord;\r\n\r\n    if (is_flagged(pS)) {\r\n        newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(pS), UNMARK, FLAG);\r\n    } else {\r\n        newWord = create_child_word((node_t<skey_t, sval_t> *)get_addr(pS), UNMARK, UNFLAG);\r\n    }\r\n\r\n    int result;\r\n\r\n    if (R->isLeftUM) {\r\n        result = atomic_cas_full(&R->lum->child.AO_val1, R->lumC, newWord);\r\n    } else {\r\n        result = atomic_cas_full(&R->lum->child.AO_val2, R->lumC, newWord);\r\n    }\r\n    \r\n    if (result) {\r\n        retireDeletedNodes(data, (node_t<skey_t, sval_t> *) get_addr(R->lumC), (node_t<skey_t, sval_t> *) get_addr(pS));\r\n    }\r\n    \r\n    return result;\r\n}\r\n\r\n#endif /* NATARAJAN_EXT_BST_LF_IMPL_H */\r\n\r\n"
  },
  {
    "path": "graphs/BenchmarkLatencyCounter.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _BENCHMARK_LATENCY_COUNTER_H_\r\n#define _BENCHMARK_LATENCY_COUNTER_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\n\r\n/**\r\n * This is a micro-benchmark for measuring on an array of counters\r\n */\r\nclass BenchmarkLatencyCounter {\r\n\r\nprivate:\r\n    // Latency constants\r\n    static const long long kLatencyMeasures =   1000000LL;   // We measure 100M iterations\r\n    static const long long kLatencyWarmups =     100000LL;   // Plus these many warmup\r\n\r\n    static const long long NSEC_IN_SEC = 1000000000LL;\r\n    static const uint64_t NUM_COUNTERS = 64;\r\n\r\n    int numThreads;\r\n\r\npublic:\r\n    struct Result {\r\n        uint64_t delay50000;\r\n        uint64_t delay90000;\r\n        uint64_t delay99000;\r\n        uint64_t delay99900;\r\n        uint64_t delay99990;\r\n        uint64_t delay99999;\r\n    };\r\n\r\n    BenchmarkLatencyCounter(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n    /*\r\n     * Execute latency benchmarks\r\n     * We only do one run for this benchmark\r\n     */\r\n    template<typename TM, template<typename> class TMTYPE>\r\n    Result latencyBenchmark(std::string& className) {\r\n        atomic<bool> start = { false };\r\n        TMTYPE<uint64_t> *counters;\r\n        TM::template updateTx([&] () { // It's ok to pass by reference because we're single-threaded\r\n            counters = (TMTYPE<uint64_t>*)TM::tmMalloc(sizeof(TMTYPE<uint64_t>)*NUM_COUNTERS);\r\n            for (int i = 0; i < NUM_COUNTERS; i++) counters[i] = 0;\r\n        });\r\n\r\n        auto latency_lambda = [this,&start,&counters](nanoseconds* delays, const int tid) {\r\n            long long delayIndex = 0;\r\n            while (!start.load()) this_thread::yield();\r\n            // Warmup + Measurements\r\n            for (int iter=0; iter < (kLatencyWarmups+kLatencyMeasures)/numThreads; iter++) {\r\n                // Alternate transactions between left-right and right-left\r\n                auto startBeats = steady_clock::now();\r\n                TM::updateTx([=] () {\r\n                    for (int i = 0; i < NUM_COUNTERS; i++) counters[i] = counters[i]+1;\r\n                });\r\n                auto stopBeats = steady_clock::now();\r\n                if (iter >= kLatencyWarmups/numThreads) delays[delayIndex++] = (stopBeats-startBeats);\r\n                TM::updateTx([=] () {\r\n                    for (int i = NUM_COUNTERS-1; i > 0; i--) counters[i] = counters[i]+1;\r\n                });\r\n            }\r\n        };\r\n\r\n        nanoseconds* delays[numThreads];\r\n        for (int it = 0; it < numThreads; it++) {\r\n            delays[it] = new nanoseconds[kLatencyMeasures/numThreads];\r\n            for (int imeas=0; imeas < kLatencyMeasures/numThreads; imeas++) delays[it][imeas] = 0ns;\r\n        }\r\n\r\n        cout << \"##### \" << TM::className() << \" #####  \\n\";\r\n        className = TM::className();\r\n        thread latencyThreads[numThreads];\r\n        for (int tid = 0; tid < numThreads; tid++) latencyThreads[tid] = thread(latency_lambda, delays[tid], tid);\r\n        start.store(true);\r\n        this_thread::sleep_for(50ms);\r\n        for (int tid = 0; tid < numThreads; tid++) latencyThreads[tid].join();\r\n\r\n        // Aggregate all the delays for enqueues and dequeues and compute the maxs\r\n        cout << \"Aggregating delays for \" << kLatencyMeasures/1000000 << \" million measurements...\\n\";\r\n        vector<nanoseconds> aggDelay(kLatencyMeasures);\r\n        long long idx = 0;\r\n        for (int it = 0; it < numThreads; it++) {\r\n            for (int i = 0; i < kLatencyMeasures/numThreads; i++) {\r\n                aggDelay[idx] = delays[it][i];\r\n                idx++;\r\n            }\r\n        }\r\n\r\n        // Sort the aggregated delays\r\n        cout << \"Sorting delays...\\n\";\r\n        sort(aggDelay.begin(), aggDelay.end());\r\n\r\n        // Show the 50% (median), 90%, 99%, 99.9%, 99.99%, 99.999% and maximum in microsecond/nanoseconds units\r\n        long per50000 = (long)(kLatencyMeasures*50000LL/100000LL);\r\n        long per70000 = (long)(kLatencyMeasures*70000LL/100000LL);\r\n        long per80000 = (long)(kLatencyMeasures*80000LL/100000LL);\r\n        long per90000 = (long)(kLatencyMeasures*90000LL/100000LL);\r\n        long per99000 = (long)(kLatencyMeasures*99000LL/100000LL);\r\n        long per99900 = (long)(kLatencyMeasures*99900LL/100000LL);\r\n        long per99990 = (long)(kLatencyMeasures*99990LL/100000LL);\r\n        long per99999 = (long)(kLatencyMeasures*99999LL/100000LL);\r\n        long imax = kLatencyMeasures-1;\r\n\r\n        cout << \"Enqueue delay (us): 50%=\" << aggDelay[per50000].count()/1000 << \"  70%=\" << aggDelay[per70000].count()/1000 << \"  80%=\" << aggDelay[per80000].count()/1000\r\n             << \"  90%=\" << aggDelay[per90000].count()/1000 << \"  99%=\" << aggDelay[per99000].count()/1000\r\n             << \"  99.9%=\" << aggDelay[per99900].count()/1000 << \"  99.99%=\" << aggDelay[per99990].count()/1000\r\n             << \"  99.999%=\" << aggDelay[per99999].count()/1000 << \"  max=\" << aggDelay[imax].count()/1000 << \"\\n\";\r\n\r\n        Result res = {\r\n            (uint64_t)aggDelay[per50000].count()/1000, (uint64_t)aggDelay[per90000].count()/1000,\r\n            (uint64_t)aggDelay[per99000].count()/1000, (uint64_t)aggDelay[per99900].count()/1000,\r\n            (uint64_t)aggDelay[per99990].count()/1000, (uint64_t)aggDelay[per99999].count()/1000\r\n        };\r\n/*\r\n        // Show in csv format\r\n        cout << \"delay (us):\\n\";\r\n        cout << \"50, \" << aggDelay[per50000].count()/1000 << \"\\n\";\r\n        cout << \"90, \" << aggDelay[per90000].count()/1000 << \"\\n\";\r\n        cout << \"99, \" << aggDelay[per99000].count()/1000 << \"\\n\";\r\n        cout << \"99.9, \" << aggDelay[per99900].count()/1000 << \"\\n\";\r\n        cout << \"99.99, \" << aggDelay[per99990].count()/1000 << \"\\n\";\r\n        cout << \"99.999, \" << aggDelay[per99999].count()/1000 << \"\\n\";\r\n*/\r\n        TM::template updateTx([&] () { // It's ok to pass by reference because we're single-threaded\r\n            TM::tmFree(counters);\r\n        });\r\n\r\n        // Cleanup\r\n        for (int it = 0; it < numThreads; it++) delete[] delays[it];\r\n        return res;\r\n    }\r\n\r\n\r\n#ifdef NEVER\r\npublic:\r\n\r\n    static void allLatencyTests() {\r\n        // Burst Latency benchmarks\r\n        //vector<int> threadList = { 30, 30, 30, 30, 30, 30, 30 }; // For the latency table in the paper\r\n        //vector<int> threadList = { 4 };\r\n        vector<int> threadList = { 1, 2, 4, 8, 12, 16, 20, 24, 28, 30, 32 };\r\n\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<MichaelScottQueue<UserData>>();\r\n        }\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<BitNextQueue<UserData>>();\r\n        }\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<BitNextLazyHeadQueue<UserData>>();\r\n        }\r\n        /*\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<KoganPetrankQueueCHP<UserData>>();\r\n        }\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<CRTurnQueue<UserData>>();\r\n        }\r\n        */\r\n    }\r\n#endif\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/BenchmarkLatencyQueues.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _BENCHMARK_LATENCY_Q_H_\r\n#define _BENCHMARK_LATENCY_Q_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\n\r\n/**\r\n * This is a micro-benchmark for measuring latency\r\n */\r\nclass BenchmarkLatencyQueues {\r\n\r\nprivate:\r\n    struct UserData  {\r\n        long long seq;\r\n        int tid;\r\n        UserData(long long lseq, int ltid) {\r\n            this->seq = lseq;\r\n            this->tid = ltid;\r\n        }\r\n        UserData() {\r\n            this->seq = -2;\r\n            this->tid = -2;\r\n        }\r\n        UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n        bool operator < (const UserData& other) const {\r\n            return seq < other.seq;\r\n        }\r\n    };\r\n\r\n    struct Result {\r\n        nanoseconds nsEnq = 0ns;\r\n        nanoseconds nsDeq = 0ns;\r\n        long long numEnq = 0;\r\n        long long numDeq = 0;\r\n        long long totOpsSec = 0;\r\n\r\n        Result() { }\r\n\r\n        Result(const Result &other) {\r\n            nsEnq = other.nsEnq;\r\n            nsDeq = other.nsDeq;\r\n            numEnq = other.numEnq;\r\n            numDeq = other.numDeq;\r\n            totOpsSec = other.totOpsSec;\r\n        }\r\n\r\n        bool operator < (const Result& other) const {\r\n            return totOpsSec < other.totOpsSec;\r\n        }\r\n    };\r\n\r\n    // Latency constants\r\n    static const long long kLatencyMeasures =     200000000LL;   // We measure 100M iterations divided among the different threads\r\n    static const long long kLatencyWarmupIterations =    10;     // At start of latency tests we do 10M warmup enqueues and dequeues in bursts of 100K\r\n    static const long long kLatencyIterations =         200;     // We do this many iterations of 100K enqueues and dequeues until we get kLatencyMeasures\r\n    static const long long kLatencyBurst = kLatencyMeasures/kLatencyIterations;\r\n\r\n    static const long long NSEC_IN_SEC = 1000000000LL;\r\n\r\n    int numThreads;\r\n    int numRuns;\r\n    seconds testLengthSeconds;\r\n\r\npublic:\r\n    BenchmarkLatencyQueues(int numThreads, int numRuns, seconds testLength) {\r\n        this->numThreads = numThreads;\r\n        this->numRuns = numRuns;\r\n        this->testLengthSeconds = testLength;\r\n    }\r\n\r\n    /*\r\n     * Execute latency benchmarks\r\n     * Make sure to enable high priority for the Windows process\r\n     *\r\n     * We can use this Mathematica function to compute the Inverse CDF of a Poisson and model the latency at 99.99% for lock-free algorithms:\r\n     * https://reference.wolfram.com/language/ref/InverseCDF.html\r\n     *\r\n     * We only do one run for this benchmark\r\n     */\r\n    template<typename Q>\r\n    void latencyBurstBenchmark() {\r\n        atomic<bool> startEnq = { false };\r\n        atomic<bool> startDeq = { false };\r\n        atomic<long> barrier = { 0 };\r\n        Q* queue = new Q(numThreads);\r\n\r\n        auto latency_lambda = [this,&startEnq,&startDeq,&barrier,&queue](nanoseconds* enqDelays, nanoseconds* deqDelays, const int tid) {\r\n            UserData ud(0,0);\r\n            long long enqDelayIndex = 0;\r\n            long long deqDelayIndex = 0;\r\n\r\n            // Warmup + Measurements\r\n            for (int iter=0; iter < kLatencyIterations+kLatencyWarmupIterations; iter++) {\r\n                // Start with enqueues\r\n                while (!startEnq.load()) this_thread::yield();\r\n                for (long long i = 0; i < kLatencyBurst/numThreads; i++) {\r\n                    auto startBeats = steady_clock::now();\r\n                    queue->enqueue(&ud, tid);\r\n                    auto stopBeats = steady_clock::now();\r\n                    if (iter >= kLatencyWarmupIterations) enqDelays[enqDelayIndex++] = (stopBeats-startBeats);\r\n                }\r\n                if (barrier.fetch_add(1) == numThreads) cout << \"ERROR: in barrier\\n\";\r\n                // dequeues\r\n                while (!startDeq.load()) this_thread::yield();\r\n                for (long long i = 0; i < kLatencyBurst/numThreads; i++) {\r\n                    auto startBeats = steady_clock::now();\r\n                    if (queue->dequeue(tid) == nullptr) cout << \"ERROR: dequeued nullptr in i=\" << i << \"\\n\";\r\n                    auto stopBeats = steady_clock::now();\r\n                    if (iter >= kLatencyWarmupIterations) deqDelays[deqDelayIndex++] = (stopBeats-startBeats);\r\n                }\r\n                if (barrier.fetch_add(1) == numThreads) cout << \"ERROR: in barrier\\n\";\r\n            }\r\n        };\r\n\r\n        nanoseconds* enqDelays[numThreads];  // Half enqueues and half dequeues\r\n        nanoseconds* deqDelays[numThreads];\r\n        for (int it = 0; it < numThreads; it++) {\r\n            enqDelays[it] = new nanoseconds[kLatencyMeasures/numThreads];\r\n            deqDelays[it] = new nanoseconds[kLatencyMeasures/numThreads];\r\n            for (int imeas=0; imeas < kLatencyMeasures/numThreads; imeas++) {\r\n                enqDelays[it][imeas] = 0ns;\r\n                deqDelays[it][imeas] = 0ns;\r\n            }\r\n        }\r\n\r\n        cout << \"##### \" << queue->className() << \" #####  \\n\";\r\n        thread latencyThreads[numThreads];\r\n        for (int tid = 0; tid < numThreads; tid++) latencyThreads[tid] = thread(latency_lambda, enqDelays[tid], deqDelays[tid], tid);\r\n        this_thread::sleep_for(50ms);\r\n        for (int iter=0; iter < kLatencyIterations+kLatencyWarmupIterations; iter++) {\r\n            // enqueue round\r\n            startEnq.store(true);\r\n            while (barrier.load() != numThreads) this_thread::yield();\r\n            startEnq.store(false);\r\n            long tmp =  numThreads;\r\n            if (!barrier.compare_exchange_strong(tmp, 0)) cout << \"ERROR: CAS\\n\";\r\n            // dequeue round\r\n            startDeq.store(true);\r\n            while (barrier.load() != numThreads) this_thread::yield();\r\n            startDeq.store(false);\r\n            tmp = numThreads;\r\n            if (!barrier.compare_exchange_strong(tmp, 0)) cout << \"ERROR: CAS\\n\";\r\n        }\r\n        for (int tid = 0; tid < numThreads; tid++) latencyThreads[tid].join();\r\n        delete queue;\r\n\r\n        // Aggregate all the delays for enqueues and dequeues and compute the maxs\r\n        cout << \"Aggregating delays for \" << kLatencyMeasures/1000000 << \" million measurements...\\n\";\r\n        vector<nanoseconds> aggEnqDelay(kLatencyMeasures);\r\n        long long idx = 0;\r\n        for (int it = 0; it < numThreads; it++) {\r\n            for (int i = 0; i < kLatencyMeasures/numThreads; i++) {\r\n                aggEnqDelay[idx] = enqDelays[it][i];\r\n                idx++;\r\n            }\r\n        }\r\n        vector<nanoseconds> aggDeqDelay(kLatencyMeasures);\r\n        idx = 0;\r\n        for (int it = 0; it < numThreads; it++) {\r\n            for (int i = 0; i < kLatencyMeasures/numThreads; i++) {\r\n                aggDeqDelay[idx] = deqDelays[it][i];\r\n                idx++;\r\n            }\r\n        }\r\n\r\n        // Sort the aggregated delays\r\n        cout << \"Sorting delays...\\n\";\r\n        sort(aggEnqDelay.begin(), aggEnqDelay.end());\r\n        sort(aggDeqDelay.begin(), aggDeqDelay.end());\r\n\r\n        // Show the 50% (median), 90%, 99%, 99.9%, 99.99%, 99.999% and maximum in microsecond/nanoseconds units\r\n        long per50000 = (long)(kLatencyMeasures*50000LL/100000LL);\r\n        long per70000 = (long)(kLatencyMeasures*70000LL/100000LL);\r\n        long per80000 = (long)(kLatencyMeasures*80000LL/100000LL);\r\n        long per90000 = (long)(kLatencyMeasures*90000LL/100000LL);\r\n        long per99000 = (long)(kLatencyMeasures*99000LL/100000LL);\r\n        long per99900 = (long)(kLatencyMeasures*99900LL/100000LL);\r\n        long per99990 = (long)(kLatencyMeasures*99990LL/100000LL);\r\n        long per99999 = (long)(kLatencyMeasures*99999LL/100000LL);\r\n        long imax = kLatencyMeasures-1;\r\n\r\n        cout << \"Enqueue delay (us): 50%=\" << aggEnqDelay[per50000].count()/1000 << \"  70%=\" << aggEnqDelay[per70000].count()/1000 << \"  80%=\" << aggEnqDelay[per80000].count()/1000\r\n             << \"  90%=\" << aggEnqDelay[per90000].count()/1000 << \"  99%=\" << aggEnqDelay[per99000].count()/1000\r\n             << \"  99.9%=\" << aggEnqDelay[per99900].count()/1000 << \"  99.99%=\" << aggEnqDelay[per99990].count()/1000\r\n             << \"  99.999%=\" << aggEnqDelay[per99999].count()/1000 << \"  max=\" << aggEnqDelay[imax].count()/1000 << \"\\n\";\r\n        cout << \"Dequeue delay (us): 50%=\" << aggDeqDelay[per50000].count()/1000 << \"  70%=\" << aggDeqDelay[per70000].count()/1000 << \"  80%=\" << aggDeqDelay[per80000].count()/1000\r\n             << \"  90%=\" << aggDeqDelay[per90000].count()/1000 << \"  99%=\" << aggDeqDelay[per99000].count()/1000\r\n             << \"  99.9%=\" << aggDeqDelay[per99900].count()/1000 << \"  99.99%=\" << aggDeqDelay[per99990].count()/1000\r\n             << \"  99.999%=\" << aggDeqDelay[per99999].count()/1000 << \"  max=\" << aggDeqDelay[imax].count()/1000 << \"\\n\";\r\n\r\n        // Show in csv format\r\n        cout << \"Enqueue delay (us):\\n\";\r\n        cout << \"50, \" << aggEnqDelay[per50000].count()/1000 << \"\\n\";\r\n        cout << \"90, \" << aggEnqDelay[per90000].count()/1000 << \"\\n\";\r\n        cout << \"99, \" << aggEnqDelay[per99000].count()/1000 << \"\\n\";\r\n        cout << \"99.9, \" << aggEnqDelay[per99900].count()/1000 << \"\\n\";\r\n        cout << \"99.99, \" << aggEnqDelay[per99990].count()/1000 << \"\\n\";\r\n        cout << \"99.999, \" << aggEnqDelay[per99999].count()/1000 << \"\\n\";\r\n        cout << \"Dequeue delay (us):\\n\";\r\n        cout << \"50, \" << aggDeqDelay[per50000].count()/1000 << \"\\n\";\r\n        cout << \"90, \" << aggDeqDelay[per90000].count()/1000 << \"\\n\";\r\n        cout << \"99, \" << aggDeqDelay[per99000].count()/1000 << \"\\n\";\r\n        cout << \"99.9, \" << aggDeqDelay[per99900].count()/1000 << \"\\n\";\r\n        cout << \"99.99, \" << aggDeqDelay[per99990].count()/1000 << \"\\n\";\r\n        cout << \"99.999, \" << aggDeqDelay[per99999].count()/1000 << \"\\n\";\r\n\r\n        // Cleanup\r\n        for (int it = 0; it < numThreads; it++) {\r\n            delete[] enqDelays[it];\r\n            delete[] deqDelays[it];\r\n        }\r\n    }\r\n\r\n\r\n#ifdef NEVER\r\npublic:\r\n\r\n    static void allLatencyTests() {\r\n        // Burst Latency benchmarks\r\n        //vector<int> threadList = { 30, 30, 30, 30, 30, 30, 30 }; // For the latency table in the paper\r\n        //vector<int> threadList = { 4 };\r\n        vector<int> threadList = { 1, 2, 4, 8, 12, 16, 20, 24, 28, 30, 32 };\r\n\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<MichaelScottQueue<UserData>>();\r\n        }\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<BitNextQueue<UserData>>();\r\n        }\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<BitNextLazyHeadQueue<UserData>>();\r\n        }\r\n        /*\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<KoganPetrankQueueCHP<UserData>>();\r\n        }\r\n        for (int nThreads : threadList) {\r\n            BenchmarkLatencyQ bench(nThreads, 0, 0s); // Only the numThreads is used in this test\r\n            std::cout << \"\\n----- Burst Latency   numThreads=\" << bench.numThreads << \"   kLatencyMeasures=\" << kLatencyMeasures/1000000LL << \"M -----\\n\";\r\n            bench.latencyBurstBenchmark<CRTurnQueue<UserData>>();\r\n        }\r\n        */\r\n    }\r\n#endif\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/BenchmarkMaps.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _BENCHMARK_MAPS_H_\r\n#define _BENCHMARK_MAPS_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n#include <iostream>\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\n// Regular UserData\r\nstruct UserData  {\r\n    long long seq;\r\n    int tid;\r\n    UserData(long long lseq, int ltid=0) {\r\n        this->seq = lseq;\r\n        this->tid = ltid;\r\n    }\r\n    UserData() {\r\n        this->seq = -2;\r\n        this->tid = -2;\r\n    }\r\n    UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n    bool operator < (const UserData& other) const {\r\n        return seq < other.seq;\r\n    }\r\n    bool operator == (const UserData& other) const {\r\n        return seq == other.seq && tid == other.tid;\r\n    }\r\n    bool operator != (const UserData& other) const {\r\n        return seq != other.seq || tid != other.tid;\r\n    }\r\n};\r\n\r\n\r\nnamespace std {\r\n    template <>\r\n    struct hash<UserData> {\r\n        std::size_t operator()(const UserData& k) const {\r\n            using std::size_t;\r\n            using std::hash;\r\n            return (hash<long long>()(k.seq));  // This hash has no collisions, which is irealistic\r\n        }\r\n    };\r\n}\r\n\r\n\r\n/**\r\n * This is a micro-benchmark of sets, used in the CX paper\r\n */\r\nclass BenchmarkMaps {\r\n\r\nprivate:\r\n    struct Result {\r\n        nanoseconds nsEnq = 0ns;\r\n        nanoseconds nsDeq = 0ns;\r\n        long long numEnq = 0;\r\n        long long numDeq = 0;\r\n        long long totOpsSec = 0;\r\n\r\n        Result() { }\r\n\r\n        Result(const Result &other) {\r\n            nsEnq = other.nsEnq;\r\n            nsDeq = other.nsDeq;\r\n            numEnq = other.numEnq;\r\n            numDeq = other.numDeq;\r\n            totOpsSec = other.totOpsSec;\r\n        }\r\n\r\n        bool operator < (const Result& other) const {\r\n            return totOpsSec < other.totOpsSec;\r\n        }\r\n    };\r\n\r\n    static const long long NSEC_IN_SEC = 1000000000LL;\r\n\r\n    int numThreads;\r\n\r\npublic:\r\n    BenchmarkMaps(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n\r\n    /**\r\n     * When doing \"updates\" we execute a random removal and if the removal is successful we do an add() of the\r\n     * same item immediately after. This keeps the size of the data structure equal to the original size (minus\r\n     * MAX_THREADS items at most) which gives more deterministic results.\r\n     */\r\n    template<template<typename,typename> class S, typename K, typename V>\r\n    long long benchmark(const int updateRatio, const seconds testLengthSeconds, const int numRuns, const int numElements, const bool dedicated=false) {\r\n        long long ops[numThreads][numRuns];\r\n        long long lengthSec[numRuns];\r\n        atomic<bool> quit = { false };\r\n        atomic<bool> startFlag = { false };\r\n        S<K,V>* set = nullptr;\r\n#ifdef TINY_STM\r\n        stm_init_thread();\r\n        //const int tid = 0;\r\n        //WRITE_TX_BEGIN\r\n        //set = TM_ALLOC<S>();\r\n        //WRITE_TX_END\r\n#endif\r\n\r\n        // Create all the keys and values in the concurrent set\r\n        K** keyarray = new K*[numElements];\r\n        for (int i = 0; i < numElements; i++) keyarray[i] = new K(i);\r\n        V** valarray = new V*[numElements];\r\n        for (int i = 0; i < numElements; i++) valarray[i] = new V(i);\r\n\r\n        // Can either be a Reader or a Writer\r\n        auto rw_lambda = [&](const int updateRatio, long long *ops, const int tid) {\r\n        \tuint64_t accum = 0;\r\n            long long numOps = 0;\r\n#ifdef TINY_STM\r\n            stm_init_thread();\r\n#endif\r\n            while (!startFlag.load()) ; // spin\r\n            uint64_t seed = tid+1234567890123456781ULL;\r\n            while (!quit.load()) {\r\n                seed = randomLong(seed);\r\n                int update = seed%1000;\r\n                seed = randomLong(seed);\r\n                auto ix = (unsigned int)(seed%numElements);\r\n                if (update < updateRatio) {\r\n                    // I'm a Writer\r\n                    if (set->remove(*keyarray[ix])) {\r\n                    \tnumOps++;\r\n                    \tset->put(*keyarray[ix], *valarray[ix]);\r\n                    }\r\n                    numOps++;\r\n                } else {\r\n                \t// I'm a Reader\r\n                    set->get(*keyarray[ix]);\r\n                    seed = randomLong(seed);\r\n                    ix = (unsigned int)(seed%numElements);\r\n                    set->get(*keyarray[ix]);\r\n                    numOps+=2;\r\n                }\r\n\r\n            }\r\n            *ops = numOps;\r\n#ifdef TINY_STM\r\n            stm_exit_thread();\r\n#endif\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            set = new S<K,V>();\r\n            // Add all the items to the list\r\n            set->addAll(keyarray, valarray, numElements);\r\n            if (irun == 0) std::cout << \"##### \" << set->className() << \" #####  \\n\";\r\n            thread rwThreads[numThreads];\r\n            if (dedicated) {\r\n                rwThreads[0] = thread(rw_lambda, 1000, &ops[0][irun], 0);\r\n                rwThreads[1] = thread(rw_lambda, 1000, &ops[1][irun], 1);\r\n                for (int tid = 2; tid < numThreads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\r\n            } else {\r\n                for (int tid = 0; tid < numThreads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\r\n            }\r\n            this_thread::sleep_for(100ms);\r\n            auto startBeats = steady_clock::now();\r\n            startFlag.store(true);\r\n            // Sleep for testLengthSeconds seconds\r\n            this_thread::sleep_for(testLengthSeconds);\r\n            quit.store(true);\r\n            auto stopBeats = steady_clock::now();\r\n            for (int tid = 0; tid < numThreads; tid++) rwThreads[tid].join();\r\n            lengthSec[irun] = (stopBeats-startBeats).count();\r\n            if (dedicated) {\r\n                // We don't account for the write-only operations but we aggregate the values from the two threads and display them\r\n                std::cout << \"Mutative transactions per second = \" << (ops[0][irun] + ops[1][irun])*1000000000LL/lengthSec[irun] << \"\\n\";\r\n                ops[0][irun] = 0;\r\n                ops[1][irun] = 0;\r\n            }\r\n            quit.store(false);\r\n            startFlag.store(false);\r\n            // Measure the time the destructor takes to complete and if it's more than 1 second, print it out\r\n            auto startDel = steady_clock::now();\r\n#ifdef TINY_STM\r\n            WRITE_TX_BEGIN\r\n            TM_FREE<S>(set);\r\n            WRITE_TX_END\r\n#endif\r\n            delete set;\r\n\r\n            auto stopDel = steady_clock::now();\r\n            if ((startDel-stopDel).count() > NSEC_IN_SEC) {\r\n                std::cout << \"Destructor took \" << (startDel-stopDel).count()/NSEC_IN_SEC << \" seconds\\n\";\r\n            }\r\n            // Compute ops at the end of each run\r\n            long long agg = 0;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg += ops[tid][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n\r\n        for (int i = 0; i < numElements; i++) delete keyarray[i];\r\n        delete[] keyarray;\r\n\r\n        // Accounting\r\n        vector<long long> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg[irun] += ops[tid][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n\r\n        // Compute the median. numRuns must be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto maxops = agg[numRuns-1];\r\n        auto minops = agg[0];\r\n        auto medianops = agg[numRuns/2];\r\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        std::cout << \"Ops/sec = \" << medianops << \"      delta = \" << delta << \"%   min = \" << minops << \"   max = \" << maxops << \"\\n\";\r\n#ifdef TINY_STM\r\n        stm_exit_thread();\r\n#endif\r\n        return medianops;\r\n    }\r\n\r\n\r\n    /**\r\n     * An imprecise but fast random number generator\r\n     */\r\n    uint64_t randomLong(uint64_t x) {\r\n        x ^= x >> 12; // a\r\n        x ^= x << 25; // b\r\n        x ^= x >> 27; // c\r\n        return x * 2685821657736338717LL;\r\n    }\r\n\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/BenchmarkQueues.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _BENCHMARK_Q_H_\r\n#define _BENCHMARK_Q_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n#include <cassert>\r\n\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\nstruct UserData  {\r\n    long long seq;\r\n    int tid;\r\n    UserData(long long lseq, int ltid) {\r\n        this->seq = lseq;\r\n        this->tid = ltid;\r\n    }\r\n    UserData() {\r\n        this->seq = -2;\r\n        this->tid = -2;\r\n    }\r\n    UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n    bool operator < (const UserData& other) const {\r\n        return seq < other.seq;\r\n    }\r\n};\r\n\r\n\r\n/**\r\n * This is a micro-benchmark to run the tests shown in CRTurnQueue paper\r\n *\r\n * <h2> Performance Benchmarks </h2>\r\n * TODO\r\n *\r\n *\r\n * <h2> Latency Distribution </h2>\r\n *\r\n * - We fire up 28 threads of type LatencyThread;\r\n * - Each thread does alternatively 1000 enqueue() and 1000 dequeue(). All dequeues are non-null;\r\n * - After start, each thread does 1M iterations as warmup.\r\n * - Measurements are done for 4M iterations, that are saved in a local array, 2M enqueue and 2M dequeue;\r\n * -\r\n *\r\n */\r\nclass BenchmarkQueues {\r\n\r\nprivate:\r\n\r\n    struct Result {\r\n        nanoseconds nsEnq = 0ns;\r\n        nanoseconds nsDeq = 0ns;\r\n        long long numEnq = 0;\r\n        long long numDeq = 0;\r\n        long long totOpsSec = 0;\r\n\r\n        Result() { }\r\n\r\n        Result(const Result &other) {\r\n            nsEnq = other.nsEnq;\r\n            nsDeq = other.nsDeq;\r\n            numEnq = other.numEnq;\r\n            numDeq = other.numDeq;\r\n            totOpsSec = other.totOpsSec;\r\n        }\r\n\r\n        bool operator < (const Result& other) const {\r\n            return totOpsSec < other.totOpsSec;\r\n        }\r\n    };\r\n\r\n    // Performance benchmark constants\r\n    static const long long kNumPairsWarmup =     1000000LL;     // Each threads does 1M iterations as warmup\r\n\r\n    // Contants for Ping-Pong performance benchmark\r\n    static const int kPingPongBatch = 1000;            // Each thread starts by injecting 1k items in the queue\r\n\r\n\r\n    static const long long NSEC_IN_SEC = 1000000000LL;\r\n\r\n    int numThreads;\r\n\r\npublic:\r\n\r\n    BenchmarkQueues(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n\r\n    /**\r\n     * enqueue-dequeue pairs: in each iteration a thread executes an enqueue followed by a dequeue;\r\n     * the benchmark executes 10^8 pairs partitioned evenly among all threads;\r\n     */\r\n    template<typename Q>\r\n    uint64_t enqDeq(std::string& className, const long numPairs, const int numRuns) {\r\n        nanoseconds deltas[numThreads][numRuns];\r\n        atomic<bool> startFlag = { false };\r\n        Q* queue = nullptr;\r\n        className = Q::className();\r\n        cout << \"##### \" << className << \" #####  \\n\";\r\n\r\n        auto enqdeq_lambda = [this,&startFlag,&numPairs,&queue](nanoseconds *delta, const int tid) {\r\n            UserData ud(0,0);\r\n            while (!startFlag.load()) {} // Spin until the startFlag is set\r\n            // Warmup phase\r\n            for (long long iter = 0; iter < kNumPairsWarmup/numThreads; iter++) {\r\n                queue->enqueue(&ud, tid);\r\n                if (queue->dequeue(tid) == nullptr) cout << \"Error at warmup dequeueing iter=\" << iter << \"\\n\";\r\n            }\r\n            // Measurement phase\r\n            auto startBeats = steady_clock::now();\r\n            for (long long iter = 0; iter < numPairs/numThreads; iter++) {\r\n                queue->enqueue(&ud, tid);\r\n                if (queue->dequeue(tid) == nullptr) cout << \"Error at measurement dequeueing iter=\" << iter << \"\\n\";\r\n            }\r\n            auto stopBeats = steady_clock::now();\r\n            *delta = stopBeats - startBeats;\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            queue = new Q(numThreads);\r\n            thread enqdeqThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid] = thread(enqdeq_lambda, &deltas[tid][irun], tid);\r\n            startFlag.store(true);\r\n            // Sleep for 2 seconds just to let the threads see the startFlag\r\n            this_thread::sleep_for(2s);\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\r\n            startFlag.store(false);\r\n            delete (Q*)queue;\r\n        }\r\n\r\n        // Sum up all the time deltas of all threads so we can find the median run\r\n        vector<nanoseconds> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            agg[irun] = 0ns;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg[irun] += deltas[tid][irun];\r\n            }\r\n        }\r\n\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto median = agg[numRuns/2].count()/numThreads; // Normalize back to per-thread time (mean of time for this run)\r\n\r\n        cout << \"Total Ops/sec = \" << numPairs*2*NSEC_IN_SEC/median << \"\\n\";\r\n        return (numPairs*2*NSEC_IN_SEC/median);\r\n    }\r\n\r\n\r\n    /**\r\n     * Start with only enqueues 100K/numThreads, wait for them to finish, then do only dequeues but only 100K/numThreads\r\n     */\r\n    template<typename Q>\r\n    void burst(std::string& className, uint64_t& resultsEnq, uint64_t& resultsDeq,\r\n               const long long burstSize, const int numIters, const int numRuns, const bool isSC=false) {\r\n        Result results[numThreads][numRuns];\r\n        atomic<bool> startEnq = { false };\r\n        atomic<bool> startDeq = { false };\r\n        atomic<long> barrier = { 0 };\r\n        Q* queue = nullptr;\r\n\r\n        auto burst_lambda = [this,&startEnq,&startDeq,&burstSize,&barrier,&numIters,&isSC,&queue](Result *res, const int tid) {\r\n            UserData ud(0,0);\r\n            // Warmup only if it is not Single-Consumer\r\n            if (!isSC) {\r\n                const long long warmupIters = 100000LL;  // Do 100K for each thread as a warmup\r\n                for (long long iter = 0; iter < warmupIters; iter++) queue->enqueue(&ud, tid);\r\n                for (long long iter = 0; iter < warmupIters; iter++) {\r\n                    if (queue->dequeue(tid) == nullptr) cout << \"ERROR: warmup dequeued nullptr in iter=\" << iter << \"\\n\";\r\n                }\r\n            }\r\n            // Measurements\r\n            for (int iter = 0; iter < numIters; iter++) {\r\n                // Start with enqueues\r\n                while (!startEnq.load()) {} // spin is better than yield here\r\n                auto startBeats = steady_clock::now();\r\n                for (long long i = 0; i < burstSize/numThreads; i++) {\r\n                    queue->enqueue(&ud, tid);\r\n                }\r\n                auto stopBeats = steady_clock::now();\r\n                res->nsEnq += (stopBeats-startBeats);\r\n                res->numEnq += burstSize/numThreads;\r\n                if (barrier.fetch_add(1) == numThreads) cout << \"ERROR: in barrier\\n\";\r\n                // dequeues\r\n                while (!startDeq.load()) { } // spin is better than yield here\r\n                if (isSC) { // Handle the single-consumer case\r\n                    if (tid == 0) {\r\n                        startBeats = steady_clock::now();\r\n                        // We need to deal with rounding errors in the single-consumer case\r\n                        for (long long i = 0; i < ((long long)(burstSize/numThreads))*numThreads; i++) {\r\n                            if (queue->dequeue(tid) == nullptr) {\r\n                                cout << \"ERROR: dequeued nullptr in iter=\" << i << \"\\n\";\r\n                                assert(false);\r\n                            }\r\n                        }\r\n                        stopBeats = steady_clock::now();\r\n                        if (queue->dequeue(tid) != nullptr) cout << \"ERROR: dequeued non-null, there must be duplicate items!\\n\";\r\n                        res->nsDeq += (stopBeats-startBeats);\r\n                        res->numDeq += burstSize/numThreads;\r\n                    }\r\n                } else {\r\n                    startBeats = steady_clock::now();\r\n                    for (long long i = 0; i < burstSize/numThreads; i++) {\r\n                        if (queue->dequeue(tid) == nullptr) {\r\n                            cout << \"ERROR: dequeued nullptr in iter=\" << i << \"\\n\";\r\n                            assert(false);\r\n                        }\r\n                    }\r\n                    stopBeats = steady_clock::now();\r\n                    res->nsDeq += (stopBeats-startBeats);\r\n                    res->numDeq += burstSize/numThreads;\r\n                }\r\n                if (barrier.fetch_add(1) == numThreads) cout << \"ERROR: in barrier\\n\";\r\n            }\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            queue = new Q(numThreads);\r\n            if (irun == 0) {\r\n                className = queue->className();\r\n                cout << \"##### \" << queue->className() << \" #####  \\n\";\r\n            }\r\n            thread burstThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) burstThreads[tid] = thread(burst_lambda, &results[tid][irun], tid);\r\n            this_thread::sleep_for(100ms);\r\n            for (int iter=0; iter < numIters; iter++) {\r\n                // enqueue round\r\n                startEnq.store(true);\r\n                while (barrier.load() != numThreads) this_thread::yield();\r\n                startEnq.store(false);\r\n                long tmp =  numThreads;\r\n                if (!barrier.compare_exchange_strong(tmp, 0)) cout << \"ERROR: CAS\\n\";\r\n                // dequeue round\r\n                startDeq.store(true);\r\n                while (barrier.load() != numThreads) this_thread::yield();\r\n                startDeq.store(false);\r\n                tmp = numThreads;\r\n                if (!barrier.compare_exchange_strong(tmp, 0)) cout << \"ERROR: CAS\\n\";\r\n            }\r\n            for (int tid = 0; tid < numThreads; tid++) burstThreads[tid].join();\r\n            delete queue;\r\n        }\r\n\r\n        // Accounting\r\n        vector<Result> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            nanoseconds maxNsEnq = 0ns;\r\n            nanoseconds maxNsDeq = 0ns;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                if (results[tid][irun].nsEnq > maxNsEnq) maxNsEnq = results[tid][irun].nsEnq;\r\n                if (results[tid][irun].nsDeq > maxNsDeq) maxNsDeq = results[tid][irun].nsDeq;\r\n                agg[irun].numEnq += results[tid][irun].numEnq;\r\n                agg[irun].numDeq += results[tid][irun].numDeq;\r\n            }\r\n            agg[irun].nsEnq = maxNsEnq;\r\n            agg[irun].nsDeq = maxNsDeq;\r\n            agg[irun].totOpsSec = agg[irun].nsEnq.count()+agg[irun].nsDeq.count();\r\n        }\r\n\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        Result median = agg[numRuns/2];\r\n        const long long allThreadsEnqPerSec = median.numEnq*NSEC_IN_SEC/median.nsEnq.count();\r\n        const long long allThreadsDeqPerSec = median.numDeq*NSEC_IN_SEC/median.nsDeq.count();\r\n\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        cout << \"Enq/sec = \" << allThreadsEnqPerSec << \"   Deq/sec = \" << allThreadsDeqPerSec << \"\\n\";\r\n        resultsEnq = allThreadsEnqPerSec;\r\n        resultsDeq = allThreadsDeqPerSec;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/BenchmarkSPS.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _BENCHMARK_SPS_H_\r\n#define _BENCHMARK_SPS_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <typeinfo>\r\n\r\nstatic const long arraySize = 1000; // 1k or 1M entries in the SPS array\r\n\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\n\r\n/**\r\n * This is a micro-benchmark\r\n */\r\nclass BenchmarkSPS {\r\n\r\nprivate:\r\n    int numThreads;\r\n\r\npublic:\r\n    struct UserData  {\r\n        long long seq;\r\n        int tid;\r\n        UserData(long long lseq, int ltid) {\r\n            this->seq = lseq;\r\n            this->tid = ltid;\r\n        }\r\n        UserData() {\r\n            this->seq = -2;\r\n            this->tid = -2;\r\n        }\r\n        UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n        bool operator < (const UserData& other) const {\r\n            return seq < other.seq;\r\n        }\r\n    };\r\n\r\n    BenchmarkSPS(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n\r\n    /*\r\n     * An array of integers that gets randomly permutated.\r\n     */\r\n    template<typename TM, template<typename> class TMTYPE>\r\n    uint64_t benchmarkSPSInteger(std::string& className, const seconds testLengthSeconds, const long numSwapsPerTx, const int numRuns) {\r\n        long long ops[numThreads][numRuns];\r\n        long long lengthSec[numRuns];\r\n        atomic<bool> startFlag = { false };\r\n        atomic<bool> quit = { false };\r\n\r\n        className = TM::className();\r\n        cout << \"##### \" << TM::className() << \" #####  \\n\";\r\n\r\n        // Create the array of integers and initialize it\r\n        TMTYPE<uint64_t>* parray;\r\n        // It's ok to capture by reference, we're running single-threaded now\r\n        TM::updateTx([&] () {\r\n            parray = new TMTYPE<uint64_t>[arraySize];\r\n            //parray = (TMTYPE<uint64_t>*)TM::tmMalloc(sizeof(TMTYPE<uint64_t>)*arraySize);\r\n        } );\r\n        // Break up the initialization into transactions of 1k stores, so it fits in the log\r\n        for (long j = 0; j < arraySize; j+=1000) {\r\n            TM::updateTx([&] () {\r\n                for (int i = 0; i < 1000 && i+j < arraySize; i++) parray[i+j] = i+j;\r\n            } );\r\n        }\r\n\r\n        auto func = [this,&startFlag,&quit,&numSwapsPerTx,&parray](long long *ops, const int tid) {\r\n            uint64_t seed = tid+1234567890123456781ULL;\r\n            // Spin until the startFlag is set\r\n            while (!startFlag.load()) {}\r\n            // Do transactions until the quit flag is set\r\n            long long tcount = 0;\r\n            while (!quit.load()) {\r\n                TM::updateTx([&] () {\r\n                    for (int i = 0; i < numSwapsPerTx; i++) {\r\n                        seed = randomLong(seed);\r\n                        auto ia = seed%arraySize;\r\n                        uint64_t tmp = parray[ia];\r\n                        seed = randomLong(seed);\r\n                        auto ib = seed%arraySize;\r\n                        parray[ia] = parray[ib];\r\n                        parray[ib] = tmp;\r\n                    }\r\n                } );\r\n                ++tcount;\r\n                /*\r\n                                PE::read_transaction([this,&seed,&parray,&numWordsPerTransaction] () {\r\n                                    PersistentArrayInt<persist>* read_array = PE::template get_object<PersistentArrayInt<persist>>(PIDX_INT_ARRAY);\r\n                                    // Check that the array is consistent\r\n                                    int sum = 0;\r\n                                    for (int i = 0; i < arraySize; i++) {\r\n                                        sum += read_array->counters[i];\r\n                                    }\r\n                                    assert(sum == 0);\r\n                                } );\r\n                */\r\n            }\r\n            *ops = tcount;\r\n        };\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            if (irun == 0) className = TM::className();\r\n            thread enqdeqThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid] = thread(func, &ops[tid][irun], tid);\r\n            auto startBeats = steady_clock::now();\r\n            startFlag.store(true);\r\n            // Sleep for 20 seconds\r\n            this_thread::sleep_for(testLengthSeconds);\r\n            quit.store(true);\r\n            auto stopBeats = steady_clock::now();\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\r\n            lengthSec[irun] = (stopBeats-startBeats).count();\r\n            startFlag.store(false);\r\n            quit.store(false);\r\n        }\r\n\r\n        // It's ok to capture by reference, we're running single-threaded now\r\n        TM::updateTx([&] () {\r\n            delete[] parray;\r\n            //TM::tmFree(parray);\r\n        });\r\n\r\n        // Accounting\r\n        vector<long long> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n        \tfor(int i=0;i<numThreads;i++){\r\n        \t\tagg[irun] += ops[i][irun]*1000000000LL/lengthSec[irun];\r\n        \t}\r\n        }\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto maxops = agg[numRuns-1];\r\n        auto minops = agg[0];\r\n        auto medianops = agg[numRuns/2];\r\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        std::cout << \"Swaps/sec = \" << medianops*numSwapsPerTx << \"     delta = \" << delta*numSwapsPerTx << \"%   min = \" << minops*numSwapsPerTx << \"   max = \" << maxops*numSwapsPerTx << \"\\n\";\r\n        return medianops*numSwapsPerTx;\r\n    }\r\n\r\n\r\n\r\n    /*\r\n     * An array of objects that gets randomly permutated.\r\n     */\r\n    template<typename TM, template<typename> class TMTYPE, typename TMBASE>\r\n    uint64_t benchmarkSPSObject(std::string& className, const seconds testLengthSeconds, const long numSwapsPerTx, const int numRuns) {\r\n        long long ops[numThreads][numRuns];\r\n        long long lengthSec[numRuns];\r\n        atomic<bool> startFlag = { false };\r\n        atomic<bool> quit = { false };\r\n\r\n        struct MyObject : public TMBASE {\r\n            uint64_t a {0};  // For the OneFile STMs these don't need to be tmtypes because they're immutable after visible in this benchmark\r\n            uint64_t b {0};\r\n            MyObject(uint64_t a0, uint64_t b0) {\r\n                a = a0;\r\n                b = b0;\r\n            }\r\n            MyObject(const MyObject &other) {\r\n                a = other.a;\r\n                b = other.b;\r\n            }\r\n        };\r\n\r\n        // Create the array of integers and initialize it\r\n        TMTYPE<MyObject*>* parray;\r\n        parray = new TMTYPE<MyObject*>[arraySize];\r\n        // Break up the initialization into transactions of 1k stores, so it fits in the log\r\n        for (long j = 0; j < arraySize; j+=1000) {\r\n            TM::updateTx([&] () {\r\n                for (int i = 0; i < 1000 && i+j < arraySize; i++) parray[i+j] = TM::template tmNew<MyObject>((uint64_t)i+j,(uint64_t)i);\r\n            } );\r\n        }\r\n        /*\r\n         TM::updateTx([&] () {\r\n            for (int i = 0; i < arraySize; i++) parray[i] = TM::template tmNew<MyObject>((uint64_t)i,(uint64_t)i);\r\n        } );\r\n        */\r\n\r\n\r\n        auto func = [this,&startFlag,&quit,&numSwapsPerTx,&parray](long long *ops, const int tid) {\r\n            uint64_t seed = tid+1234567890123456781ULL;\r\n            // Spin until the startFlag is set\r\n            while (!startFlag.load()) {}\r\n            // Do transactions until the quit flag is set\r\n            long long tcount = 0;\r\n            while (!quit.load()) {\r\n                TM::updateTx([&] () {\r\n                    for (int i = 0; i < numSwapsPerTx; i++) {\r\n                        seed = randomLong(seed);\r\n                        auto ia = seed%arraySize;\r\n                        // Create a new object with the same contents to replace the old object, at a random location\r\n                        MyObject* tmp = TM::template tmNew<MyObject>(*parray[ia]);\r\n                        TM::template tmDelete<MyObject>(parray[ia]);\r\n                        parray[ia] = tmp;\r\n                    }\r\n                } );\r\n                ++tcount;\r\n            }\r\n            *ops = tcount;\r\n        };\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            if (irun == 0) {\r\n                className = TM::className();\r\n                cout << \"##### \" << TM::className() << \" #####  \\n\";\r\n            }\r\n            thread enqdeqThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid] = thread(func, &ops[tid][irun], tid);\r\n            auto startBeats = steady_clock::now();\r\n            startFlag.store(true);\r\n            // Sleep for 20 seconds\r\n            this_thread::sleep_for(testLengthSeconds);\r\n            quit.store(true);\r\n            auto stopBeats = steady_clock::now();\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\r\n            lengthSec[irun] = (stopBeats-startBeats).count();\r\n            startFlag.store(false);\r\n            quit.store(false);\r\n        }\r\n        TM::updateTx([&] () {\r\n            for (int i = 0; i < arraySize; i++) TM::template tmDelete<MyObject>(parray[i]);\r\n        });\r\n        delete[] parray;\r\n\r\n        // Accounting\r\n        vector<long long> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            for(int i=0;i<numThreads;i++){\r\n                agg[irun] += ops[i][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto maxops = agg[numRuns-1];\r\n        auto minops = agg[0];\r\n        auto medianops = agg[numRuns/2];\r\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        std::cout << \"Swaps/sec = \" << medianops*numSwapsPerTx << \"     delta = \" << delta*numSwapsPerTx << \"%   min = \" << minops*numSwapsPerTx << \"   max = \" << maxops*numSwapsPerTx << \"\\n\";\r\n        return medianops*numSwapsPerTx;\r\n    }\r\n\r\n\r\n    /**\r\n     * An imprecise but fast random number generator\r\n     */\r\n    uint64_t randomLong(uint64_t x) {\r\n        x ^= x >> 12; // a\r\n        x ^= x << 25; // b\r\n        x ^= x >> 27; // c\r\n        return x * 2685821657736338717LL;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/BenchmarkSets.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _BENCHMARK_SETS_H_\r\n#define _BENCHMARK_SETS_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n#include <iostream>\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\n// Regular UserData\r\nstruct UserData  {\r\n    long long seq;\r\n    int tid;\r\n    UserData(long long lseq, int ltid=0) {\r\n        this->seq = lseq;\r\n        this->tid = ltid;\r\n    }\r\n    UserData() {\r\n        this->seq = -2;\r\n        this->tid = -2;\r\n    }\r\n    UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n    bool operator < (const UserData& other) const {\r\n        return seq < other.seq;\r\n    }\r\n    bool operator == (const UserData& other) const {\r\n        return seq == other.seq && tid == other.tid;\r\n    }\r\n    bool operator != (const UserData& other) const {\r\n        return seq != other.seq || tid != other.tid;\r\n    }\r\n};\r\n\r\n\r\nnamespace std {\r\n    template <>\r\n    struct hash<UserData> {\r\n        std::size_t operator()(const UserData& k) const {\r\n            using std::size_t;\r\n            using std::hash;\r\n            return (hash<long long>()(k.seq));  // This hash has no collisions, which is irealistic\r\n        }\r\n    };\r\n}\r\n\r\n\r\n/**\r\n * This is a micro-benchmark of sets\r\n */\r\nclass BenchmarkSets {\r\n\r\nprivate:\r\n    struct Result {\r\n        nanoseconds nsEnq = 0ns;\r\n        nanoseconds nsDeq = 0ns;\r\n        long long numEnq = 0;\r\n        long long numDeq = 0;\r\n        long long totOpsSec = 0;\r\n\r\n        Result() { }\r\n\r\n        Result(const Result &other) {\r\n            nsEnq = other.nsEnq;\r\n            nsDeq = other.nsDeq;\r\n            numEnq = other.numEnq;\r\n            numDeq = other.numDeq;\r\n            totOpsSec = other.totOpsSec;\r\n        }\r\n\r\n        bool operator < (const Result& other) const {\r\n            return totOpsSec < other.totOpsSec;\r\n        }\r\n    };\r\n\r\n    static const long long NSEC_IN_SEC = 1000000000LL;\r\n\r\n    int numThreads;\r\n\r\npublic:\r\n    BenchmarkSets(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n\r\n    /**\r\n     * When doing \"updates\" we execute a random removal and if the removal is successful we do an add() of the\r\n     * same item immediately after. This keeps the size of the data structure equal to the original size (minus\r\n     * MAX_THREADS items at most) which gives more deterministic results.\r\n     */\r\n    template<typename S, typename K>\r\n    long long benchmark(std::string& className, const int updateRatio, const seconds testLengthSeconds, const int numRuns, const int numElements, const bool dedicated=false) {\r\n        long long ops[numThreads][numRuns];\r\n        long long lengthSec[numRuns];\r\n        atomic<bool> quit = { false };\r\n        atomic<bool> startFlag = { false };\r\n\r\n        className = S::className();\r\n        std::cout << \"##### \" << S::className() << \" #####  \\n\";\r\n        S* set = new S(numThreads);\r\n        // Create all the keys in the concurrent set\r\n        K** udarray = new K*[numElements];\r\n        for (int i = 0; i < numElements; i++) udarray[i] = new K(i);\r\n        // Add all the items to the list\r\n        set->addAll(udarray, numElements, 0);\r\n\r\n        // Can either be a Reader or a Writer\r\n        auto rw_lambda = [this,&quit,&startFlag,&set,&udarray,&numElements](const int updateRatio, long long *ops, const int tid) {\r\n            long long numOps = 0;\r\n            while (!startFlag.load()) ; // spin\r\n            uint64_t seed = tid+1234567890123456781ULL;\r\n            while (!quit.load()) {\r\n                seed = randomLong(seed);\r\n                int update = seed%1000;\r\n                seed = randomLong(seed);\r\n                auto ix = (unsigned int)(seed%numElements);\r\n                if (update < updateRatio) {\r\n                    // I'm a Writer\r\n                    if (set->remove(*udarray[ix], tid)) {\r\n                    \tnumOps++;\r\n                    \tset->add(*udarray[ix], tid);\r\n                    }\r\n                    numOps++;\r\n                } else {\r\n                \t// I'm a Reader\r\n                    set->contains(*udarray[ix], tid);\r\n                    seed = randomLong(seed);\r\n                    ix = (unsigned int)(seed%numElements);\r\n                    set->contains(*udarray[ix], tid);\r\n                    numOps += 2;\r\n                }\r\n            }\r\n            *ops = numOps;\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            thread rwThreads[numThreads];\r\n            if (dedicated) {\r\n                rwThreads[0] = thread(rw_lambda, 1000, &ops[0][irun], 0);\r\n                rwThreads[1] = thread(rw_lambda, 1000, &ops[1][irun], 1);\r\n                for (int tid = 2; tid < numThreads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\r\n            } else {\r\n                for (int tid = 0; tid < numThreads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\r\n            }\r\n            this_thread::sleep_for(100ms);\r\n            auto startBeats = steady_clock::now();\r\n            startFlag.store(true);\r\n            // Sleep for testLengthSeconds seconds\r\n            this_thread::sleep_for(testLengthSeconds);\r\n            quit.store(true);\r\n            auto stopBeats = steady_clock::now();\r\n            for (int tid = 0; tid < numThreads; tid++) rwThreads[tid].join();\r\n            lengthSec[irun] = (stopBeats-startBeats).count();\r\n            if (dedicated) {\r\n                // We don't account for the write-only operations but we aggregate the values from the two threads and display them\r\n                std::cout << \"Mutative transactions per second = \" << (ops[0][irun] + ops[1][irun])*1000000000LL/lengthSec[irun] << \"\\n\";\r\n                ops[0][irun] = 0;\r\n                ops[1][irun] = 0;\r\n            }\r\n            quit.store(false);\r\n            startFlag.store(false);\r\n            // Compute ops at the end of each run\r\n            long long agg = 0;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg += ops[tid][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n\r\n        // Clear the set, one key at a time and then delete the instance\r\n        for (int i = 0; i < numElements; i++) set->remove(*udarray[i], 0);\r\n        delete set;\r\n\r\n        for (int i = 0; i < numElements; i++) delete udarray[i];\r\n        delete[] udarray;\r\n\r\n        // Accounting\r\n        vector<long long> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg[irun] += ops[tid][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n\r\n        // Compute the median. numRuns must be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto maxops = agg[numRuns-1];\r\n        auto minops = agg[0];\r\n        auto medianops = agg[numRuns/2];\r\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        std::cout << \"Ops/sec = \" << medianops << \"      delta = \" << delta << \"%   min = \" << minops << \"   max = \" << maxops << \"\\n\";\r\n        return medianops;\r\n    }\r\n\r\n\r\n\r\n    /*\r\n     * Inspired by Trevor Brown's benchmarks (does everyone else do it like this?)\r\n     */\r\n    template<typename S, typename K>\r\n    long long benchmarkRandomFill(std::string& className, const int updateRatio, const seconds testLengthSeconds, const int numRuns, const int numElements, const bool dedicated=false) {\r\n        long long ops[numThreads][numRuns];\r\n        long long lengthSec[numRuns];\r\n        atomic<bool> quit = { false };\r\n        atomic<bool> startFlag = { false };\r\n\r\n        className = S::className();\r\n        std::cout << \"##### \" << S::className() << \" #####  \\n\";\r\n        S* set = new S(numThreads);\r\n        // Create all the keys in the concurrent set\r\n        K** udarray = new K*[2*numElements];\r\n        for (int i = 0; i < 2*numElements; i++) udarray[i] = new K(i);\r\n        // Add half the keys to the list\r\n        long ielem = 0;\r\n        uint64_t seed = 1234567890123456781ULL;\r\n        while (ielem < numElements/2) {\r\n            seed = randomLong(seed);\r\n            // Insert new random keys until we have 'numElements/2' keys in the tree\r\n            if (set->add(*udarray[seed%(numElements)], 0)) ielem++;\r\n        }\r\n        // Add all keys, repeating if needed\r\n        set->addAll(udarray, numElements, 0);\r\n\r\n        // Can either be a Reader or a Writer\r\n        auto rw_lambda = [this,&quit,&startFlag,&set,&udarray,&numElements](const int updateRatio, long long *ops, const int tid) {\r\n            long long numOps = 0;\r\n            while (!startFlag.load()) ; // spin\r\n            uint64_t seed = tid+1234567890123456781ULL;\r\n            while (!quit.load()) {\r\n                seed = randomLong(seed);\r\n                int update = seed%1000;\r\n                seed = randomLong(seed);\r\n                auto ix = (unsigned int)(seed%numElements);\r\n                if (update < updateRatio) {\r\n                    // I'm a Writer\r\n                    if (set->remove(*udarray[ix], tid)) {\r\n                        numOps++;\r\n                        set->add(*udarray[ix], tid);\r\n                    }\r\n                    numOps++;\r\n                } else {\r\n                    // I'm a Reader\r\n                    set->contains(*udarray[ix], tid);\r\n                    seed = randomLong(seed);\r\n                    ix = (unsigned int)(seed%numElements);\r\n                    set->contains(*udarray[ix], tid);\r\n                    numOps += 2;\r\n                }\r\n            }\r\n            *ops = numOps;\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            thread rwThreads[numThreads];\r\n            if (dedicated) {\r\n                rwThreads[0] = thread(rw_lambda, 1000, &ops[0][irun], 0);\r\n                rwThreads[1] = thread(rw_lambda, 1000, &ops[1][irun], 1);\r\n                for (int tid = 2; tid < numThreads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\r\n            } else {\r\n                for (int tid = 0; tid < numThreads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\r\n            }\r\n            this_thread::sleep_for(100ms);\r\n            auto startBeats = steady_clock::now();\r\n            startFlag.store(true);\r\n            // Sleep for testLengthSeconds seconds\r\n            this_thread::sleep_for(testLengthSeconds);\r\n            quit.store(true);\r\n            auto stopBeats = steady_clock::now();\r\n            for (int tid = 0; tid < numThreads; tid++) rwThreads[tid].join();\r\n            lengthSec[irun] = (stopBeats-startBeats).count();\r\n            if (dedicated) {\r\n                // We don't account for the write-only operations but we aggregate the values from the two threads and display them\r\n                std::cout << \"Mutative transactions per second = \" << (ops[0][irun] + ops[1][irun])*1000000000LL/lengthSec[irun] << \"\\n\";\r\n                ops[0][irun] = 0;\r\n                ops[1][irun] = 0;\r\n            }\r\n            quit.store(false);\r\n            startFlag.store(false);\r\n            // Compute ops at the end of each run\r\n            long long agg = 0;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg += ops[tid][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n\r\n        /* Clear the tree, one key at a time and then delete the instance */\r\n        for (int i = 0; i < numElements; i++) set->remove(*udarray[i], 0);\r\n        delete set;\r\n\r\n        for (int i = 0; i < numElements; i++) delete udarray[i];\r\n        delete[] udarray;\r\n\r\n        // Accounting\r\n        vector<long long> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg[irun] += ops[tid][irun]*1000000000LL/lengthSec[irun];\r\n            }\r\n        }\r\n\r\n        // Compute the median. numRuns must be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto maxops = agg[numRuns-1];\r\n        auto minops = agg[0];\r\n        auto medianops = agg[numRuns/2];\r\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        std::cout << \"Ops/sec = \" << medianops << \"      delta = \" << delta << \"%   min = \" << minops << \"   max = \" << maxops << \"\\n\";\r\n        return medianops;\r\n    }\r\n\r\n    /**\r\n     * An imprecise but fast random number generator\r\n     */\r\n    uint64_t randomLong(uint64_t x) {\r\n        x ^= x >> 12; // a\r\n        x ^= x << 25; // b\r\n        x ^= x >> 27; // c\r\n        return x * 2685821657736338717LL;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/Makefile",
    "content": "CXX = g++-8\nCXXFLAGS = -std=c++17 -g -O2 -DPWB_IS_CLFLUSHOPT # -fuse-ld=gold -fsanitize=address\n# For castor-1\n#CXXFLAGS = -std=c++17 -g -O2 -DPWB_IS_CLWB -DPM_REGION_SIZE=64*1024*1024*1024ULL -DPM_USE_DAX -DPM_FILE_NAME=\"\\\"/mnt/pmem0/durable\\\"\"\n\n# Possible options for PWB are:\n# -DPWB_IS_CLFLUSH\t\tpwb is a CLFLUSH and pfence/psync are nops      (Broadwell)\n# -DPWB_IS_CLFLUSHOPT\tpwb is a CLFLUSHOPT and pfence/psync are SFENCE (Kaby Lake) \n# -DPWB_IS_CLWB\t\t\tpwb is a CLWB and pfence/psync are SFENCE       (Sky Lake SP, or Canon Lake SP and beyond)\n# -DPWB_IS_NOP\t\t\tpwb/pfence/psync are nops. Used for shared memory persistence\n\n\nINCLUDES = -I../ -I../common/ \n#LIBS = -l/home/vagrant/tinystm/lib/libstm.a\n\n# This library is needed for ESTM\nESTM_LIB = -L../stms/estm-0.3.0/lib/ -lstm -lpthread\n\n# This library is needed for TinySTM\nTINYSTM_LIB = -L../stms/tinystm/lib/ -lstm -lpthread\nTINYSTM_INC = -I../stms/tinystm/\n\n# This library is needed for PMDK\nPMDKLIBS = -L/usr/local/lib -lpmemobj\n\n\nBINARIES = \\\n\tbin/sps-integer \\\n\tbin/sps-integer-tiny \\\n\tbin/sps-object \\\n\tbin/sps-object-tiny \\\n\tbin/set-ll-1k \\\n\tbin/set-ll-1k-tiny \\\n\tbin/set-ll-10k \\\n\tbin/set-ll-10k-tiny \\\n\tbin/set-tree-1k \\\n\tbin/set-tree-1k-tiny \\\n\tbin/set-tree-10k \\\n\tbin/set-tree-10k-tiny \\\n\tbin/set-tree-1m \\\n\tbin/set-tree-1m-tiny \\\n\tbin/set-hash-1k \\\n\tbin/set-hash-1k-tiny \\\n\tbin/q-ll-enq-deq \\\n\tbin/q-ll-enq-deq-tiny \\\n\tbin/q-array-enq-deq \\\n\tbin/q-array-enq-deq-tiny \\\n\tbin/psps-integer \\\n\tbin/pset-ll-1k \\\n\tbin/pset-ll-10k \\\n\tbin/pset-hash-1k \\\n\tbin/pset-tree-1k \\\n\tbin/pq-ll-enq-deq \\\n\tbin/latency-counter \\\n\tbin/latency-counter-tiny \\\n    bin/pset-tree-1m-oflf \\\n    bin/pset-tree-1m-ofwf \\\n    bin/pset-tree-1m-pmdk \\\n\tbin/pset-tree-1m-romlog \\\n\tbin/pset-tree-1m-romlr \\\n#\tbin/pset-tree-1m-pmdk \\\n#\tbin/pread-while-writing-romlog \\\n\tbin/pread-while-writing-romlr \\\n\tbin/pread-while-writing-oflf \\\n\tbin/pread-while-writing-ofwf \\\n\tbin/pread-while-writing-pmdk \\\n\nSTMS = \\\n\t../stms/CRWWPSTM.hpp \\\n\t../stms/OneFileLF.hpp \\\n\t../stms/OneFileWF.hpp \\\n\t../stms/TinySTM.hpp \\\n\t../stms/tinystm/lib/libstm.a \\\n\nPTMS = \\\n\t../ptms/OneFilePTMLF.hpp \\\n\t../ptms/OneFilePTMWF.hpp \\\n\t../ptms/PMDKTM.hpp \\\n\tlib/libromulus.a \\\n    ../ptms/romuluslog/RomulusLog.hpp \\\n    ../ptms/romuluslr/RomulusLR.hpp \\\n\nSRC_LISTS = \\\n\t../datastructures/linkedlists/CRWWPLinkedListSet.hpp \\\n\t../datastructures/linkedlists/ESTMLinkedListSet.hpp \\\n\t../datastructures/linkedlists/OFLFLinkedListSet.hpp \\\n\t../datastructures/linkedlists/OFWFLinkedListSet.hpp \\\n\t../datastructures/linkedlists/STMLinkedListSet.hpp \\\n\t../datastructures/linkedlists/TinySTMLinkedListSet.hpp \\\n\t\nSRC_TREES = \\\n\t../datastructures/treemaps/ESTMRedBlackTree.hpp \\\n\t../datastructures/treemaps/NatarajanTreeHE.hpp \\\n\t../datastructures/treemaps/OFLFRedBlackTree.hpp \\\n\t../datastructures/treemaps/OFWFRedBlackTree.hpp \\\n\nQUEUES_DEP = \\\n\t../datastructures/queues/ESTMArrayLinkedListQueue.hpp \\\n\t../datastructures/queues/ESTMLinkedListQueue.hpp \\\n\t../datastructures/queues/FAAArrayQueue.hpp \\\n\t../datastructures/queues/LCRQueue.hpp \\\n\t../datastructures/queues/MichaelScottQueue.hpp \\\n\t../datastructures/queues/OFLFArrayLinkedListQueue.hpp \\\n\t../datastructures/queues/OFLFLinkedListQueue.hpp \\\n\t../datastructures/queues/OFWFArrayLinkedListQueue.hpp \\\n\t../datastructures/queues/OFWFLinkedListQueue.hpp \\\n\t../datastructures/queues/TurnQueue.hpp \\\n\t\nPQUEUES_DEP = \\\n\t../pdatastructures/pqueues/MichaelScottQueue.hpp \\\n\t../pdatastructures/pqueues/PFriedmanQueue.hpp \\\n\t../pdatastructures/pqueues/PMDKLinkedListQueue.hpp \\\n\t../pdatastructures/pqueues/PMichaelScottQueue.hpp \\\n\t../pdatastructures/TMLinkedListQueue.hpp \\\n\t../pdatastructures/pqueues/POFLFLinkedListQueue.hpp \\\n\t../pdatastructures/pqueues/POFWFLinkedListQueue.hpp \\\n\t../pdatastructures/pqueues/RomLogLinkedListQueue.hpp \\\n\t../pdatastructures/pqueues/RomLRLinkedListQueue.hpp \\\n\nROMULUS_LIB_SRC = \\\n\t../common/ThreadRegistry.cpp \\\n\t../ptms/romuluslog/malloc.cpp \\\n\t../ptms/romuluslog/RomulusLog.cpp \\\n\t../ptms/romuluslr/malloc.cpp \\\n\t../ptms/romuluslr/RomulusLR.cpp \\\n\nROMULUS_LIB_DEP = \\\n\t$(ROMULUS_LIB_SRC) \\\n\t../ptms/romuluslog/RomulusLog.hpp \\\n\t../ptms/romuluslr/RomulusLR.hpp \\\n\t\t\nTREVOR_BROWN_INCLUDES = \\\n\t-I../datastructures/trevor_brown_abtree/common/recordmgr \\\n\t-I../datastructures/trevor_brown_abtree/common \\\n\t-I../datastructures/trevor_brown_abtree/common/descriptors \\\n\t-I../datastructures/trevor_brown_abtree/common/rq \\\n\t-I../datastructures/trevor_brown_abtree/common/rq \\\n\t-I../datastructures/trevor_brown_abtree/common/atomic_ops \\\n\nall: $(BINARIES) persistencyclean\n\n\nclean: persistencyclean\n\trm -f bin/*\n\trm -f lib/*\n\n\npersistencyclean:\n\trm -f /dev/shm/*_shared\n\trm -f /dev/shm/psegments/*\n\n\n#\n# Create a library for RomulusLog and RomulusLR\n#\nlib/threadregistry.o: $(ROMULUS_LIB_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) -c ../common/ThreadRegistry.cpp -o lib/threadregistry.o\n\nlib/mallocromlog.o: $(ROMULUS_LIB_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) -c ../ptms/romuluslog/malloc.cpp -o lib/mallocromlog.o\n\nlib/romlog.o: $(ROMULUS_LIB_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) -c ../ptms/romuluslog/RomulusLog.cpp -o lib/romlog.o\n\nlib/mallocromlr.o: $(ROMULUS_LIB_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) -c ../ptms/romuluslr/malloc.cpp -o lib/mallocromlr.o\n\nlib/romlr.o: $(ROMULUS_LIB_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) -c ../ptms/romuluslr/RomulusLR.cpp -o lib/romlr.o\n\t\nlib/libromulus.a: lib/threadregistry.o lib/mallocromlog.o lib/romlog.o lib/mallocromlr.o lib/romlr.o\n\tar rcs lib/libromulus.a lib/threadregistry.o lib/mallocromlog.o lib/romlog.o lib/mallocromlr.o lib/romlr.o\n\n\n\n#\n# Queues for volatile memory\n#\t\nbin/q-ll-enq-deq: q-ll-enq-deq.cpp $(STMS) $(QUEUES_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) q-ll-enq-deq.cpp -o bin/q-ll-enq-deq -lpthread $(ESTM_LIB)\n\t\nbin/q-array-enq-deq: q-array-enq-deq.cpp $(STMS) $(QUEUES_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) q-array-enq-deq.cpp -o bin/q-array-enq-deq -lpthread $(ESTM_LIB)\n\t\nbin/q-ll-burst: q-ll-burst.cpp $(QUEUES_DEP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) q-ll-burst.cpp -o bin/q-ll-burst -lpthread $(ESTM_LIB)\n\n# Same as above but for TinySTM\nbin/q-ll-enq-deq-tiny: q-ll-enq-deq.cpp $(STMS) $(QUEUES_DEP)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) q-ll-enq-deq.cpp -o bin/q-ll-enq-deq-tiny -lpthread $(TINYSTM_LIB)\n\nbin/q-array-enq-deq-tiny: q-array-enq-deq.cpp $(STMS) $(QUEUES_DEP)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) q-array-enq-deq.cpp -o bin/q-array-enq-deq-tiny -lpthread $(TINYSTM_LIB)\n\n\n#\n# Queues for persistent memory\n#\t\nbin/pq-ll-enq-deq: pq-ll-enq-deq.cpp $(PTMS) $(PQUEUES_DEP) PBenchmarkQueues.hpp\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) pq-ll-enq-deq.cpp -o bin/pq-ll-enq-deq -lpthread $(PMDKLIBS) lib/libromulus.a\n\n\t\n#\n# Sets for volatile memory\n#\t\nbin/set-ll-1k: set-ll-1k.cpp $(STMS) $(SRC_LISTS)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) set-ll-1k.cpp -o bin/set-ll-1k -lpthread $(ESTM_LIB)\n\nbin/set-ll-10k: set-ll-10k.cpp $(STMS) $(SRC_LISTS)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) set-ll-10k.cpp -o bin/set-ll-10k -lpthread $(ESTM_LIB)\n\nbin/set-tree-1k: set-tree-1k.cpp $(STMS) $(SRC_TREES)\n\t$(CXX) $(CXXFLAGS) -fuse-ld=gold -fsanitize=address $(INCLUDES) $(TREVOR_BROWN_INCLUDES) ../common/ThreadRegistry.cpp $(CSRCS) set-tree-1k.cpp -o bin/set-tree-1k -lpthread $(ESTM_LIB)\n\nbin/set-tree-10k: set-tree-10k.cpp $(STMS) $(SRC_TREES)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(TREVOR_BROWN_INCLUDES) ../common/ThreadRegistry.cpp $(CSRCS) set-tree-10k.cpp -o bin/set-tree-10k -lpthread $(ESTM_LIB)\n\nbin/set-tree-1m: set-tree-1m.cpp $(STMS) $(SRC_TREES)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(TREVOR_BROWN_INCLUDES) ../common/ThreadRegistry.cpp $(CSRCS) set-tree-1m.cpp -o bin/set-tree-1m -lpthread $(ESTM_LIB)\n\nbin/set-hash-1k: set-hash-1k.cpp $(STMS)\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) set-hash-1k.cpp -o bin/set-hash-1k -lpthread $(ESTM_LIB)\n\n\n\n# Same as above, but for Tiny STM only\nbin/set-ll-1k-tiny: set-ll-1k.cpp $(STMS) $(SRC_LISTS)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) set-ll-1k.cpp -o bin/set-ll-1k-tiny -lpthread $(TINYSTM_LIB)\n\nbin/set-ll-10k-tiny: set-ll-10k.cpp $(STMS) $(SRC_LISTS)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) set-ll-10k.cpp -o bin/set-ll-10k-tiny -lpthread $(TINYSTM_LIB)\n\nbin/set-tree-1k-tiny: set-tree-1k.cpp $(STMS)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) set-tree-1k.cpp -o bin/set-tree-1k-tiny -lpthread $(TINYSTM_LIB)\n\nbin/set-tree-10k-tiny: set-tree-10k.cpp $(STMS)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) set-tree-10k.cpp -o bin/set-tree-10k-tiny -lpthread $(TINYSTM_LIB)\n\nbin/set-tree-1m-tiny: set-tree-1m.cpp $(STMS)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) set-tree-1m.cpp -o bin/set-tree-1m-tiny -lpthread $(TINYSTM_LIB)\n\nbin/set-hash-1k-tiny: set-hash-1k.cpp $(STMS)\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) set-hash-1k.cpp -o bin/set-hash-1k-tiny -lpthread $(TINYSTM_LIB)\n\n\n\n#\n# Sets for persistent memory\n#\t\nbin/pset-ll-1k: pset-ll-1k.cpp $(PTMS) PBenchmarkSets.hpp ../pdatastructures/TMLinkedListSet.hpp lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) pset-ll-1k.cpp -o bin/pset-ll-1k -lpthread $(PMDKLIBS) lib/libromulus.a\n\nbin/pset-ll-10k: pset-ll-10k.cpp $(PTMS) PBenchmarkSets.hpp ../pdatastructures/TMLinkedListSet.hpp lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) pset-ll-10k.cpp -o bin/pset-ll-10k -lpthread $(PMDKLIBS) lib/libromulus.a\n\nbin/pset-hash-1k: pset-hash-1k.cpp $(PTMS) PBenchmarkSets.hpp ../pdatastructures/TMHashMap.hpp lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) pset-hash-1k.cpp -o bin/pset-hash-1k -lpthread $(PMDKLIBS) lib/libromulus.a\n\nbin/pset-tree-1k: pset-tree-1k.cpp $(PTMS) PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) pset-tree-1k.cpp -o bin/pset-tree-1k -lpthread $(PMDKLIBS) lib/libromulus.a\n\t\nbin/pset-tree-1m: pset-tree-1m.cpp $(PTMS) PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) pset-tree-1m.cpp -o bin/pset-tree-1m -lpthread $(PMDKLIBS) lib/libromulus.a\n\n\t\n#\t\n# SPS for volatile memory\n#\nbin/sps-integer: sps-integer.cpp $(STMS) BenchmarkSPS.hpp\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) sps-integer.cpp -o bin/sps-integer -lpthread $(ESTM_LIB)\n\nbin/sps-integer-tiny: sps-integer.cpp $(STMS) BenchmarkSPS.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) sps-integer.cpp -o bin/sps-integer-tiny -lpthread $(TINYSTM_LIB)\n\nbin/sps-object: sps-object.cpp $(STMS) BenchmarkSPS.hpp\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) sps-object.cpp -o bin/sps-object -lpthread $(ESTM_LIB)\n\nbin/sps-object-tiny: sps-object.cpp $(STMS) BenchmarkSPS.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) sps-object.cpp -o bin/sps-object-tiny -lpthread $(TINYSTM_LIB)\n\n\n#\n# SPS for persistent memory\n#\nbin/psps-integer: psps-integer.cpp $(PTMS) PBenchmarkSPS.hpp lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) psps-integer.cpp -o bin/psps-integer -lpthread $(PMDKLIBS) lib/libromulus.a\n\nbin/psps-integer-atlas: psps-integer-atlas.cpp $(PTMS) PBenchmarkSPS.hpp persistencyclean lib/libromulus.a\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) psps-integer-atlas.cpp -o bin/psps-integer-atlas -lpthread lib/libromulus.a\n\t\n\n# TODO: is it worth doing sps-object for PTMs ?\n\n\n#\n# Latency for STMs\n#\nbin/latency-counter: latency-counter.cpp $(STMS) BenchmarkLatencyCounter.hpp\n\t$(CXX) $(CXXFLAGS) $(INCLUDES) $(CSRCS) latency-counter.cpp -o bin/latency-counter -lpthread $(ESTM_LIB)\n\nbin/latency-counter-tiny: latency-counter.cpp $(STMS) BenchmarkLatencyCounter.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_TINY $(INCLUDES) $(TINYSTM_INC) $(CSRCS) latency-counter.cpp -o bin/latency-counter-tiny -lpthread $(TINYSTM_LIB)\n\n\n\n\t\n# \n# Persistent balanced tree with 1M keys. Must be compiled one at a time otherwise you get all the NVM heaps allocated, which is too much \n#\nbin/pset-tree-1m-romlog: pset-tree-1m.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp lib/libromulus.a \n\t$(CXX) $(CXXFLAGS) -DUSE_ROMLOG $(INCLUDES) pset-tree-1m.cpp -o bin/pset-tree-1m-romlog -lpthread lib/libromulus.a\n\nbin/pset-tree-1m-romlr: pset-tree-1m.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp lib/libromulus.a \n\t$(CXX) $(CXXFLAGS) -DUSE_ROMLR $(INCLUDES) pset-tree-1m.cpp -o bin/pset-tree-1m-romlr -lpthread lib/libromulus.a\n\nbin/pset-tree-1m-oflf: pset-tree-1m.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp ../ptms/OneFilePTMLF.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_OFLF $(INCLUDES) pset-tree-1m.cpp -o bin/pset-tree-1m-oflf -lpthread\n\nbin/pset-tree-1m-ofwf: pset-tree-1m.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp ../ptms/OneFilePTMWF.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_OFWF $(INCLUDES) pset-tree-1m.cpp -o bin/pset-tree-1m-ofwf -lpthread\n\nbin/pset-tree-1m-pmdk: pset-tree-1m.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp \n\t$(CXX) $(CXXFLAGS) -DUSE_PMDK $(INCLUDES) pset-tree-1m.cpp -o bin/pset-tree-1m-pmdk -lpthread $(PMDKLIBS)\n\t\n\n# experimental...\nbin/pread-while-writing-romlog: pread-while-writing.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp lib/libromulus.a \n\t$(CXX) $(CXXFLAGS) -DUSE_ROMLOG $(INCLUDES) pread-while-writing.cpp -o bin/pread-while-writing-romlog -lpthread lib/libromulus.a\n\nbin/pread-while-writing-romlr: pread-while-writing.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp lib/libromulus.a \n\t$(CXX) $(CXXFLAGS) -DUSE_ROMLR $(INCLUDES) pread-while-writing.cpp -o bin/pread-while-writing-romlr -lpthread lib/libromulus.a\n\nbin/pread-while-writing-oflf: pread-while-writing.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp ../ptms/OneFilePTMLF.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_OFLF $(INCLUDES) pread-while-writing.cpp -o bin/pread-while-writing-oflf -lpthread\n\nbin/pread-while-writing-ofwf: pread-while-writing.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp ../ptms/OneFilePTMWF.hpp\n\t$(CXX) $(CXXFLAGS) -DUSE_OFWF $(INCLUDES) pread-while-writing.cpp -o bin/pread-while-writing-ofwf -lpthread\n\nbin/pread-while-writing-pmdk: pread-while-writing.cpp PBenchmarkSets.hpp ../pdatastructures/TMRedBlackTree.hpp \n\t$(CXX) $(CXXFLAGS) -DUSE_PMDK $(INCLUDES) pread-while-writing.cpp -o bin/pread-while-writing-pmdk -lpthread $(PMDKLIBS)\n\t\n"
  },
  {
    "path": "graphs/PBenchmarkQueues.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_BENCHMARK_Q_H_\r\n#define _PERSISTENT_BENCHMARK_Q_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n#include <cassert>\r\n\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\nstruct UserData  {\r\n    long long seq;\r\n    int tid;\r\n    UserData(long long lseq, int ltid) {\r\n        this->seq = lseq;\r\n        this->tid = ltid;\r\n    }\r\n    UserData() {\r\n        this->seq = -2;\r\n        this->tid = -2;\r\n    }\r\n    UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n    bool operator < (const UserData& other) const {\r\n        return seq < other.seq;\r\n    }\r\n};\r\n\r\n\r\n/**\r\n * This is a micro-benchmark for persistent queues\r\n */\r\nclass PBenchmarkQueues {\r\n\r\nprivate:\r\n\r\n    struct Result {\r\n        nanoseconds nsEnq = 0ns;\r\n        nanoseconds nsDeq = 0ns;\r\n        long long numEnq = 0;\r\n        long long numDeq = 0;\r\n        long long totOpsSec = 0;\r\n\r\n        Result() { }\r\n\r\n        Result(const Result &other) {\r\n            nsEnq = other.nsEnq;\r\n            nsDeq = other.nsDeq;\r\n            numEnq = other.numEnq;\r\n            numDeq = other.numDeq;\r\n            totOpsSec = other.totOpsSec;\r\n        }\r\n\r\n        bool operator < (const Result& other) const {\r\n            return totOpsSec < other.totOpsSec;\r\n        }\r\n    };\r\n\r\n    // Performance benchmark constants\r\n    static const long long kNumPairsWarmup =     1000000LL;     // Each threads does 1M iterations as warmup\r\n\r\n    // Contants for Ping-Pong performance benchmark\r\n    static const int kPingPongBatch = 1000;            // Each thread starts by injecting 1k items in the queue\r\n\r\n\r\n    static const long long NSEC_IN_SEC = 1000000000LL;\r\n\r\n    int numThreads;\r\n\r\npublic:\r\n\r\n    PBenchmarkQueues(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n\r\n    /**\r\n     * enqueue-dequeue pairs: in each iteration a thread executes an enqueue followed by a dequeue;\r\n     * the benchmark executes 10^8 pairs partitioned evenly among all threads;\r\n     * WARNING: If you modify this, please modify enqDeqNoTransaction() also\r\n     */\r\n    template<typename Q, typename PTM>\r\n    uint64_t enqDeq(std::string& className, const long numPairs, const int numRuns) {\r\n        nanoseconds deltas[numThreads][numRuns];\r\n        atomic<bool> startFlag = { false };\r\n        Q* queue = nullptr;\r\n        className = Q::className();\r\n        cout << \"##### \" << className << \" #####  \\n\";\r\n\r\n        auto enqdeq_lambda = [this,&startFlag,&numPairs,&queue](nanoseconds *delta, const int tid) {\r\n            //UserData* ud = new UserData{0,0};\r\n            uint64_t* ud = new uint64_t(42);\r\n            while (!startFlag.load()) {} // Spin until the startFlag is set\r\n            // Warmup phase\r\n            for (long long iter = 0; iter < numPairs/(numThreads*10); iter++) { // Do 1/10 iterations as warmup\r\n                PTM::updateTx([=] () {\r\n                    queue->enqueue(*ud, tid);\r\n                    if (queue->dequeue(tid) == queue->EMPTY) cout << \"Error at warmup dequeueing iter=\" << iter << \"\\n\";\r\n                });\r\n            }\r\n            // Measurement phase\r\n            auto startBeats = steady_clock::now();\r\n            for (long long iter = 0; iter < numPairs/numThreads; iter++) {\r\n                PTM::updateTx([=] () {\r\n                    queue->enqueue(*ud, tid);\r\n                    if (queue->dequeue(tid) == queue->EMPTY) cout << \"Error at measurement dequeueing iter=\" << iter << \"\\n\";\r\n                });\r\n            }\r\n            auto stopBeats = steady_clock::now();\r\n            *delta = stopBeats - startBeats;\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            PTM::updateTx([&] () { // It's ok to capture by reference, only the main thread is active (but it is not ok for CX-PTM)\r\n                queue = PTM::template tmNew<Q>();\r\n            });\r\n            thread enqdeqThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid] = thread(enqdeq_lambda, &deltas[tid][irun], tid);\r\n            startFlag.store(true);\r\n            // Sleep for 2 seconds just to let the threads see the startFlag\r\n            this_thread::sleep_for(2s);\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\r\n            startFlag.store(false);\r\n            PTM::updateTx([=] () {\r\n                PTM::tmDelete(queue);\r\n            });\r\n        }\r\n\r\n        // Sum up all the time deltas of all threads so we can find the median run\r\n        vector<nanoseconds> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            agg[irun] = 0ns;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg[irun] += deltas[tid][irun];\r\n            }\r\n        }\r\n\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto median = agg[numRuns/2].count()/numThreads; // Normalize back to per-thread time (mean of time for this run)\r\n\r\n        cout << \"Total Ops/sec = \" << numPairs*2*NSEC_IN_SEC/median << \"\\n\";\r\n        return (numPairs*2*NSEC_IN_SEC/median);\r\n    }\r\n\r\n\r\n    /*\r\n     * WARNING: If you modify this, please modify enqDeq() also\r\n     */\r\n    template<typename Q>\r\n    uint64_t enqDeqNoTransaction(std::string& className, const long numPairs, const int numRuns) {\r\n        nanoseconds deltas[numThreads][numRuns];\r\n        atomic<bool> startFlag = { false };\r\n        Q* queue = nullptr;\r\n        className = Q::className();\r\n        cout << \"##### \" << className << \" #####  \\n\";\r\n\r\n        auto enqdeq_lambda = [this,&startFlag,&numPairs,&queue](nanoseconds *delta, const int tid) {\r\n            uint64_t* ud = new uint64_t(42);\r\n            while (!startFlag.load()) {} // Spin until the startFlag is set\r\n            // Warmup phase\r\n            for (long long iter = 0; iter < numPairs/(numThreads*10); iter++) { // Do 1/10 iterations as warmup\r\n                queue->enqueue(*ud, tid);\r\n                if (queue->dequeue(tid) == queue->EMPTY) cout << \"Error at warmup dequeueing iter=\" << iter << \"\\n\";\r\n            }\r\n            // Measurement phase\r\n            auto startBeats = steady_clock::now();\r\n            for (long long iter = 0; iter < numPairs/numThreads; iter++) {\r\n                queue->enqueue(*ud, tid);\r\n                if (queue->dequeue(tid) == queue->EMPTY) cout << \"Error at measurement dequeueing iter=\" << iter << \"\\n\";\r\n            }\r\n            auto stopBeats = steady_clock::now();\r\n            *delta = stopBeats - startBeats;\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            queue = new Q();  // TODO: use a PTM allocator, maybe the one in PMDK\r\n            thread enqdeqThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid] = thread(enqdeq_lambda, &deltas[tid][irun], tid);\r\n            startFlag.store(true);\r\n            // Sleep for 2 seconds just to let the threads see the startFlag\r\n            this_thread::sleep_for(2s);\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\r\n            startFlag.store(false);\r\n            delete queue;   // TODO: use PTM de-allocator\r\n        }\r\n\r\n        // Sum up all the time deltas of all threads so we can find the median run\r\n        vector<nanoseconds> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            agg[irun] = 0ns;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                agg[irun] += deltas[tid][irun];\r\n            }\r\n        }\r\n\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto median = agg[numRuns/2].count()/numThreads; // Normalize back to per-thread time (mean of time for this run)\r\n\r\n        cout << \"Total Ops/sec = \" << numPairs*2*NSEC_IN_SEC/median << \"\\n\";\r\n        return (numPairs*2*NSEC_IN_SEC/median);\r\n    }\r\n\r\n\r\n\r\n    /**\r\n     * Start with only enqueues 100K/numThreads, wait for them to finish, then do only dequeues but only 100K/numThreads\r\n     * TODO: must fix this for persistency, not yet working\r\n     */\r\n    template<typename Q>\r\n    void burst(std::string& className, uint64_t& resultsEnq, uint64_t& resultsDeq,\r\n               const long long burstSize, const int numIters, const int numRuns, const bool isSC=false) {\r\n        Result results[numThreads][numRuns];\r\n        atomic<bool> startEnq = { false };\r\n        atomic<bool> startDeq = { false };\r\n        atomic<long> barrier = { 0 };\r\n        Q* queue = nullptr;\r\n\r\n        auto burst_lambda = [this,&startEnq,&startDeq,&burstSize,&barrier,&numIters,&isSC,&queue](Result *res, const int tid) {\r\n            UserData ud(0,0);\r\n            // Warmup only if it is not Single-Consumer\r\n            if (!isSC) {\r\n                const long long warmupIters = 100000LL;  // Do 100K for each thread as a warmup\r\n                for (long long iter = 0; iter < warmupIters; iter++) queue->enqueue(&ud, tid);\r\n                for (long long iter = 0; iter < warmupIters; iter++) {\r\n                    if (queue->dequeue(tid) == nullptr) cout << \"ERROR: warmup dequeued nullptr in iter=\" << iter << \"\\n\";\r\n                }\r\n            }\r\n            // Measurements\r\n            for (int iter = 0; iter < numIters; iter++) {\r\n                // Start with enqueues\r\n                while (!startEnq.load()) {} // spin is better than yield here\r\n                auto startBeats = steady_clock::now();\r\n                for (long long i = 0; i < burstSize/numThreads; i++) {\r\n                    queue->enqueue(&ud, tid);\r\n                }\r\n                auto stopBeats = steady_clock::now();\r\n                res->nsEnq += (stopBeats-startBeats);\r\n                res->numEnq += burstSize/numThreads;\r\n                if (barrier.fetch_add(1) == numThreads) cout << \"ERROR: in barrier\\n\";\r\n                // dequeues\r\n                while (!startDeq.load()) { } // spin is better than yield here\r\n                if (isSC) { // Handle the single-consumer case\r\n                    if (tid == 0) {\r\n                        startBeats = steady_clock::now();\r\n                        // We need to deal with rounding errors in the single-consumer case\r\n                        for (long long i = 0; i < ((long long)(burstSize/numThreads))*numThreads; i++) {\r\n                            if (queue->dequeue(tid) == nullptr) {\r\n                                cout << \"ERROR: dequeued nullptr in iter=\" << i << \"\\n\";\r\n                                assert(false);\r\n                            }\r\n                        }\r\n                        stopBeats = steady_clock::now();\r\n                        if (queue->dequeue(tid) != nullptr) cout << \"ERROR: dequeued non-null, there must be duplicate items!\\n\";\r\n                        res->nsDeq += (stopBeats-startBeats);\r\n                        res->numDeq += burstSize/numThreads;\r\n                    }\r\n                } else {\r\n                    startBeats = steady_clock::now();\r\n                    for (long long i = 0; i < burstSize/numThreads; i++) {\r\n                        if (queue->dequeue(tid) == nullptr) {\r\n                            cout << \"ERROR: dequeued nullptr in iter=\" << i << \"\\n\";\r\n                            assert(false);\r\n                        }\r\n                    }\r\n                    stopBeats = steady_clock::now();\r\n                    res->nsDeq += (stopBeats-startBeats);\r\n                    res->numDeq += burstSize/numThreads;\r\n                }\r\n                if (barrier.fetch_add(1) == numThreads) cout << \"ERROR: in barrier\\n\";\r\n            }\r\n        };\r\n\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            queue = new Q(numThreads);\r\n            if (irun == 0) {\r\n                className = queue->className();\r\n                cout << \"##### \" << queue->className() << \" #####  \\n\";\r\n            }\r\n            thread burstThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) burstThreads[tid] = thread(burst_lambda, &results[tid][irun], tid);\r\n            this_thread::sleep_for(100ms);\r\n            for (int iter=0; iter < numIters; iter++) {\r\n                // enqueue round\r\n                startEnq.store(true);\r\n                while (barrier.load() != numThreads) this_thread::yield();\r\n                startEnq.store(false);\r\n                long tmp =  numThreads;\r\n                if (!barrier.compare_exchange_strong(tmp, 0)) cout << \"ERROR: CAS\\n\";\r\n                // dequeue round\r\n                startDeq.store(true);\r\n                while (barrier.load() != numThreads) this_thread::yield();\r\n                startDeq.store(false);\r\n                tmp = numThreads;\r\n                if (!barrier.compare_exchange_strong(tmp, 0)) cout << \"ERROR: CAS\\n\";\r\n            }\r\n            for (int tid = 0; tid < numThreads; tid++) burstThreads[tid].join();\r\n            delete queue;\r\n        }\r\n\r\n        // Accounting\r\n        vector<Result> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            nanoseconds maxNsEnq = 0ns;\r\n            nanoseconds maxNsDeq = 0ns;\r\n            for (int tid = 0; tid < numThreads; tid++) {\r\n                if (results[tid][irun].nsEnq > maxNsEnq) maxNsEnq = results[tid][irun].nsEnq;\r\n                if (results[tid][irun].nsDeq > maxNsDeq) maxNsDeq = results[tid][irun].nsDeq;\r\n                agg[irun].numEnq += results[tid][irun].numEnq;\r\n                agg[irun].numDeq += results[tid][irun].numDeq;\r\n            }\r\n            agg[irun].nsEnq = maxNsEnq;\r\n            agg[irun].nsDeq = maxNsDeq;\r\n            agg[irun].totOpsSec = agg[irun].nsEnq.count()+agg[irun].nsDeq.count();\r\n        }\r\n\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        Result median = agg[numRuns/2];\r\n        const long long allThreadsEnqPerSec = median.numEnq*NSEC_IN_SEC/median.nsEnq.count();\r\n        const long long allThreadsDeqPerSec = median.numDeq*NSEC_IN_SEC/median.nsDeq.count();\r\n\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        cout << \"Enq/sec = \" << allThreadsEnqPerSec << \"   Deq/sec = \" << allThreadsDeqPerSec << \"\\n\";\r\n        resultsEnq = allThreadsEnqPerSec;\r\n        resultsDeq = allThreadsDeqPerSec;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/PBenchmarkSPS.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_BENCHMARK_SPS_H_\r\n#define _PERSISTENT_BENCHMARK_SPS_H_\r\n\r\n#include <atomic>\r\n#include <chrono>\r\n#include <thread>\r\n#include <string>\r\n#include <vector>\r\n#include <algorithm>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <typeinfo>\r\n\r\nstatic const long arraySize=1000*1000;   // 1M entries in the SPS array\r\n\r\nusing namespace std;\r\nusing namespace chrono;\r\n\r\n\r\n/**\r\n * This is a micro-benchmark with integer swaps (SPS) for PTMs\r\n */\r\nclass PBenchmarkSPS {\r\n\r\nprivate:\r\n    int numThreads;\r\n\r\npublic:\r\n    struct UserData  {\r\n        long long seq;\r\n        int tid;\r\n        UserData(long long lseq, int ltid) {\r\n            this->seq = lseq;\r\n            this->tid = ltid;\r\n        }\r\n        UserData() {\r\n            this->seq = -2;\r\n            this->tid = -2;\r\n        }\r\n        UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\r\n\r\n        bool operator < (const UserData& other) const {\r\n            return seq < other.seq;\r\n        }\r\n    };\r\n\r\n    PBenchmarkSPS(int numThreads) {\r\n        this->numThreads = numThreads;\r\n    }\r\n\r\n\r\n    /*\r\n     * An array of integers that gets randomly permutated.\r\n     */\r\n    template<typename PTM, template<typename> class PERSIST>\r\n    uint64_t benchmarkSPSInteger(std::string& className, const seconds testLengthSeconds, const long numSwapsPerTx, const int numRuns) {\r\n        long long ops[numThreads][numRuns];\r\n        long long lengthSec[numRuns];\r\n        atomic<bool> startFlag = { false };\r\n        atomic<bool> quit = { false };\r\n\r\n        // Create the array of integers and initialize it, saving it in root pointer 0\r\n        int larraySize = arraySize;\r\n        PTM::template updateTx<bool>([larraySize] () {\r\n            //PTM::pfree( PTM::template get_object<PERSIST<uint64_t>>(0) ); // TODO: re-enable this after we add the clear of objects as a transaction in CX\r\n            PTM::put_object(0, PTM::pmalloc( larraySize*sizeof(PERSIST<uint64_t>*) ));\r\n            return true;\r\n        });\r\n        // Break up the initialization into transactions of 1k stores, so it fits in the log\r\n        for (long j = 0; j < arraySize; j+=1000) {\r\n            PTM::template updateTx<bool>([larraySize,j] () {\r\n                PERSIST<uint64_t>* parray = PTM::template get_object<PERSIST<uint64_t>>(0);\r\n                for (int i = 0; i < 1000 && i+j < larraySize; i++) parray[i+j] = i+j;\r\n                return true;\r\n            } );\r\n        }\r\n\r\n        auto func = [this,&startFlag,&quit,&numSwapsPerTx](long long *ops, const int tid) {\r\n            uint64_t seed = (tid*1024)+tid+1234567890123456781ULL;\r\n            int larraySize = arraySize;\r\n            // Spin until the startFlag is set\r\n            while (!startFlag.load()) {}\r\n            // Do transactions until the quit flag is set\r\n            long long tcount = 0;\r\n            while (!quit.load()) {\r\n                // Everything has to be captured by value, or get/put in root pointers\r\n                PTM::template updateTx<bool>([seed,numSwapsPerTx,larraySize] () {\r\n                    PERSIST<uint64_t>* parray = PTM::template get_object<PERSIST<uint64_t>>(0);\r\n                    uint64_t lseed = seed;\r\n                    for (int i = 0; i < numSwapsPerTx; i++) {\r\n                        lseed = randomLong(lseed);\r\n                        auto ia = lseed%arraySize;\r\n                        uint64_t tmp = parray[ia];\r\n                        lseed = randomLong(lseed);\r\n                        auto ib = lseed%arraySize;\r\n                        parray[ia] = parray[ib];\r\n                        parray[ib] = tmp;\r\n                    }\r\n                    return true;\r\n                });\r\n                // Can't have capture by ref for wait-free, so replicate seed advance outside tx\r\n                seed = randomLong(seed);\r\n                seed = randomLong(seed);\r\n                ++tcount;\r\n                /*\r\n                    PE::read_transaction([this,&seed,&parray,&numWordsPerTransaction] () {\r\n                        PersistentArrayInt<persist>* read_array = PE::template get_object<PersistentArrayInt<persist>>(PIDX_INT_ARRAY);\r\n                        // Check that the array is consistent\r\n                        int sum = 0;\r\n                        for (int i = 0; i < arraySize; i++) {\r\n                            sum += read_array->counters[i];\r\n                        }\r\n                        assert(sum == 0);\r\n                    } );\r\n                */\r\n            }\r\n            *ops = tcount;\r\n        };\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n            if (irun == 0) {\r\n                className = PTM::className();\r\n                cout << \"##### \" << PTM::className() << \" #####  \\n\";\r\n            }\r\n            thread enqdeqThreads[numThreads];\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid] = thread(func, &ops[tid][irun], tid);\r\n            auto startBeats = steady_clock::now();\r\n            startFlag.store(true);\r\n            // Sleep for 20 seconds\r\n            this_thread::sleep_for(testLengthSeconds);\r\n            quit.store(true);\r\n            auto stopBeats = steady_clock::now();\r\n            for (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\r\n            lengthSec[irun] = (stopBeats-startBeats).count();\r\n            startFlag.store(false);\r\n            quit.store(false);\r\n        }\r\n\r\n        PTM::template updateTx<bool>([] () {\r\n            PTM::pfree( PTM::template get_object<PERSIST<uint64_t>>(0) );\r\n            PTM::template put_object<void>(0, nullptr);\r\n            return true;\r\n        });\r\n\r\n        // Accounting\r\n        vector<long long> agg(numRuns);\r\n        for (int irun = 0; irun < numRuns; irun++) {\r\n        \tfor(int i=0;i<numThreads;i++){\r\n        \t\tagg[irun] += ops[i][irun]*1000000000LL/lengthSec[irun];\r\n        \t}\r\n        }\r\n        // Compute the median. numRuns should be an odd number\r\n        sort(agg.begin(),agg.end());\r\n        auto maxops = agg[numRuns-1];\r\n        auto minops = agg[0];\r\n        auto medianops = agg[numRuns/2];\r\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\r\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\r\n        std::cout << \"Swaps/sec = \" << medianops*numSwapsPerTx << \"     delta = \" << delta*numSwapsPerTx << \"%   min = \" << minops*numSwapsPerTx << \"   max = \" << maxops*numSwapsPerTx << \"\\n\";\r\n        return medianops*numSwapsPerTx;\r\n    }\r\n\r\n\r\n    /**\r\n     * An imprecise but fast random number generator\r\n     */\r\n    static uint64_t randomLong(uint64_t x) {\r\n        x ^= x >> 12; // a\r\n        x ^= x << 25; // b\r\n        x ^= x >> 27; // c\r\n        return x * 2685821657736338717LL;\r\n    }\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "graphs/PBenchmarkSets.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _PERSISTENT_BENCHMARK_SETS_H_\n#define _PERSISTENT_BENCHMARK_SETS_H_\n\n#include <atomic>\n#include <chrono>\n#include <thread>\n#include <string>\n#include <vector>\n#include <algorithm>\n#include <iostream>\n\nusing namespace std;\nusing namespace chrono;\n\ntemplate <template <typename> class TMTYPE>\nstruct UserData  {\n    TMTYPE<long long> seq;\n    TMTYPE<int> tid;\n    UserData(long long lseq, int ltid=0) {\n        this->seq = lseq;\n        this->tid = ltid;\n    }\n    UserData() {\n        this->seq = -2;\n        this->tid = -2;\n    }\n    UserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\n\n    bool operator < (const UserData& other) const {\n        return seq.pload() < other.seq.pload();\n    }\n    bool operator == (const UserData& other) const {\n        return seq.pload() == other.seq.pload() && tid.pload() == other.tid.pload();\n    }\n};\n\n#ifdef NEVER\nnamespace std {\n    template <>\n    struct hash<UserData> {\n        std::size_t operator()(const UserData& k) const {\n            using std::size_t;\n            using std::hash;\n            return (hash<long long>()(k.seq.pload()));  // This hash has no collisions, which is irealistic\n            /*\n            long long x = k.seq;\n            x ^= x >> 12; // a\n            x ^= x << 25; // b\n            x ^= x >> 27; // c\n            return hash<long long>()(x * 2685821657736338717LL);\n            */\n        }\n    };\n}\n#endif\n\n\n/**\n * This is a micro-benchmark of sets, used in the CX paper\n */\ntemplate<typename K>\nclass PBenchmarkSets {\n\nprivate:\n    struct Result {\n        nanoseconds nsEnq = 0ns;\n        nanoseconds nsDeq = 0ns;\n        long long numEnq = 0;\n        long long numDeq = 0;\n        long long totOpsSec = 0;\n\n        Result() { }\n\n        Result(const Result &other) {\n            nsEnq = other.nsEnq;\n            nsDeq = other.nsDeq;\n            numEnq = other.numEnq;\n            numDeq = other.numDeq;\n            totOpsSec = other.totOpsSec;\n        }\n\n        bool operator < (const Result& other) const {\n            return totOpsSec < other.totOpsSec;\n        }\n    };\n\n    static const long long NSEC_IN_SEC = 1000000000LL;\n\n    bool firstTime = true;\n\npublic:\n    /**\n     * When doing \"updates\" we execute a random removal and if the removal is successful we do an add() of the\n     * same item immediately after. This keeps the size of the data structure equal to the original size (minus\n     * MAX_THREADS items at most) which gives more deterministic results.\n     */\n    template<typename S, typename PTM>\n    long long benchmark(std::string& className, int numThreads, const int updateRatio, const seconds testLengthSeconds, const int numRuns, const int numElements, const bool dedicated=false) {\n    \tint num_threads = numThreads;\n    \tif (dedicated) num_threads = numThreads+2;\n        long long ops[num_threads][numRuns];\n        long long lengthSec[numRuns];\n        atomic<bool> quit = { false };\n        atomic<bool> startFlag = { false };\n        atomic<int> startAtZero = { false };\n\n        className = S::className();\n        std::cout << \"##### \" << S::className() << \" #####  \\n\";\n        S* set = nullptr;\n\n        // Create all the keys in the concurrent set\n        K** udarray = new K*[numElements];\n        for (int i = 0; i < numElements; i++) udarray[i] = new K(i);\n        // Create the set in persistent memory\n        PTM::template updateTx<bool>([&] () {\n            set = PTM::template tmNew<S>();\n            return true;\n        });\n        // Add all the items, one at a time, otherwise the transaction is too big to fit in the logs\n        set->addAll(udarray, numElements);\n\n        // Can either be a Reader or a Writer\n        auto rw_lambda = [this,&quit,&startFlag,&startAtZero,&set,&udarray,&numElements](const int updateRatio, long long *ops, const int tid) {\n            long long numOps = 0;\n            uint64_t seed = tid*133 + 1234567890123456781ULL;\n            if (firstTime) {\n                // Execute 1k iterations as warmup and then spin wwait for all other threads\n                for (uint64_t iter = 0; iter < 1000; iter++) {\n                    seed = randomLong(seed);\n                    auto ix = (unsigned int)(seed%numElements);\n                    if (set->remove(*udarray[ix])) set->add(*udarray[ix]);\n                }\n            }\n            startAtZero.fetch_add(-1);\n            // spin waiting for all other threads before starting the measurements\n            // (we wait for startAtZero to be zero on the main thread).\n            while (!startFlag.load()) ; // spin\n            while (!quit.load()) {\n                seed = randomLong(seed);\n                int update = seed%1000;\n                seed = randomLong(seed);\n                auto ix = (unsigned int)(seed%numElements);\n                if (update < updateRatio) {\n                    // I'm a Writer\n                    if (set->remove(*udarray[ix])) {\n                    \tnumOps++;\n                    \tset->add(*udarray[ix]);\n                    }\n                    numOps++;\n                } else {\n                \t// I'm a Reader\n                    set->contains(*udarray[ix]);\n                    seed = randomLong(seed);\n                    ix = (unsigned int)(seed%numElements);\n                    set->contains(*udarray[ix]);\n                    numOps+=2;\n                }\n\n            }\n            *ops = numOps;\n        };\n\n        for (int irun = 0; irun < numRuns; irun++) {\n            startAtZero.store(num_threads);\n            thread rwThreads[num_threads];\n            if (dedicated) {\n                rwThreads[0] = thread(rw_lambda, 1000, &ops[0][irun], 0);\n                rwThreads[1] = thread(rw_lambda, 1000, &ops[1][irun], 1);\n                for (int tid = 2; tid < num_threads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\n            } else {\n                for (int tid = 0; tid < num_threads; tid++) rwThreads[tid] = thread(rw_lambda, updateRatio, &ops[tid][irun], tid);\n            }\n            this_thread::sleep_for(100ms);\n            // Wait for startAtZero to be zero (all threads have done the 1k iteration warmup)\n            while (startAtZero.load() != 0) ;\n            auto startBeats = steady_clock::now();\n            startFlag.store(true);\n            // Sleep for testLengthSeconds seconds\n            this_thread::sleep_for(testLengthSeconds);\n            quit.store(true);\n            auto stopBeats = steady_clock::now();\n            for (int tid = 0; tid < num_threads; tid++) {\n            \trwThreads[tid].join();\n            }\n            lengthSec[irun] = (stopBeats-startBeats).count();\n            if (dedicated) {\n                // We don't account for the write-only operations but we aggregate the values from the two threads and display them\n                std::cout << \"Mutative transactions per second = \" << (ops[0][irun] + ops[1][irun])*1000000000LL/lengthSec[irun] << \"\\n\";\n                ops[0][irun] = 0;\n                ops[1][irun] = 0;\n            }\n            quit.store(false);\n            startFlag.store(false);\n            // Compute ops at the end of each run\n            long long agg = 0;\n            for (int tid = 0; tid < num_threads; tid++) {\n                agg += ops[tid][irun]*1000000000LL/lengthSec[irun];\n            }\n            firstTime = false;\n        }\n\n        // Clear the set, one key at a time and then delete the instance\n        for (int i = 0; i < numElements; i++) {\n            PTM::template updateTx<bool>([=] () {\n                set->remove(*udarray[i]);\n                return true;\n            });\n        }\n        PTM::template updateTx<bool>([=] () {\n            PTM::tmDelete(set);\n            return true;\n        });\n        // Delete all the keys\n        for (int i = 0; i < numElements; i++) delete udarray[i];\n        delete[] udarray;\n\n        // Accounting\n        vector<long long> agg(numRuns);\n        for (int irun = 0; irun < numRuns; irun++) {\n            for (int tid = 0; tid < num_threads; tid++) {\n                agg[irun] += ops[tid][irun]*1000000000LL/lengthSec[irun];\n            }\n        }\n\n        // Compute the median. numRuns must be an odd number\n        sort(agg.begin(),agg.end());\n        auto maxops = agg[numRuns-1];\n        auto minops = agg[0];\n        auto medianops = agg[numRuns/2];\n        auto delta = (long)(100.*(maxops-minops) / ((double)medianops));\n        // Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\n        std::cout << \"Ops/sec = \" << medianops << \"      delta = \" << delta << \"%   min = \" << minops << \"   max = \" << maxops << \"\\n\";\n        return medianops;\n    }\n\n\n    /**\n     * An imprecise but fast random number generator\n     */\n    uint64_t randomLong(uint64_t x) {\n        x ^= x >> 12; // a\n        x ^= x << 25; // b\n        x ^= x >> 27; // c\n        return x * 2685821657736338717LL;\n    }\n};\n\n#endif\n"
  },
  {
    "path": "graphs/README.md",
    "content": "Every .cpp file here outputs a plot taken from a benchmark.\r\nThe corresponding tab-separated values are placed in the data/ folder and can then be read by gnuplot to make the actual plots.\r\nThe .gp and corresponding pdf files are in the plots/ folder.\r\nTo generate the plots, type:\r\ncd plots\r\n./plot-all.sh\r\n"
  },
  {
    "path": "graphs/bin/.gitignore",
    "content": "/pset-ll-1k\n/psps-integer\n/q-array-enq-deq\n/q-ll-burst\n/q-ll-enq-deq\n/q-ll-enq-deq-tiny\n/set-hash-1k-tiny\n/set-ll-10k\n/set-ll-10k-tiny\n/set-ll-1k\n/set-ll-1k-tiny\n/set-tree-10k\n/set-tree-10k-tiny\n/set-tree-1k\n/set-tree-1k-tiny\n/sps-integer\n/sps-integer-oversubs\n/sps-integer-tiny\n/sps-object\n/sps-object-tiny\n/psps-integer-atlas\n/set-hash-1k\n/pset-ll-10k\n/pset-hash-1k\n/pq-ll-enq-deq\n/pset-tree-1k\n/q-array-enq-deq-tiny\n/latency-counter\n/latency-counter-tiny\n/set-tree-1m\n/set-tree-1m-tiny\n/pset-tree-1m\n/pset-tree-1m-oflf\n/pset-tree-1m-ofwf\n/pset-tree-1m-pmdk\n/pset-tree-1m-romlog\n/pset-tree-1m-romlr\n/pread-while-writing-oflf\n/pread-while-writing-ofwf\n/pread-while-writing-pmdk\n/pread-while-writing-romlog\n/pread-while-writing-romlr\n"
  },
  {
    "path": "graphs/data/README.md",
    "content": "The benchmarks will generate data here"
  },
  {
    "path": "graphs/latency-counter.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkLatencyCounter.hpp\"\r\n#include \"stms/OneFileLF.hpp\"\r\n#include \"stms/OneFileWF.hpp\"\r\n#if defined USE_TINY\r\n#include \"stms/TinySTM.hpp\"\r\n#define DATA_FILENAME \"data/latency-counter-tiny.txt\"\r\n#else\r\n#include \"stms/ESTM.hpp\"\r\n#define DATA_FILENAME \"data/latency-counter.txt\"\r\n#endif\r\n\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8 };             // For the laptop\r\n    //vector<int> threadList = { 1, 2, 4, 8, 16, 32, 62 };             // For the cervino\r\n    const int EMAX_CLASS = 10;\r\n    BenchmarkLatencyCounter::Result results[EMAX_CLASS][threadList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size());\r\n\r\n    for (unsigned it = 0; it < threadList.size(); it++) {\r\n        auto nThreads = threadList[it];\r\n        int ic = 0;\r\n        BenchmarkLatencyCounter bench(nThreads);\r\n        std::cout << \"\\n----- Latency Counter    nThreads=\" << nThreads << \" -----\\n\";\r\n#if defined USE_TINY\r\n        results[ic][it] = bench.latencyBenchmark<tinystm::TinySTM,tinystm::tmtype>(cNames[ic]);\r\n        ic++;\r\n#else\r\n        results[ic][it] = bench.latencyBenchmark<oflf::OneFileLF,oflf::tmtype>(cNames[ic]);\r\n        ic++;\r\n        results[ic][it] = bench.latencyBenchmark<ofwf::OneFileWF,ofwf::tmtype>(cNames[ic]);\r\n        ic++;\r\n        results[ic][it] = bench.latencyBenchmark<estm::ESTM,estm::tmtype>(cNames[ic]);\r\n        ic++;\r\n#endif\r\n        maxClass = ic;\r\n     }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and percentiles for each column\r\n    for (int ic = 0; ic < maxClass; ic++) {\r\n        dataFile << cNames[ic] << \"-50%\"<< \"\\t\";\r\n        dataFile << cNames[ic] << \"-90%\"<< \"\\t\";\r\n        dataFile << cNames[ic] << \"-99%\"<< \"\\t\";\r\n        dataFile << cNames[ic] << \"-99.9%\"<< \"\\t\";\r\n        dataFile << cNames[ic] << \"-99.99%\"<< \"\\t\";\r\n        dataFile << cNames[ic] << \"-99.999%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (int ic = 0; ic < maxClass; ic++) {\r\n            dataFile << results[ic][it].delay50000 << \"\\t\";\r\n            dataFile << results[ic][it].delay90000 << \"\\t\";\r\n            dataFile << results[ic][it].delay99000 << \"\\t\";\r\n            dataFile << results[ic][it].delay99900 << \"\\t\";\r\n            dataFile << results[ic][it].delay99990 << \"\\t\";\r\n            dataFile << results[ic][it].delay99999 << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/lib/.gitignore",
    "content": "/libromulus.a\n/mallocromlog.o\n/mallocromlr.o\n/romlog.o\n/romlr.o\n/threadregistry.o\n"
  },
  {
    "path": "graphs/plots/caption.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"caption.eps\"\n\nset size 0.95,0.15\n\nload \"styles.inc\"\n\nunset tics\nunset border\nunset xlabel\nunset ylabel\nunset label\n\nset object 1 rectangle from screen 0.02,0.01 to screen 0.925,0.14 fillcolor rgb \"white\" dashtype (2,3) behind\nset label at screen 0.5,0.11 center \"{/Helvetica-bold Legend for volatile memory} (all graphs of {\\247}V.A)\"\n\nset key at screen 0.9,0.07 samplen 1.5 maxrows 2 width 0.25\nplot [][0:1] \\\n    2 with linespoints title 'OF-LF'        ls 1 lw 3 dt 1, \\\n    2 with linespoints title 'OF-WF'        ls 2 lw 3 dt 1, \\\n    2 with linespoints title 'ESTM'         ls 3 lw 3 dt (1,1), \\\n    2 with linespoints title 'Tiny'         ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/latency-counter.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"latency-counter.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, 2, 4, 8, 16, 32, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Latency when incrementing an array of 64 counters\"\n\nset logscale x\nset logscale y\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0,0 \"Tx time duration ({/Symbol m}s)\"\nset ytics offset 0.5,0\nset ytics add (\"\" 1e1, \"\" 1e3, \"\" 1e5, \"\" 1e7)\nset format y \"10^{%T}\"\nset yrange [1e0:1e8]\n\nset label at graph 0.2,1.075 font \"Helvetica-bold,18\" \"50% (median)\"\n\nplot \\\n\t'../data/latency-counter-10m-cervino.txt'      using 1:2  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:8  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:14 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/latency-counter-10m-cervino-tiny.txt' using 1:2  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"90%\"\n\nplot \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:3  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:9  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:15 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/latency-counter-10m-cervino-tiny.txt' using 1:3  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"99%\"\n\nplot \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:4  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:10 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:16 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/latency-counter-10m-cervino-tiny.txt' using 1:4  with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0,0 \"Tx time duration ({/Symbol m}s)\"\nset ytics offset 0.5,0\nset format y \"10^{%T}\"\nset yrange [1e0:1e8]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"99.9%\"\n\nplot \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:5  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:11 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:17 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/latency-counter-10m-cervino-tiny.txt' using 1:5  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"99.99%\"\n\nplot \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:6  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:12 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:18 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/latency-counter-10m-cervino-tiny.txt' using 1:6  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"99.999%\"\n\nplot \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:7  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:13 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/latency-counter-10m-cervino.txt'      using 1:19 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/latency-counter-10m-cervino-tiny.txt' using 1:7  with linespoints notitle ls 5 lw 3 dt (1,1)\n\n"
  },
  {
    "path": "graphs/plots/pcaption.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pcaption.eps\"\n\nset size 0.95,0.15\n\nload \"styles.inc\"\n\nunset tics\nunset border\nunset xlabel\nunset ylabel\nunset label\n\nset object 1 rectangle from screen 0.02,0.01 to screen 0.925,0.14 fillcolor rgb \"white\" dashtype (2,3) behind\nset label at screen 0.5,0.11 center \"{/Helvetica-bold Legend for non-volatile memory} (all graphs of {\\247}V.B)\"\n\nset key at screen 0.9,0.07 samplen 1.5 maxrows 2 width 0.25\nplot [][0:1] \\\n    2 with linespoints title 'OF-LF'        ls 1 lw 3 dt 1, \\\n    2 with linespoints title 'OF-WF'        ls 2 lw 3 dt 1, \\\n    2 with linespoints title 'RomL'         ls 3 lw 3 dt (1,1), \\\n    2 with linespoints title 'RomLR'        ls 4 lw 3 dt (1,1), \\\n    2 with linespoints title 'PMDK'         ls 5 lw 3 dt (1,1) \n"
  },
  {
    "path": "graphs/plots/plot-all.sh",
    "content": "#!/bin/sh\n\nfor i in \\\ncaption.gp \\\nsps-integer.gp \\\nsps-object.gp \\\nq-enq-deq.gp \\\nset-ll-1k.gp \\\nset-hash-1k.gp \\\nset-tree-1k.gp \\\nset-tree-10k.gp \\\nlatency-counter.gp \\\npcaption.gp \\\npsps-integer.gp \\\npset-ll-1k.gp \\\npset-tree-1k.gp \\\npset-hash-1k.gp \\\npq-ll-enq-deq.gp \\\n;\ndo\n  echo \"Processing:\" $i\n  gnuplot $i\n  epstopdf `basename $i .gp`.eps\n  rm `basename $i .gp`.eps\ndone\n"
  },
  {
    "path": "graphs/plots/plot.sh",
    "content": "#!/bin/sh\n\nwhile [ $# -gt 0 ]\ndo\n  echo \"Processing:\" $1\n  gnuplot $1\n  epstopdf `basename $1 .gp`.eps\n  rm `basename $1 .gp`.eps\n  open `basename $1 .gp`.pdf\n  shift\ndone\n"
  },
  {
    "path": "graphs/plots/pq-enq-deq.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pq-enq-deq.eps\"\n\nset size 0.95,0.6\n\nX=0.08\nW=0.370\nM=0.100\n\nload \"styles.inc\"\n\nset tmargin 10.5\nset bmargin 3\n\nset multiplot layout 1,2\n\nunset key\n\nset grid ytics\n\nset xtics (\" 1\" 1, 2, 4, 8, 16, \"32 \" 32, 64) nomirror out offset -0.25,0.5\nset label at screen 0.25,0.04 center \"Number of threads\"\n\nset logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 1 offset 0.5,0\nset yrange [0:4]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"Linked list-based queue\"\nset key at graph 0.50,0.99 samplen 1.5\n\nplot \\\n    '../data/pq-ll-enq-deq.txt' using 1:($2/1e6) with linespoints notitle ls 1 lw 2 dt 1,     \\\n    '../data/pq-ll-enq-deq.txt' using 1:($3/1e6) with linespoints notitle ls 2 lw 2 dt 1,     \\\n    '../data/pq-ll-enq-deq.txt' using 1:($4/1e6) with linespoints notitle ls 3 lw 2 dt (1,1), \\\n    '../data/pq-ll-enq-deq.txt' using 1:($5/1e6) with linespoints notitle ls 4 lw 2 dt (1,1), \\\n    '../data/pq-ll-enq-deq.txt' using 1:($6/1e6) with linespoints notitle ls 5 lw 2 dt (1,1), \\\n    '../data/pq-ll-enq-deq.txt' using 1:($7/1e6) with linespoints title \"FHMP\" ls 6 lw 2 dt (1,1)\n\nunset ylabel\nset ytics 10 offset 0.5,0\nset yrange [0:40]\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nunset arrow\nset xtics (2, 4, 8, 16, 32) nomirror out offset -0.25,0.5\nset ylabel offset 1.5,0 \"Transactions ({/Symbol \\264}10^6/s)\"\nset label at screen 0.75,0.04 center \"Number of processes\"\n\nset ytics (\"\" 0.5,1,\"\" 1.5,2) offset 0.5,0\nset xrange [2:32]\nset yrange [0:2]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"Swapping item between queues\"\nset key at graph 0.99,0.99 samplen 1.5\n\n# we divide by 1e8 because the data is in total number of tx and we want tx/second\nplot \\\n    '../data/stress-multi-process-q-nokills.txt' using 1:($2/1e8) with linespoints title \"No kill\"            ls 1 lw 4 dt (1,1), \\\n    '../data/stress-multi-process-q-kills.txt'   using 1:($2/1e8) with linespoints title \"1 kill every 100ms\" ls 2 lw 2 dt 1\n"
  },
  {
    "path": "graphs/plots/pq-ll-enq-deq.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pq-ll-enq-deq.eps\"\n\nset size 0.95,0.6\n\nS=0.2125\nX=0.1\nW=0.375\nM=0.075\n\nload \"styles.inc\"\n\nset tmargin 10.5\nset bmargin 3\n\n# We can fit a second graph if need be (remove S \"hack\")\nset multiplot layout 1,2\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, 2, 4, 8, 16, 32, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\n\nset logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen S+X\nset rmargin at screen S+X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 1 offset 0.5,0\nset yrange [0:4]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"Linked list-based queue\"\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n    '../data/pq-ll-enq-deq.txt' using 1:($2/1e6) with linespoints notitle ls 1 lw 2 dt 1,     \\\n    '../data/pq-ll-enq-deq.txt' using 1:($3/1e6) with linespoints notitle ls 2 lw 2 dt 1,     \\\n    '../data/pq-ll-enq-deq.txt' using 1:($4/1e6) with linespoints notitle ls 3 lw 2 dt (1,1), \\\n    '../data/pq-ll-enq-deq.txt' using 1:($5/1e6) with linespoints notitle ls 4 lw 2 dt (1,1), \\\n    '../data/pq-ll-enq-deq.txt' using 1:($6/1e6) with linespoints notitle ls 5 lw 2 dt (1,1), \\\n    '../data/pq-ll-enq-deq.txt' using 1:($7/1e6) with linespoints title \"FHMP\" ls 6 lw 2 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/pset-hash-1k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pset-hash-1k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Persistent resizable hash table sets with 10^{3} keys\"\n\n#set logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset -0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 1 offset 0.5,0\nset format y \"%g\"\nset yrange [0:3]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\n\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n\t'../data/pset-hash-1k.txt'     using 1:($2/1e6)  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($3/1e6)  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($4/1e6)  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($5/1e6)  with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($6/1e6)  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nplot \\\n    '../data/pset-hash-1k.txt'     using 1:($7/1e6)  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($8/1e6)  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($9/1e6)  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($10/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($11/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset ytics 2 offset 0.5,0\nset yrange [0:14]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,14 front boxed left offset -0.5,0 \"14\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nplot \\\n    '../data/pset-hash-1k.txt'     using 1:($12/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($13/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($14/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($15/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($16/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 25 offset 0.5,0\nset format y \"%g\"\nset yrange [0:125]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/pset-hash-1k.txt'     using 1:($17/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($18/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($20/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($21/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset yrange [0:200]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,200 front boxed left offset -0.5,0 \"200\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nplot \\\n    '../data/pset-hash-1k.txt'     using 1:($22/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($23/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($24/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($25/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($26/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset ytics 100 offset 0.5,0\nset yrange [0:850]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,850 front boxed left offset -0.5,0 \"850\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nplot \\\n    '../data/pset-hash-1k.txt'     using 1:($27/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($28/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-hash-1k.txt'     using 1:($29/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($30/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-hash-1k.txt'     using 1:($31/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/pset-ll-1k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pset-ll-1k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Persistent linked list sets with 10^{3} keys\"\n\n#set logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 0.2 offset 0.5,0\nset format y \"%g\"\nset yrange [0:0.7]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\n\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n\t'../data/pset-ll-1k.txt'     using 1:($2/1e6)  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($3/1e6)  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($4/1e6)  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($5/1e6)  with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($6/1e6)  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset yrange [0:1]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,1 front boxed left offset -0.5,0 \"1\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nplot \\\n    '../data/pset-ll-1k.txt'     using 1:($7/1e6)  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($8/1e6)  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($9/1e6)  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($10/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($11/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset ytics 0.5 offset 0.5,0\nset yrange [0:3]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,3 front boxed left offset -0.5,0 \"3\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nplot \\\n    '../data/pset-ll-1k.txt'     using 1:($12/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($13/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($14/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($15/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($16/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset -0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 1 offset 0.5,0\nset format y \"%g\"\nset yrange [0:4]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/pset-ll-1k.txt'     using 1:($17/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($18/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($20/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($21/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset yrange [0:8]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,8 front boxed left offset -0.5,0 \"8\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nplot \\\n    '../data/pset-ll-1k.txt'     using 1:($22/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($23/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($24/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($25/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($26/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset ytics 10 offset 0.5,0\nset yrange [0:60]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,60 front boxed left offset -0.5,0 \"60\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nplot \\\n    '../data/pset-ll-1k.txt'     using 1:($27/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($28/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-ll-1k.txt'     using 1:($29/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($30/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-ll-1k.txt'     using 1:($31/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/pset-tree-1k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pset-tree-1k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Persistent red-black tree sets with 10^{3} keys\"\n\n#set logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\n#set logscale y\n#set format y \"10^{%T}\"\n#set yrange [1e4:5e6]\nset format y \"%g\"\nset yrange [0:0.6]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\n\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n\t'../data/pset-tree-1k.txt'     using 1:($2/1e6)  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($3/1e6)  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($4/1e6)  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($5/1e6)  with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($6/1e6)  with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nplot \\\n    '../data/pset-tree-1k.txt'     using 1:($7/1e6)  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($8/1e6)  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($9/1e6)  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($10/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($11/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset yrange [0:3]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,3 front boxed left offset -0.5,0 \"3\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nplot \\\n    '../data/pset-tree-1k.txt'     using 1:($12/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($13/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($14/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($15/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($16/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\n#set logscale y\n#set format y \"10^{%T}\"\n#set yrange [1e6:4e8]\nset format y \"%g\"\nset yrange [0:30]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/pset-tree-1k.txt'     using 1:($17/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($18/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($20/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($21/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset yrange [0:150]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,150 front boxed left offset -0.5,0 \"150\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nplot \\\n    '../data/pset-tree-1k.txt'     using 1:($22/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($23/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($24/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($25/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($26/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset yrange [0:350]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,350 front boxed left offset -0.5,0 \"350\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nplot \\\n    '../data/pset-tree-1k.txt'     using 1:($27/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($28/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1k.txt'     using 1:($29/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($30/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1k.txt'     using 1:($31/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/pset-tree-1m.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"pset-tree-1m.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Persistent red-black tree sets with 10^{6} keys\"\n\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 0.1 offset 0.5,0\nset format y \"%g\"\nset yrange [0:0.3]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\n\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n    '../data/pset-tree-1m-oflf.txt'   using 1:($2/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-ofwf.txt'   using 1:($2/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-romlog.txt' using 1:($2/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-romlr.txt'  using 1:($2/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-pmdk.txt'   using 1:($2/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nplot \\\n    '../data/pset-tree-1m-oflf.txt'   using 1:($3/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-ofwf.txt'   using 1:($3/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-romlog.txt' using 1:($3/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-romlr.txt'  using 1:($3/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-pmdk.txt'   using 1:($3/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset ytics 0.2 offset 0.5,0\nset yrange [0:1.4]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,1.4 front boxed left offset -0.5,0 \"1.4\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nplot \\\n    '../data/pset-tree-1m-oflf.txt'   using 1:($4/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-ofwf.txt'   using 1:($4/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-romlog.txt' using 1:($4/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-romlr.txt'  using 1:($4/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-pmdk.txt'   using 1:($4/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 5 offset 0.5,0\nset format y \"%g\"\nset yrange [0:12]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/pset-tree-1m-oflf.txt'   using 1:($5/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-ofwf.txt'   using 1:($5/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-romlog.txt' using 1:($5/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-romlr.txt'  using 1:($5/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-pmdk.txt'   using 1:($5/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset ytics 5 offset 0.5,0\nset yrange [0:25]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,25 front boxed left offset -0.5,0 \"25\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nplot \\\n    '../data/pset-tree-1m-oflf.txt'   using 1:($6/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-ofwf.txt'   using 1:($6/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-romlog.txt' using 1:($6/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-romlr.txt'  using 1:($6/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-pmdk.txt'   using 1:($6/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset ytics 5 offset 0.5,0\nset yrange [0:38]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,38 front boxed left offset -0.5,0 \"38\"\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nplot \\\n    '../data/pset-tree-1m-oflf.txt'   using 1:($7/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-ofwf.txt'   using 1:($7/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/pset-tree-1m-romlog.txt' using 1:($7/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-romlr.txt'  using 1:($7/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/pset-tree-1m-pmdk.txt'   using 1:($7/1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n\nunset tics\nunset border\nunset xlabel\nunset ylabel\nunset label\n\n#set key at screen 0.92,0.20 samplen 2.0 bottom\n#plot [][0:1] \\\n#    2 with linespoints title 'OF-LF'   ls 1, \\\n#    2 with linespoints title 'OF-WF'   ls 2, \\\n#    2 with linespoints title 'RomLog'  ls 3, \\\n#    2 with linespoints title 'RomLR'   ls 4, \\\n#    2 with linespoints title 'PMDK'    ls 5       \n    "
  },
  {
    "path": "graphs/plots/psps-integer.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"psps-integer.eps\"\n\nset size 0.95,1.12\n\nS1=0.005\nS2=0.3\nX=0.1+S1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (1, 2, 4, 8, \"\" 16, 32, \"\" 64, 128, \"\" 256) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of swaps per transaction\"\nset label at screen 0.5,1.09 center \"Persistent SPS integer swap\"\n\nset logscale x\nset xrange [1:256]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5-S2,0 \"Swaps ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\nset yrange [0:14]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1 thread\"\n\nplot \\\n\t'../data/psps-integer.txt'       using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,    \\\n    '../data/psps-integer.txt'       using 1:($10/1e6) with linespoints notitle ls 2 lw 3 dt 1,    \\\n    '../data/psps-integer.txt'       using 1:($18/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/psps-integer.txt'       using 1:($26/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/psps-integer-atlas.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"2 threads\"\n\nplot \\\n    '../data/psps-integer.txt'       using 1:($3 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($11/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/psps-integer.txt'       using 1:($27/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/psps-integer-atlas.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"4 threads\"\n\nplot \\\n    '../data/psps-integer.txt'       using 1:($4 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($12/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($20/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/psps-integer.txt'       using 1:($28/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/psps-integer-atlas.txt' using 1:($4 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5-S2,0 \"Swaps ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\nset ytics format \"%g\"\nset yrange [0:11]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"16 threads\"\n\nplot \\\n    '../data/psps-integer.txt'       using 1:($6 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($14/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($22/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/psps-integer.txt'       using 1:($30/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/psps-integer-atlas.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"32 threads\"\n\nplot \\\n    '../data/psps-integer.txt'       using 1:($7 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($15/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($23/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/psps-integer.txt'       using 1:($31/1e6) with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/psps-integer-atlas.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"64 threads\"\n\nplot \\\n    '../data/psps-integer.txt'       using 1:($9 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($17/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/psps-integer.txt'       using 1:($25/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/psps-integer.txt'       using 1:($33/1e6) with linespoints notitle ls 4 lw 3 dt (1,1)#, \\\n#    '../data/psps-integer-atlas.txt' using 1:($9 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/q-array-enq-deq.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"q-array-enq-deq.eps\"\n\n#set size 0.95,0.6\n#X=0.09\n#W=0.26\n#M=0.02\n\nload \"styles.inc\"\n\n#set tmargin 11.0\n#set bmargin 2.5\n\nset grid ytics\n\nset ylabel offset 0.7,0 \"Op/s\"\nset format y \"10^{%T}\"\nset xtics (\"\" 1, 2, 4, 8, 16, 32, 64) nomirror out offset -0.25,0.5\n#set ytics 100 offset 0.5,0\n#set mytics 10\nset label at screen 0.5,0.03 center \"Number of threads\"\n\nset logscale x\n#set yrange [1:1e7]\n#set lmargin at screen X\n#set rmargin at screen X+W\n\nset label at graph 1.6,1.1 center \"Queues (array based)\"\n\nplot \\\n\t'../data/q-array-enq-deq.txt'      using 1:2  with linespoints title 'OF-LF' ls 1 lw 2 dt 1,     \\\n    '../data/q-array-enq-deq.txt'      using 1:3  with linespoints title 'OF-WF' ls 2 lw 2 dt 1,     \\\n    '../data/q-array-enq-deq.txt'      using 1:4  with linespoints title 'ESTM'  ls 3 lw 2 dt (1,1), \\\n    '../data/q-array-enq-deq-tiny.txt' using 1:2  with linespoints title 'Tiny'  ls 5 lw 2 dt (1,1), \\\n    '../data/q-array-enq-deq.txt'      using 1:5  with linespoints title 'FAA'   ls 6 lw 2 dt (1,1), \\\n    '../data/q-array-enq-deq.txt'      using 1:6  with linespoints title 'LCRQ'  ls 7 lw 2 dt (1,1), \\\n\n\n"
  },
  {
    "path": "graphs/plots/q-enq-deq.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"q-enq-deq.eps\"\n\nset size 0.95,0.6\n\nX=0.1\nW=0.375\nM=0.075\n\nload \"styles.inc\"\n\nset tmargin 10.5\nset bmargin 3\n\nset multiplot layout 1,2\n\nunset key\n\nset grid ytics\n\nset xtics (\" 1\" 1, 2, 4, 8, 16, \"32 \" 32, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\n\nset logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 4 offset 0.5,0\nset yrange [0:15]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"Linked list-based queue\"\nset key at graph 0.99,0.92 samplen 1.5\n\n# set label at graph 0.12,0.77 center font \"Helvetica,18\" \"MS\"\n# set arrow from graph 0.12,0.82 to graph 0.12,0.90 size screen 0.015,25 lw 3\n# set label at graph 0.55,0.72 left font \"Helvetica,18\" \"SimQ\"\n# set arrow from graph 0.53,0.72 to graph 0.47,0.72 size screen 0.015,25 lw 3\n# set label at graph 0.88,0.60 center font \"Helvetica,18\" \"TurnQ\"\n# set arrow from graph 0.88,0.55 to graph 0.88,0.47 size screen 0.015,25 lw 3\n\nplot \\\n    '../data/q-ll-enq-deq.txt'      using 1:($2/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/q-ll-enq-deq.txt'      using 1:($3/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/q-ll-enq-deq.txt'      using 1:($4/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/q-ll-enq-deq-tiny.txt' using 1:($2/1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/q-ll-enq-deq.txt'      using 1:($5/1e6) with linespoints title \"MS\" ls 6 lw 3 dt (1,1), \\\n    '../data/q-ll-enq-deq.txt'      using 1:($6/1e6) with linespoints title \"SimQ\" ls 7 lw 3 dt (1,1), \\\n    '../data/q-ll-enq-deq.txt'      using 1:($7/1e6) with linespoints title \"TurnQ\" ls 8 lw 3 dt (1,1)\n\nunset ylabel\nset ytics 10 offset 0.5,0\nset yrange [0:40]\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nunset arrow\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"Array-based queue\"\nset key at graph 0.99,0.35 samplen 1.5\n\n# set label at graph 0.55,0.61 left font \"Helvetica,18\" \"FAA\"\n# set arrow from graph 0.53,0.61 to graph 0.47,0.61 size screen 0.015,25 lw 3\n# set label at graph 0.37,0.76 right font \"Helvetica,18\" \"LCRQ\"\n# set arrow from graph 0.39,0.76 to graph 0.45,0.76 size screen 0.015,25 lw 3\n\nplot \\\n    '../data/q-array-enq-deq.txt'     using 1:($2/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/q-array-enq-deq.txt'     using 1:($3/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/q-array-enq-deq.txt'     using 1:($4/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/q-array-enq-deq.txt'     using 1:($5/1e6) with linespoints title \"FAA\" ls 6 lw 3 dt (1,1), \\\n    '../data/q-array-enq-deq.txt'     using 1:($6/1e6) with linespoints title \"LCRQ\" ls 7 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/q-ll-enq-deq.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"q-ll-enq-deq.eps\"\n\n#set size 0.95,0.6\n#X=0.09\n#W=0.26\n#M=0.02\n\nload \"styles.inc\"\n\n#set tmargin 11.0\n#set bmargin 2.5\n\n#set grid ytics\n\nset ylabel offset 0.7,0 \"Op/s\"\nset format y \"10^{%T}\"\nset xtics (\"\" 1, 2, 4, 8, 16, 32) nomirror out offset -0.25,0.5\n#set ytics 100 offset 0.5,0\n#set mytics 10\nset label at screen 0.5,0.03 center \"Number of threads\"\n\nset logscale x\n#set yrange [1:1e7]\n#set lmargin at screen X\n#set rmargin at screen X+W\n\nset label at graph 1.6,1.1 center \"Queues (linked-list based)\"\n#unset key\n\nplot \\\n    '../data/q-ll-enq-deq.txt'      using 1:2  with linespoints title 'OF-LF' ls 1 lw 2 dt 1,     \\\n    '../data/q-ll-enq-deq.txt'      using 1:3  with linespoints title 'OF-WF' ls 2 lw 2 dt 1,     \\\n    '../data/q-ll-enq-deq.txt'      using 1:4  with linespoints title 'ESTM'  ls 3 lw 2 dt (1,1), \\\n    '../data/q-ll-enq-deq-tiny.txt' using 1:2  with linespoints title 'Tiny'  ls 5 lw 2 dt (1,1), \\\n    '../data/q-ll-enq-deq.txt'      using 1:5  with linespoints title 'MS'    ls 6 lw 2 dt (1,1), \\\n    '../data/q-ll-enq-deq.txt'      using 1:6  with linespoints title 'SimQ'  ls 7 lw 2 dt (1,1), \\\n    '../data/q-ll-enq-deq.txt'      using 1:7  with linespoints title 'TurnQ' ls 8 lw 2 dt (1,1)\n\n\n"
  },
  {
    "path": "graphs/plots/set-hash-1k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"set-hash-1k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, 2, 4, 8, 16, 32, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Resizable hash table sets with 10^{3} keys\"\n\nset logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 2 offset 0.5,0\nset yrange [0:14]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\n\nplot \\\n    '../data/set-hash-1k.txt'      using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($3 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($4 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-hash-1k-tiny.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nset ytics 2 offset 0.5,0\nset yrange [0:14]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,14 front boxed left offset -0.5,0 \"14\"\n\nplot \\\n    '../data/set-hash-1k.txt'      using 1:($5 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($6 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($7 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-hash-1k-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nset ytics 2 offset 0.5,0\nset yrange [0:20]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,20 front boxed left offset -0.5,0 \"20\"\n\nplot \\\n    '../data/set-hash-1k.txt'      using 1:($8 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($9 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($10/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-hash-1k-tiny.txt' using 1:($4 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 50 offset 0.5,0\nset ytics format \"%g\"\nset yrange [0:100]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/set-hash-1k.txt'      using 1:($11/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($12/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($13/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-hash-1k-tiny.txt' using 1:($5 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nset ytics 50 offset 0.5,0\nset yrange [0:220]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,220 front boxed left offset -0.5,0 \"220\"\n\nplot \\\n    '../data/set-hash-1k.txt'      using 1:($14/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($15/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($16/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-hash-1k-tiny.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nset ytics 50 offset 0.5,0\nset yrange [0:550]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,550 front boxed left offset -0.5,0 \"550\"\n\nplot \\\n    '../data/set-hash-1k.txt'      using 1:($17/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($18/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-hash-1k.txt'      using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-hash-1k-tiny.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/set-ll-10k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"set-ll-10k.eps\"\n\nset size 0.95,1.08\n\nX=0.09\nW=0.26\nM=0.02\n\nload \"styles.inc\"\n\n#set tmargin 11.0\n#set bmargin 2.5\n\nset grid ytics\n\nset ylabel offset 0.7,0 \"Op/s\"\nset format y \"10^{%T}\"\nset xtics (\"\" 1, 2, 4, 8, 16, 32) nomirror out offset -0.25,0.5\nset ytics 100 offset 0.5,0\nset mytics 10\nset label at screen 0.5,0.03 center \"Number of threads\"\nset label at screen 0.5,1.05 center \"Linked List Sets with 10^{4} keys\"\n\nset multiplot layout 2,3\n\nset logscale x\nset xrange [1:32]\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nunset key\nset label at graph 0.5,1.1 center \"100%\"\n\nplot \\\n\t'../data/set-ll-10k.txt'      using 1:2  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:3  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:4  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tiny.txt' using 1:2  with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:5  with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:6  with linespoints notitle ls 7 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.1 center \"50%\"\n\nplot \\\n    '../data/set-ll-10k.txt'      using 1:7  with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:8  with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:9  with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tiny.txt' using 1:3  with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:10 with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:11 with linespoints notitle ls 7 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.1 center \"10%\"\n\nplot \\\n    '../data/set-ll-10k.txt'      using 1:12 with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:13 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:14 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tl2.txt'  using 1:4  with linespoints notitle ls 4 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tiny.txt' using 1:4  with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:15 with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:16 with linespoints notitle ls 7 lw 3 dt (1,1)\n\n\n    \n    \n# Second row\n\n\nset logscale x\n#set yrange [1:1e7]\nset lmargin at screen X\nset rmargin at screen X+W\n\nunset label\nset label at graph 0.5,1.1 center \"1%\"\n\nplot \\\n    '../data/set-ll-10k.txt'      using 1:17 with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:18 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:19 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tiny.txt' using 1:5  with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:20 with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:21 with linespoints notitle ls 7 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.1 center \"0.1%\"\n\nplot \\\n    '../data/set-ll-10k.txt'      using 1:22 with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:23 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:24 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tiny.txt' using 1:6  with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:25 with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:26 with linespoints notitle ls 7 lw 3 dt (1,1)\n\n    \nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.1 center \"0%\"\n\nplot \\\n    '../data/set-ll-10k.txt'      using 1:27 with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:28 with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-10k.txt'      using 1:29 with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-10k-tiny.txt' using 1:7  with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:30 with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-10k.txt'      using 1:31 with linespoints notitle ls 7 lw 3 dt (1,1)\n\n\n\nunset tics\nunset border\nunset xlabel\nunset ylabel\nunset label\n\nset key at screen 0.62,0.22 samplen 2.0 bottom\nplot [][0:1] \\\n    2 with linespoints title 'OF-LF'        ls 1, \\\n    2 with linespoints title 'OF-WF'        ls 2, \\\n    2 with linespoints title 'ESTM'         ls 3, \\\n    2 with linespoints title 'Tiny'         ls 5\n\nset key at screen 0.88,0.28 samplen 2.0 bottom\nplot [][0:1] \\\n    2 with linespoints title 'HarrisHP'     ls 6, \\\n    2 with linespoints title 'HarrisHE'     ls 7\n\n\nunset multiplot\n"
  },
  {
    "path": "graphs/plots/set-ll-1k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"set-ll-1k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Linked list sets with 10^{3} keys\"\n\n#set logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 1 offset 0.5,0\nset yrange [0:3]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\n\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n    '../data/set-ll-1k.txt'      using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($3 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($4 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-1k-tiny.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($5 /1e6) with linespoints title \"HarrisHP\" ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($6 /1e6) with linespoints notitle ls 7 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nset ytics 1 offset 0.5,0\nset yrange [0:4]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,4 front boxed left offset -0.5,0 \"4\"\n\nplot \\\n    '../data/set-ll-1k.txt'      using 1:($7 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($8 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($9 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-1k-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($10/1e6) with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($11/1e6) with linespoints title \"HarrisHE\" ls 7 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nset ytics 1 offset 0.5,0\nset yrange [0:5]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,5 front boxed left offset -0.5,0 \"5\"\n\nplot \\\n    '../data/set-ll-1k.txt'      using 1:($12/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($13/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($14/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-1k-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($15/1e6) with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($16/1e6) with linespoints notitle ls 7 lw 3 dt (1,1)\n\n#\n# Second row\n#\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 2 offset 0.5,0\nset ytics 2 format \"%g\"\nset yrange [0:7]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/set-ll-1k.txt'      using 1:($17/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($18/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-1k-tiny.txt' using 1:($5 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($20/1e6) with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($21/1e6) with linespoints notitle ls 7 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nset ytics 2 offset 0.5,0\nset yrange [0:9]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,9 front boxed left offset -0.5,0 \"9\"\n\nplot \\\n    '../data/set-ll-1k.txt'      using 1:($22/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($23/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($24/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-1k-tiny.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($25/1e6) with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($26/1e6) with linespoints notitle ls 7 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nset ytics 2 offset 0.5,0\nset yrange [0:17]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,17 front boxed left offset -0.5,0 \"17\"\n\nplot \\\n    '../data/set-ll-1k.txt'      using 1:($27/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($28/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-ll-1k.txt'      using 1:($29/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-ll-1k-tiny.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($30/1e6) with linespoints notitle ls 6 lw 3 dt (1,1), \\\n    '../data/set-ll-1k.txt'      using 1:($31/1e6) with linespoints notitle ls 7 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/set-tree-10k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"set-tree-10k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Red-black tree sets with 10^{4} keys\"\n\n#set logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 2.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 0.1 offset 0.5,0\nset yrange [0:0.4]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n    '../data/set-tree-10k.txt'      using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($3 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($4 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-10k.txt'      using 1:($5 /1e6) with linespoints title \"NataHE\" ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-10k-tiny.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nset ytics 0.1 offset 0.5,0\nset yrange [0:1.0]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,1.0 front boxed left offset -0.5,0 \"1.0\"\n\nplot \\\n    '../data/set-tree-10k.txt'      using 1:($6 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($7 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($8 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-10k.txt'      using 1:($9 /1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-10k-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nset ytics 0.5 offset 0.5,0\nset yrange [0:2.0]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,2.0 front boxed left offset -0.5,0 \"2.0\"\n\nplot \\\n    '../data/set-tree-10k.txt'      using 1:($10/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($11/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($12/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-10k.txt'      using 1:($13/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-10k-tiny.txt' using 1:($4 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 5 offset 0.5,0\nset ytics format \"%g\"\nset yrange [0:16]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/set-tree-10k.txt'      using 1:($14/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($15/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($16/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-10k.txt'      using 1:($17/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-10k-tiny.txt' using 1:($5 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nset ytics 10 offset 0.5,0\nset yrange [0:80]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,80 front boxed left offset -0.5,0 \"80\"\n\nplot \\\n    '../data/set-tree-10k.txt'      using 1:($18/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($19/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($20/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-10k.txt'      using 1:($21/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-10k-tiny.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nset ytics 20 offset 0.5,0\nset yrange [0:140]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,140 front boxed left offset -0.5,0 \"140\"\n\nplot \\\n    '../data/set-tree-10k.txt'      using 1:($22/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($23/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-10k.txt'      using 1:($24/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-10k.txt'      using 1:($25/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-10k-tiny.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/set-tree-1k.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"set-tree-1k.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (\"\" 1, \"\" 2, 4, \"\" 8, 16, 32, 48, 64) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of threads\"\nset label at screen 0.5,1.09 center \"Red-black tree sets with 10^{3} keys\"\n\n#set logscale x\nset xrange [1:64]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 2.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 0.5 offset 0.5,0\nset yrange [0:2]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"100%\"\nset key at graph 0.99,0.99 samplen 1.5\n\nplot \\\n    '../data/set-tree-1k.txt'      using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($3 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($4 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-1k.txt'      using 1:($5 /1e6) with linespoints title \"NatarajanHE\" ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-1k-tiny.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"50%\"\n\nset ytics 0.5 offset 0.5,0\nset yrange [0:2.6]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,2.6 front boxed left offset -0.5,0 \"2.6\"\n\nplot \\\n    '../data/set-tree-1k.txt'      using 1:($6 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($7 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($8 /1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-1k.txt'      using 1:($9 /1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-1k-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"10%\"\n\nset ytics 0.5 offset 0.5,0\nset yrange [0:8]\n\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,8 front boxed left offset -0.5,0 \"8\"\n\nplot \\\n    '../data/set-tree-1k.txt'      using 1:($10/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($11/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($12/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-1k.txt'      using 1:($13/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-1k-tiny.txt' using 1:($4 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Operations ({/Symbol \\264}10^6/s)\"\nset ytics 10 offset 0.5,0\nset ytics format \"%g\"\nset yrange [0:16]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1%\"\n\nplot \\\n    '../data/set-tree-1k.txt'      using 1:($14/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($15/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($16/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-1k.txt'      using 1:($17/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-1k-tiny.txt' using 1:($5 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0.1%\"\n\nset ytics 10 offset 0.5,0\nset yrange [0:100]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,100 front boxed left offset -0.5,0 \"100\"\n\nplot \\\n    '../data/set-tree-1k.txt'      using 1:($18/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($19/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($20/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-1k.txt'      using 1:($21/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-1k-tiny.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"0%\"\n\nset ytics 10 offset 0.5,0\nset yrange [0:210]\nset style textbox opaque noborder fillcolor rgb \"white\"\nset label at first 1,210 front boxed left offset -0.5,0 \"210\"\n\nplot \\\n    '../data/set-tree-1k.txt'      using 1:($22/1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($23/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/set-tree-1k.txt'      using 1:($24/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/set-tree-1k.txt'      using 1:($25/1e6) with linespoints notitle ls 9 lw 3 dt (1,1), \\\n    '../data/set-tree-1k-tiny.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/sps-integer.gp",
    "content": "# this is for an array with 1000 entries\nset term postscript color eps enhanced 22\nset output \"sps-integer.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (1, 2, 4, 8, \"\" 16, 32, \"\" 64, 128, \"\" 256) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of swaps per transaction\"\nset label at screen 0.5,1.09 center \"SPS integer swap\"\n\nset logscale x\nset xrange [1:256]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Swaps ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\nset yrange [0:32]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1 thread\"\n\nplot \\\n\t'../data/sps-integer.txt'      using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,    \\\n    '../data/sps-integer.txt'      using 1:($10/1e6) with linespoints notitle ls 2 lw 3 dt 1,    \\\n    '../data/sps-integer.txt'      using 1:($18/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-integer-tiny.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"2 threads\"\n\nplot \\\n    '../data/sps-integer.txt'      using 1:($3 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($11/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-integer-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"4 threads\"\n\nplot \\\n    '../data/sps-integer.txt'      using 1:($4 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($12/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($20/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-integer-tiny.txt' using 1:($4 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Swaps ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\nset ytics format \"%g\"\nset yrange [0:13]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"16 threads\"\n\nplot \\\n    '../data/sps-integer.txt'      using 1:($6 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($14/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($22/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-integer-tiny.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"32 threads\"\n\nplot \\\n    '../data/sps-integer.txt'      using 1:($7 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($15/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($23/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-integer-tiny.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"64 threads\"\n\nplot \\\n    '../data/sps-integer.txt'      using 1:($9 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($17/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-integer.txt'      using 1:($25/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-integer-tiny.txt' using 1:($9 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/sps-object.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"sps-object.eps\"\n\nset size 0.95,1.12\n\nX=0.1\nW=0.26\nM=0.025\n\nload \"styles.inc\"\n\nset tmargin 0\nset bmargin 3\n\nset multiplot layout 2,3\n\nunset key\n\nset grid ytics\n\nset xtics (1, 2, 4, 8, \"\" 16, 32, \"\" 64, 128, \"\" 256) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of swaps per transaction\"\nset label at screen 0.5,1.09 center \"SPS object swap\"\n\nset logscale x\nset xrange [1:256]\n\n# First row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 1.5,0 \"Swaps ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\nset yrange [0:12]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"1 thread\"\n\nplot \\\n    '../data/sps-object.txt'      using 1:($2 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($8 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($14/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-object-tiny.txt' using 1:($2 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"2 threads\"\n\nplot \\\n    '../data/sps-object.txt'      using 1:($3 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($9 /1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($15/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-object-tiny.txt' using 1:($3 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"4 threads\"\n\nplot \\\n    '../data/sps-object.txt'      using 1:($4 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($10/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($16/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-object-tiny.txt' using 1:($4 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n \n# Second row\n\nset lmargin at screen X\nset rmargin at screen X+W\n\nset ylabel offset 0.5,0 \"Swaps ({/Symbol \\264}10^6/s)\"\nset ytics offset 0.5,0\nset ytics format \"%g\"\nset yrange [0:12]\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"8 threads\"\n\nplot \\\n    '../data/sps-object.txt'      using 1:($5 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($11/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($17/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-object-tiny.txt' using 1:($5 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nunset ylabel\nset ytics format \"\"\n\nset lmargin at screen X+(W+M)\nset rmargin at screen X+(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"16 threads\"\n\nplot \\\n    '../data/sps-object.txt'      using 1:($6 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($12/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($18/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-object-tiny.txt' using 1:($6 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n\nset lmargin at screen X+2*(W+M)\nset rmargin at screen X+2*(W+M)+W\n\nunset label\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"32 threads\"\n\nplot \\\n    '../data/sps-object.txt'      using 1:($7 /1e6) with linespoints notitle ls 1 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($13/1e6) with linespoints notitle ls 2 lw 3 dt 1,     \\\n    '../data/sps-object.txt'      using 1:($19/1e6) with linespoints notitle ls 3 lw 3 dt (1,1), \\\n    '../data/sps-object-tiny.txt' using 1:($7 /1e6) with linespoints notitle ls 5 lw 3 dt (1,1)\n"
  },
  {
    "path": "graphs/plots/stress-multi-process-q.gp",
    "content": "set term postscript color eps enhanced 22\nset output \"stress-multi-process-q.eps\"\n\nset size 0.95,0.6\n\nS=0.2125\nX=0.1\nW=0.375\nM=0.075\n\nload \"styles.inc\"\n\nset tmargin 10.5\nset bmargin 3\n\n# We can fit a second graph if need be (remove S \"hack\")\nset multiplot layout 1,2\n\nunset key\n\nset grid ytics\n\nset xtics (2, 4, 8, 16, 32) nomirror out offset -0.25,0.5\nset label at screen 0.5,0.04 center \"Number of processes\"\n\nset logscale x\nset xrange [2:32]\n\n# First row\n\nset lmargin at screen S+X\nset rmargin at screen S+X+W\n\nset ylabel offset 1.5,0 \"Transactions ({/Symbol \\264}10^6/s)\"\nset ytics 1 offset 0.5,0\nset yrange [0:2]\n\nset label at graph 0.5,1.075 center font \"Helvetica-bold,18\" \"Swapping item from q to q\"\nset key at graph 0.99,0.99 samplen 1.5\n\n# set label at graph 0.14,0.89 center font \"Helvetica,18\" \"FHMP\"\n# set arrow from graph 0.14,0.84 to graph 0.14,0.76 size screen 0.015,25 lw 3\n\n# we divide by 1e8 because the data is in total number of tx and we want tx/second\nplot \\\n    '../data/stress-multi-process-q-nokills.txt' using 1:($2/1e8) with linespoints title \"No kill\"            ls 1 lw 2 dt (1,1), \\\n    '../data/stress-multi-process-q-kills.txt'   using 1:($2/1e8) with linespoints title \"1 kill every 100ms\" ls 2 lw 2 dt 1\n"
  },
  {
    "path": "graphs/plots/styles.inc",
    "content": "set pointsize 2\n\n# BLUE   -> #0066CC (light: #0099FF - dark: #003366)\n# RED    -> #993333\n# GREEN  -> #669900 (light: #00CC66)\n# PURPLE -> #663399\n# ORANGE -> #CC6633 (light: #FFCC00)\n\n# OF-LF\nset style line 1 lt 1 lc rgb \"#0099FF\" lw 2 pt 9  ps 1.75 dt 1\n# OF-WF\nset style line 2 lt 1 lc rgb \"#0033CC\" lw 2 pt 11 ps 1.75 dt 1\n# ESTM\nset style line 3 lt 1 lc rgb \"#00CC66\" lw 2 pt 13 ps 1.5 dt 1\n# TL2\nset style line 4 lt 1 lc rgb \"#993333\" lw 2 pt 5  ps 1.5 dt 1\n# Tiny STM\nset style line 5 lt 1 lc rgb \"#333333\" lw 2 pt 7  ps 1.5 dt 1\n# Custom 1\nset style line 6 lt 1 lc rgb \"#CC6633\" lw 2 pt 2  ps 1.5 dt 1\n# Custom 2\nset style line 7 lt 1 lc rgb \"#663399\" lw 2 pt 3  ps 1.5 dt 1\n# Custom 3\nset style line 8 lt 1 lc rgb \"#000000\" lw 2 pt 1  ps 1.5 dt 1\n# Natarajan\nset style line 9 lt 1 lc rgb \"#CC6633\" lw 2 pt 4  ps 1.25 dt 1\n\n\npat1 = 'fs solid 0.5 lc rgb \"#FFCC00\"'\npat2 = 'fs solid 0.5 lc rgb \"#00CC66\"'\npat3 = 'fs solid 0.7 lc rgb \"#0066CC\"'\npat4 = 'fs solid 1.0 lc rgb \"#993333\"'\npat5 = 'fs solid 1.0 lc rgb \"#333333\"'\n#pat5 = 'fs pattern 2 lc rgb \"#0066CC\"'\n#pat6 = 'fs pattern 6 lc rgb \"#0066CC\"'\n#pat5 = 'fs pattern 2 lc rgb \"#000000\"'\n#pat6 = 'fs pattern 6 lc rgb \"#000000\"'\n\n#pat1 = 'fs solid 0.0  lc rgb \"#000000\"'\n#pat2 = 'fs solid 0.3  lc rgb \"#000000\"'\n#pat3 = 'fs solid 0.65 lc rgb \"#000000\"'\n#pat4 = 'fs solid 1.0  lc rgb \"#000000\"'\n#pat5 = 'fs pattern 2  lc rgb \"#000000\"'\n#pat6 = 'fs pattern 6  lc rgb \"#000000\"'\n#pat7 = 'fs solid 0.5  lc rgb \"#000000\"'\n"
  },
  {
    "path": "graphs/pq-ll-enq-deq.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"PBenchmarkQueues.hpp\"\r\n#include \"pdatastructures/pqueues/POFLFLinkedListQueue.hpp\"\r\n#include \"pdatastructures/pqueues/POFWFLinkedListQueue.hpp\"\r\n#include \"pdatastructures/pqueues/RomLogLinkedListQueue.hpp\"\r\n#include \"pdatastructures/pqueues/RomLRLinkedListQueue.hpp\"\r\n#include \"pdatastructures/pqueues/PMDKLinkedListQueue.hpp\"\r\n#include \"pdatastructures/pqueues/MichaelScottQueue.hpp\"\r\n#include \"pdatastructures/pqueues/PMichaelScottQueue.hpp\"\r\n#include \"pdatastructures/pqueues/PFriedmanQueue.hpp\"\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {\"data/pq-ll-enq-deq.txt\"};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.2xlarge\r\n    const int numPairs = 100*1000*1000;                          // Number of pairs of items to enqueue-dequeue. 100M for the paper\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size());\r\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\r\n\r\n    for (unsigned it = 0; it < threadList.size(); it++) {\r\n        auto nThreads = threadList[it];\r\n        int ic = 0;\r\n        PBenchmarkQueues bench(nThreads);\r\n        std::cout << \"\\n----- Persistent Queues (Linked-Lists)   numPairs=\" << numPairs << \"   threads=\" << nThreads << \"   runs=\" << numRuns << \" -----\\n\";\r\n        results[ic][it] = bench.enqDeq<POFLFLinkedListQueue<uint64_t>,poflf::OneFileLF>       (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<POFWFLinkedListQueue<uint64_t>,pofwf::OneFileWF>       (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<RomLogLinkedListQueue<uint64_t>,romuluslog::RomulusLog>(cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<RomLRLinkedListQueue<uint64_t>,romuluslr::RomulusLR>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<PMDKLinkedListQueue<uint64_t>,pmdk::PMDKTM>            (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        // We have to use a lot less pairs for the Friedman Queue because it doesn't do memory reclamation and fills up the NVM pool too fast\r\n        results[ic][it] = bench.enqDeqNoTransaction<PFriedmanQueue<uint64_t>>                 (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        //results[ic][it] = bench.enqDeqNoTransaction<PMichaelScottQueue<uint64_t>>             (cNames[ic], numPairs, numRuns);\r\n        //ic++;\r\n        //results[ic][it] = bench.enqDeqNoTransaction<MichaelScottQueue<uint64_t>>              (cNames[ic], numPairs, numRuns);\r\n        //ic++;\r\n        // TODO: Add memory reclamation to Michal's queue... use Andreia's technique, or just fill up the pool\r\n        maxClass = ic;\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names\r\n    for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"\\t\";\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it] << \"\\t\";\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/pread-while-writing.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <cstring>\n\n#include \"pdatastructures/TMRedBlackTree.hpp\"\n#include \"pdatastructures/TMRedBlackTreeByRef.hpp\"\n#ifdef USE_ROMLOG\n#include \"ptms/romuluslog/RomulusLog.hpp\"\n#define DATA_FILE \"data/pread-while-writing-romlog.txt\"\n#elif defined USE_ROMLR\n#include \"ptms/romuluslr/RomulusLR.hpp\"\n#define DATA_FILE \"data/pread-while-writing-romlr.txt\"\n#elif defined USE_OFLF\n#include \"ptms/ponefilelf/OneFilePTMLF.hpp\"\n#define DATA_FILE \"data/pread-while-writing-oflf.txt\"\n#elif defined USE_OFWF\n#include \"ptms/ponefilewf/OneFilePTMWF.hpp\"\n#define DATA_FILE \"data/pread-while-writing-ofwf.txt\"\n#elif defined USE_PMDK\n#include \"ptms/pmdk/PMDKTM.hpp\"\n#define DATA_FILE \"data/pread-while-writing-pmdk.txt\"\n#endif\n#include \"benchmarks/PBenchmarkSets.hpp\"\n\n\nint main(void) {\n    const std::string dataFilename { DATA_FILE };\n    vector<int> threadList = { 32, 64 }; // For the laptop or AWS c5.9xlarge\n    vector<int> ratioList = { 1000 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\n    const int numElements = 1000*1000;                           // Number of keys in the set\n    const int numRuns = 1;                                       // 5 runs for the paper\n    const seconds testLength = 20s;                              // 20s for the paper\n    const int EMAX_CLASS = 10;\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\n    std::string cNames[EMAX_CLASS];\n    int maxClass = 0;\n    // Reset results\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\n\n    double totalHours = (double)ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\n    std::cout << \"This benchmark is going to take \" << totalHours << \" hours to complete\\n\";\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\n\n    PBenchmarkSets<uint64_t> bench;\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\n        auto ratio = ratioList[ir];\n        for (unsigned it = 0; it < threadList.size(); it++) {\n            auto nThreads = threadList[it];\n            int ic = 0;\n            std::cout << \"\\n----- Persistent Sets (Red-Black Tree)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\n#ifdef USE_ROMLOG\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,romuluslog::RomulusLog,romuluslog::persist>,  romuluslog::RomulusLog> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, true);\n            ic++;\n#elif defined USE_ROMLR\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,romuluslr::RomulusLR,romuluslr::persist>,    romuluslr::RomulusLR>    (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, true);\n            ic++;\n#elif defined USE_OFLF\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTree<uint64_t,uint64_t,onefileptmlf::OneFileLF,onefileptmlf::tmtype>,    onefileptmlf::OneFileLF> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, true);\n            ic++;\n#elif defined USE_OFWF\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTree<uint64_t,uint64_t,onefileptmwf::OneFileWF,onefileptmwf::tmtype>,    onefileptmwf::OneFileWF> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, true);\n            ic++;\n#elif defined USE_PMDK\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,pmdk::PMDKTM,pmdk::persist>,                 pmdk::PMDKTM>            (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, true);\n            ic++;\n#endif\n            maxClass = ic;\n        }\n    }\n\n    // Export tab-separated values to a file to be imported in gnuplot or excel\n    ofstream dataFile;\n    dataFile.open(dataFilename);\n    dataFile << \"Threads\\t\";\n    // Printf class names and ratios for each column\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\n        auto ratio = ratioList[ir];\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\n    }\n    dataFile << \"\\n\";\n    for (int it = 0; it < threadList.size(); it++) {\n        dataFile << threadList[it] << \"\\t\";\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\n        }\n        dataFile << \"\\n\";\n    }\n    dataFile.close();\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\n\n    return 0;\n}\n"
  },
  {
    "path": "graphs/pset-hash-1k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"PBenchmarkSets.hpp\"\r\n#include \"pdatastructures/TMHashMap.hpp\"\r\n#include \"pdatastructures/TMHashMapByRef.hpp\"\r\n//#include \"ptms/romuluslog/RomulusLog.hpp\"\r\n//#include \"ptms/romuluslr/RomulusLR.hpp\"\r\n#include \"ptms/PMDKTM.hpp\"\r\n#include \"ptms/OneFilePTMLF.hpp\"\r\n#include \"ptms/OneFilePTMWF.hpp\"\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {\"data/pset-hash-1k.txt\"};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000;                                // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\r\n\r\n    PBenchmarkSets<uint64_t> bench;\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            std::cout << \"\\n----- Persistent Hash Set (resizable)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n            results[ic][it][ir] = bench.benchmark<TMHashMap<uint64_t,uint64_t,poflf::OneFileLF,poflf::tmtype>,                    poflf::OneFileLF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMHashMap<uint64_t,uint64_t,pofwf::OneFileWF,pofwf::tmtype>,                    pofwf::OneFileWF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][ir] = bench.benchmark<TMHashMapByRef<uint64_t,uint64_t,romuluslog::RomulusLog,romuluslog::persist>,   romuluslog::RomulusLog> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][ir] = bench.benchmark<TMHashMapByRef<uint64_t,uint64_t,romuluslr::RomulusLR,romuluslr::persist>,      romuluslr::RomulusLR>   (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMHashMapByRef<uint64_t,uint64_t,pmdk::PMDKTM,pmdk::persist>,                   pmdk::PMDKTM>           (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/pset-ll-10k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"PBenchmarkSets.hpp\"\r\n#include \"pdatastructures/TMLinkedListSet.hpp\"\r\n//#include \"ptms/romuluslog/RomulusLog.hpp\"\r\n//#include \"ptms/romuluslr/RomulusLR.hpp\"\r\n#include \"ptms/PMDKTM.hpp\"\r\n#include \"ptms/OneFilePTMLF.hpp\"\r\n#include \"ptms/OneFilePTMWF.hpp\"\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {\"data/pset-ll-10k.txt\"};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 10000;                               // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\r\n\r\n    PBenchmarkSets<uint64_t> bench;\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            std::cout << \"\\n----- Persistent Sets (Linked-Lists)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n            results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,poflf::OneFileLF,poflf::tmtype>,               poflf::OneFileLF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,pofwf::OneFileWF,pofwf::tmtype>,               pofwf::OneFileWF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,romuluslog::RomulusLog,romuluslog::persist>,   romuluslog::RomulusLog> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,romuluslr::RomulusLR,romuluslr::persist>,      romuluslr::RomulusLR>   (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,pmdk::PMDKTM,pmdk::persist>,                   pmdk::PMDKTM>           (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned iratio = 0; iratio < ratioList.size(); iratio++) {\r\n        auto ratio = ratioList[iratio];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/pset-ll-1k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"PBenchmarkSets.hpp\"\r\n#include \"pdatastructures/TMLinkedListSetByRef.hpp\"\r\n#include \"pdatastructures/TMLinkedListSet.hpp\"\r\n//#include \"ptms/romuluslog/RomulusLog.hpp\"\r\n//#include \"ptms/romuluslr/RomulusLR.hpp\"\r\n#include \"ptms/PMDKTM.hpp\"\r\n#include \"ptms/OneFilePTMLF.hpp\"\r\n#include \"ptms/OneFilePTMWF.hpp\"\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {\"data/pset-ll-1k.txt\"};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000;                                // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\r\n\r\n    PBenchmarkSets<uint64_t> bench;\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            std::cout << \"\\n----- Persistent Sets (Linked-Lists)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n            results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,poflf::OneFileLF,poflf::tmtype>,                    poflf::OneFileLF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMLinkedListSet<uint64_t,pofwf::OneFileWF,pofwf::tmtype>,                    pofwf::OneFileWF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][ir] = bench.benchmark<TMLinkedListSetByRef<uint64_t,romuluslog::RomulusLog,romuluslog::persist>,   romuluslog::RomulusLog> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][ir] = bench.benchmark<TMLinkedListSetByRef<uint64_t,romuluslr::RomulusLR,romuluslr::persist>,      romuluslr::RomulusLR>   (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMLinkedListSetByRef<uint64_t,pmdk::PMDKTM,pmdk::persist>,                   pmdk::PMDKTM>           (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/pset-tree-1k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n\r\n#include \"PBenchmarkSets.hpp\"\r\n#include \"pdatastructures/TMRedBlackTree.hpp\"\r\n#include \"pdatastructures/TMRedBlackTreeByRef.hpp\"\r\n#include \"ptms/romuluslog/RomulusLog.hpp\"\r\n#include \"ptms/romuluslr/RomulusLR.hpp\"\r\n#include \"ptms/PMDKTM.hpp\"\r\n#include \"ptms/OneFilePTMLF.hpp\"\r\n#include \"ptms/OneFilePTMWF.hpp\"\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {\"data/pset-tree-1k.txt\"};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000;                                // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\r\n\r\n    PBenchmarkSets<uint64_t> bench;\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            std::cout << \"\\n----- Persistent Sets (Red-Black Tree)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTree<uint64_t,uint64_t,poflf::OneFileLF,poflf::tmtype>,                    poflf::OneFileLF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTree<uint64_t,uint64_t,pofwf::OneFileWF,pofwf::tmtype>,                    pofwf::OneFileWF>       (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,romuluslog::RomulusLog,romuluslog::persist>,   romuluslog::RomulusLog> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,romuluslr::RomulusLR,romuluslr::persist>,      romuluslr::RomulusLR>   (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,pmdk::PMDKTM,pmdk::persist>,                   pmdk::PMDKTM>           (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/pset-tree-1m.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <cstring>\n\n#include \"pdatastructures/TMRedBlackTree.hpp\"\n#include \"pdatastructures/TMRedBlackTreeByRef.hpp\"\n#ifdef USE_ROMLOG\n#include \"ptms/romuluslog/RomulusLog.hpp\"\n#define DATA_FILE \"data/pset-tree-1m-romlog.txt\"\n#elif defined USE_ROMLR\n#include \"ptms/romuluslr/RomulusLR.hpp\"\n#define DATA_FILE \"data/pset-tree-1m-romlr.txt\"\n#elif defined USE_OFLF\n#include \"ptms/OneFilePTMLF.hpp\"\n#define DATA_FILE \"data/pset-tree-1m-oflf.txt\"\n#elif defined USE_OFWF\n#include \"ptms/OneFilePTMWF.hpp\"\n#define DATA_FILE \"data/pset-tree-1m-ofwf.txt\"\n#elif defined USE_PMDK\n#include \"ptms/PMDKTM.hpp\"\n#define DATA_FILE \"data/pset-tree-1m-pmdk.txt\"\n#endif\n#include \"PBenchmarkSets.hpp\"\n\n\nint main(void) {\n    const std::string dataFilename { DATA_FILE };\n    vector<int> threadList = { 1, 2, 4, 8, 16, 24, 32, 48, 64 }; // For the laptop or AWS c5.9xlarge\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\n    const int numElements = 1000*1000;                           // Number of keys in the set\n    const int numRuns = 1;                                       // 5 runs for the paper\n    const seconds testLength = 20s;                              // 20s for the paper\n    const int EMAX_CLASS = 10;\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\n    std::string cNames[EMAX_CLASS];\n    int maxClass = 0;\n    // Reset results\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\n\n    double totalHours = (double)ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\n    std::cout << \"This benchmark is going to take \" << totalHours << \" hours to complete\\n\";\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\n\n    PBenchmarkSets<uint64_t> bench;\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\n        auto ratio = ratioList[ir];\n        for (unsigned it = 0; it < threadList.size(); it++) {\n            auto nThreads = threadList[it];\n            int ic = 0;\n            std::cout << \"\\n----- Persistent Sets (Red-Black Tree)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\n#ifdef USE_ROMLOG\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,romuluslog::RomulusLog,romuluslog::persist>,  romuluslog::RomulusLog> (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\n            ic++;\n#elif defined USE_ROMLR\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,romuluslr::RomulusLR,romuluslr::persist>,    romuluslr::RomulusLR>    (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\n            ic++;\n#elif defined USE_OFLF\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTree<uint64_t,uint64_t,poflf::OneFileLF,poflf::tmtype>,                  poflf::OneFileLF>        (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\n            ic++;\n#elif defined USE_OFWF\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTree<uint64_t,uint64_t,pofwf::OneFileWF,pofwf::tmtype>,                  pofwf::OneFileWF>        (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\n            ic++;\n#elif defined USE_PMDK\n            results[ic][it][ir] = bench.benchmark<TMRedBlackTreeByRef<uint64_t,uint64_t,pmdk::PMDKTM,pmdk::persist>,                 pmdk::PMDKTM>            (cNames[ic], nThreads, ratio, testLength, numRuns, numElements, false);\n            ic++;\n#endif\n            maxClass = ic;\n        }\n    }\n\n    // Export tab-separated values to a file to be imported in gnuplot or excel\n    ofstream dataFile;\n    dataFile.open(dataFilename);\n    dataFile << \"Threads\\t\";\n    // Printf class names and ratios for each column\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\n        auto ratio = ratioList[ir];\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\n    }\n    dataFile << \"\\n\";\n    for (int it = 0; it < threadList.size(); it++) {\n        dataFile << threadList[it] << \"\\t\";\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\n        }\n        dataFile << \"\\n\";\n    }\n    dataFile.close();\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\n\n    return 0;\n}\n"
  },
  {
    "path": "graphs/psps-integer.cpp",
    "content": "/*\r\n * This benchmark executes SPS for the following PTMs:\r\n * - RomulusLog\r\n * - RomulusLR\r\n * - PMDK\r\n * - OneFilePTM-LF (lock-free)\r\n * - OneFilePTM-WF (wait-free bounded)\r\n */\r\n#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n\r\n#include \"PBenchmarkSPS.hpp\"\r\n#include \"ptms/romuluslog/RomulusLog.hpp\"\r\n#include \"ptms/romuluslr/RomulusLR.hpp\"\r\n#include \"ptms/PMDKTM.hpp\"\r\n#include \"ptms/OneFilePTMLF.hpp\"\r\n#include \"ptms/OneFilePTMWF.hpp\"\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {\"data/psps-integer.txt\"};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 }; // For the laptop or AWS c5.9xlarge\r\n    vector<long> swapsPerTxList = { 1, 4, 8, 16, 32, 64, 128, 256 };\r\n    const int numRuns = 1;                                   // 5 runs for the paper\r\n    const seconds testLength = 20s;                          // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    int maxClass = 0;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][swapsPerTxList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*swapsPerTxList.size());\r\n\r\n    // SPS Benchmarks multi-threaded\r\n    std::cout << \"If you use PMDK, don't forget to set 'export PMEM_IS_PMEM_FORCE=1'\\n\";\r\n    std::cout << \"\\n----- Persistent SPS Benchmark (multi-threaded integer array swap) -----\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        int nThreads = threadList[it];\r\n        for (int is = 0; is < swapsPerTxList.size(); is++) {\r\n            int nWords = swapsPerTxList[is];\r\n            int ic = 0;\r\n            PBenchmarkSPS bench(nThreads);\r\n            std::cout << \"\\n----- threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s   arraySize=\" << arraySize << \"   swaps/tx=\" << nWords << \" -----\\n\";\r\n            results[ic][it][is] = bench.benchmarkSPSInteger<poflf::OneFileLF,        poflf::tmtype>        (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            results[ic][it][is] = bench.benchmarkSPSInteger<pofwf::OneFileWF,        pofwf::tmtype>        (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            results[ic][it][is] = bench.benchmarkSPSInteger<romuluslog::RomulusLog,  romuluslog::persist>  (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            results[ic][it][is] = bench.benchmarkSPSInteger<romuluslr::RomulusLR,    romuluslr::persist>   (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            results[ic][it][is] = bench.benchmarkSPSInteger<pmdk::PMDKTM,            pmdk::persist>        (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            maxClass = ic;\r\n        }\r\n        std::cout << \"\\n\";\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Swaps\\t\";\r\n    // Printf class names for each column plus the corresponding thread\r\n    for (int ic = 0; ic < maxClass; ic++) {\r\n        for (int it = 0; it < threadList.size(); it++) {\r\n            int nThreads = threadList[it];\r\n            dataFile << cNames[ic] << \"-\" << nThreads <<\"T\\t\";\r\n        }\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int is = 0; is < swapsPerTxList.size(); is++) {\r\n        dataFile << swapsPerTxList[is] << \"\\t\";\r\n        for (int ic = 0; ic < maxClass; ic++) {\r\n            for (int it = 0; it < threadList.size(); it++) {\r\n                dataFile << results[ic][it][is] << \"\\t\";\r\n            }\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/q-array-enq-deq.cpp",
    "content": "/*\r\n * Executes the following non-blocking (array based) queues in a single-enqueue-single-dequeue benchmark:\r\n * - LCRQ (lock-free)\r\n * - FAAArrayQueue (lock-free)\r\n * - MWC-LF (lock-free)\r\n * - MWC-WF (wait-free bounded)\r\n */\r\n#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkQueues.hpp\"\r\n#include \"datastructures/queues/LCRQueue.hpp\"\r\n#include \"datastructures/queues/FAAArrayQueue.hpp\"\r\n#include \"datastructures/queues/OFLFArrayLinkedListQueue.hpp\"\r\n#include \"datastructures/queues/OFWFArrayLinkedListQueue.hpp\"\r\n#include \"datastructures/queues/OFLFArrayQueue.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n#include \"datastructures/queues/TL2STMArrayLinkedListQueue.hpp\"\r\n#include \"datastructures/queues/TL2STMArrayQueue.hpp\"\r\n#define DATA_FILENAME \"data/q-array-enq-deq-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"datastructures/queues/TinySTMArrayLinkedListQueue.hpp\"\r\n#define DATA_FILENAME \"data/q-array-enq-deq-tiny.txt\"\r\n#else\r\n#include \"datastructures/queues/ESTMArrayLinkedListQueue.hpp\"\r\n#define DATA_FILENAME \"data/q-array-enq-deq.txt\"\r\n#endif\r\n\r\n#define MILLION  1000000LL\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    const int numRuns = 1;                                   // Number of runs\r\n    const long numPairs = 100*MILLION;                       // 10M is fast enough on the laptop, but on AWS we can use 100M\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size());\r\n\r\n    // Enq-Deq Throughput benchmarks\r\n    for (int ithread = 0; ithread < threadList.size(); ithread++) {\r\n        int nThreads = threadList[ithread];\r\n        int ic = 0;\r\n        BenchmarkQueues bench(nThreads);\r\n        std::cout << \"\\n----- q-array-enq-deq   threads=\" << nThreads << \"   pairs=\" << numPairs/MILLION << \"M   runs=\" << numRuns << \"-----\\n\";\r\n#ifdef USE_TL2\r\n        results[ic][ithread] = bench.enqDeq<TL2STMArrayLinkedListQueue<UserData>> (cNames[ic], numPairs, numRuns);\r\n        //results[iclass][ithread] = bench.enqDeq<TL2STMArrayQueue<UserData>> (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n#elif defined USE_TINY\r\n        results[ic][ithread] = bench.enqDeq<TinySTMArrayLinkedListQueue<UserData>> (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n#else\r\n        results[ic][ithread] = bench.enqDeq<OFLFArrayLinkedListQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        //results[iclass][ithread] = bench.enqDeq<OFLFArrayQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][ithread] = bench.enqDeq<OFWFArrayLinkedListQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][ithread] = bench.enqDeq<ESTMArrayLinkedListQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][ithread] = bench.enqDeq<FAAArrayQueue<UserData>>              (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][ithread] = bench.enqDeq<LCRQueue<UserData>>                   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n#endif\r\n        maxClass = ic;\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names for each column\r\n    for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"\\t\";\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it] << \"\\t\";\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/q-ll-enq-deq.cpp",
    "content": "/*\r\n * Executes the following non-blocking (linked list based) queues in a single-enqueue-single-dequeue benchmark:\r\n * - Michael-Scott (lock-free)\r\n * - SimQueue (wait-free bounded)\r\n * - Turn Queue (wait-free bounded)\r\n * - MWC-LF (lock-free)\r\n * - MWC-WF (wait-free bounded)\r\n */\r\n#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkQueues.hpp\"\r\n#include \"datastructures/queues/MichaelScottQueue.hpp\"\r\n#include \"datastructures/queues/SimQueue.hpp\"\r\n#include \"datastructures/queues/TurnQueue.hpp\"\r\n#include \"datastructures/queues/OFWFLinkedListQueue.hpp\"\r\n#include \"datastructures/queues/OFLFLinkedListQueue.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n#include \"datastructures/queues/TL2STMLinkedListQueue.hpp\"\r\n#define DATA_FILENAME \"data/q-ll-enq-deq-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"datastructures/queues/TinySTMLinkedListQueue.hpp\"\r\n#define DATA_FILENAME \"data/q-ll-enq-deq-tiny.txt\"\r\n#else\r\n#include \"datastructures/queues/ESTMLinkedListQueue.hpp\"\r\n#define DATA_FILENAME \"data/q-ll-enq-deq.txt\"\r\n#endif\r\n\r\n\r\n\r\n#define MILLION  1000000LL\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    const int numRuns = 1;                                       // Number of runs\r\n    const long numPairs = 200*MILLION;                           // 10M is fast enough on the laptop, but on AWS we can use 100M\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size());\r\n\r\n    // Enq-Deq Throughput benchmarks\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        int nThreads = threadList[it];\r\n        int ic = 0;\r\n        BenchmarkQueues bench(nThreads);\r\n        std::cout << \"\\n----- q-ll-enq-deq   threads=\" << nThreads << \"   pairs=\" << numPairs/MILLION << \"M   runs=\" << numRuns << \" -----\\n\";\r\n#if defined USE_TL2\r\n        results[ic][it] = bench.enqDeq<TL2STMLinkedListQueue<UserData>> (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n#elif defined USE_TINY\r\n        results[ic][it] = bench.enqDeq<TinySTMLinkedListQueue<UserData>>(cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n#else\r\n        results[ic][it] = bench.enqDeq<OFLFLinkedListQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<OFWFLinkedListQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<ESTMLinkedListQueue<UserData>>   (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<MichaelScottQueue<UserData>>     (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<SimQueue<UserData>>              (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n        results[ic][it] = bench.enqDeq<TurnQueue<UserData>>             (cNames[ic], numPairs, numRuns);\r\n        ic++;\r\n#endif\r\n        maxClass = ic;\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names for each column\r\n    for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"\\t\";\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it] << \"\\t\";\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/run-all-aws.sh",
    "content": "echo \"Run this on a C5 AWS instance (c5.9xlarge) to generate all the data files for the plots\"\nexport PMEM_IS_PMEM_FORCE=1\nmake persistencyclean\nbin/pq-ll-enq-deq\nmake persistencyclean\nbin/pset-hash-1k\nmake persistencyclean\nbin/pset-ll-1k\nmake persistencyclean\nbin/pset-tree-1k\nmake persistencyclean\nbin/psps-integer\nmake persistencyclean\nbin/q-array-enq-deq\nbin/q-array-enq-deq-tiny\nbin/q-ll-enq-deq\nbin/q-ll-enq-deq-tiny\nbin/set-hash-1k\nbin/set-hash-1k-tiny\nbin/set-ll-1k\nbin/set-ll-1k-tiny\nbin/set-tree-1k\nbin/set-tree-1k-tiny\nbin/set-tree-10k\nbin/set-tree-10k-tiny\nbin/set-tree-1m\nbin/set-tree-1m-tiny\nbin/sps-integer\nbin/sps-integer-tiny\n#bin/sps-object\n#bin/sps-object-tiny\n\nmake persistencyclean\nbin/pset-tree-1m-romlog\nmake persistencyclean\nbin/pset-tree-1m-romlr\nmake persistencyclean\nbin/pset-tree-1m-oflf\nmake persistencyclean\nbin/pset-tree-1m-ofwf\nmake persistencyclean\nbin/pset-tree-1m-pmdk\n\n\n"
  },
  {
    "path": "graphs/set-hash-1k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkSets.hpp\"\r\n#include \"datastructures/hashmaps/OFLFResizableHashSet.hpp\"\r\n#include \"datastructures/hashmaps/OFWFResizableHashSet.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n//#include \"datastructures/hashmaps/TL2STMResizableHashSet.hpp\"\r\n#define DATA_FILENAME \"data/set-hash-1k-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"datastructures/hashmaps/TinySTMResizableHashSet.hpp\"\r\n#define DATA_FILENAME \"data/set-hash-1k-tiny.txt\"\r\n#else\r\n#include \"datastructures/hashmaps/ESTMResizableHashSet.hpp\"\r\n#define DATA_FILENAME \"data/set-hash-1k.txt\"\r\n#endif\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000;                                // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            BenchmarkSets bench(nThreads);\r\n            std::cout << \"\\n----- Sets (Hashtable)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n#if defined USE_TL2\r\n            //results[ic][it][ir] = bench.benchmark<TL2STMResizableHashSet<uint64_t>,uint64_t>            (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n#elif defined USE_TINY\r\n            results[ic][it][ir] = bench.benchmark<TinySTMResizableHashSet<uint64_t>,uint64_t>           (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#else\r\n            // TODO: infinte loop bug?\r\n            results[ic][it][ir] = bench.benchmark<OFLFResizableHashSet<uint64_t>,uint64_t>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<OFWFResizableHashSet<uint64_t>,uint64_t>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<ESTMResizableHashSet<uint64_t>,uint64_t>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][ir] = bench.benchmark<MagedHarrisLinkedListSetHP<uint64_t>,uint64_t>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][ir] = bench.benchmark<MagedHarrisLinkedListSetHE<uint64_t>,uint64_t>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/set-ll-10k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkSets.hpp\"\r\n#include \"datastructures/linkedlists/MagedHarrisLinkedListSetHP.hpp\"\r\n#include \"datastructures/linkedlists/MagedHarrisLinkedListSetHE.hpp\"\r\n#include \"datastructures/linkedlists/OFLFLinkedListSet.hpp\"\r\n#include \"datastructures/linkedlists/OFWFLinkedListSet.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n#include \"datastructures/linkedlists/TL2STMLinkedListSet.hpp\"\r\n#define DATA_FILENAME \"data/set-ll-10k-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"datastructures/linkedlists/TinySTMLinkedListSet.hpp\"\r\n#define DATA_FILENAME \"data/set-ll-10k-tiny.txt\"\r\n#else\r\n#include \"datastructures/linkedlists/ESTMLinkedListSet.hpp\"\r\n#define DATA_FILENAME \"data/set-ll-10k.txt\"\r\n#endif\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.2xlarge\r\n    //vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64, 96 }; // For Cervino\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 10000;                               // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            BenchmarkSets bench(nThreads);\r\n            std::cout << \"\\n----- Sets (Linked-Lists)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n#if defined USE_TL2\r\n            results[ic][it][ir] = bench.benchmark<TL2STMLinkedListSet<UserData>,UserData>            (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#elif defined USE_TINY\r\n            results[ic][it][ir] = bench.benchmark<TinySTMLinkedListSet<UserData>,UserData>           (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#else\r\n            results[ic][it][ir] = bench.benchmark<OFLFLinkedListSet<UserData>,UserData>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<OFWFLinkedListSet<UserData>,UserData>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<ESTMLinkedListSet<UserData>,UserData>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<MagedHarrisLinkedListSetHP<UserData>,UserData>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<MagedHarrisLinkedListSetHE<UserData>,UserData>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][ir] = bench.benchmark<UCSet<CXMutationWF<LinkedListSet<UserData>>,LinkedListSet<UserData>,UserData>,UserData>          (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][ir] = bench.benchmark<UCSet<CXMutationWFTimed<LinkedListSet<UserData>>,LinkedListSet<UserData>,UserData>,UserData>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned iratio = 0; iratio < ratioList.size(); iratio++) {\r\n        auto ratio = ratioList[iratio];\r\n        for (int iclass = 0; iclass < maxClass; iclass++) dataFile << cNames[iclass] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/set-ll-1k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkSets.hpp\"\r\n#include \"datastructures/linkedlists/MagedHarrisLinkedListSetHP.hpp\"\r\n#include \"datastructures/linkedlists/MagedHarrisLinkedListSetHE.hpp\"\r\n#include \"datastructures/linkedlists/OFLFLinkedListSet.hpp\"\r\n#include \"datastructures/linkedlists/OFWFLinkedListSet.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n#include \"datastructures/linkedlists/TL2STMLinkedListSet.hpp\"\r\n#define DATA_FILENAME \"data/set-ll-1k-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"datastructures/linkedlists/TinySTMLinkedListSet.hpp\"\r\n#define DATA_FILENAME \"data/set-ll-1k-tiny.txt\"\r\n#else\r\n#include \"datastructures/linkedlists/ESTMLinkedListSet.hpp\"\r\n#define DATA_FILENAME \"data/set-ll-1k.txt\"\r\n#endif\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000;                                // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take at most \" << totalHours << \" hours to complete\\n\";\r\n\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            BenchmarkSets bench(nThreads);\r\n            std::cout << \"\\n----- Sets (Linked-Lists)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n#if defined USE_TL2\r\n            results[ic][it][ir] = bench.benchmark<TL2STMLinkedListSet<UserData>,UserData>            (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#elif defined USE_TINY\r\n            results[ic][it][ir] = bench.benchmark<TinySTMLinkedListSet<UserData>,UserData>           (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#else\r\n            results[ic][it][ir] = bench.benchmark<OFLFLinkedListSet<UserData>,UserData>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<OFWFLinkedListSet<UserData>,UserData>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<ESTMLinkedListSet<UserData>,UserData>              (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<MagedHarrisLinkedListSetHP<UserData>,UserData>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][ir] = bench.benchmark<MagedHarrisLinkedListSetHE<UserData>,UserData>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned iratio = 0; iratio < ratioList.size(); iratio++) {\r\n        auto ratio = ratioList[iratio];\r\n        for (int iclass = 0; iclass < maxClass; iclass++) dataFile << cNames[iclass] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/set-tree-10k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkSets.hpp\"\r\n#include \"datastructures/treemaps/NatarajanTreeHE.hpp\"\r\n#include \"datastructures/treemaps/OFLFRedBlackTree.hpp\"\r\n#include \"datastructures/treemaps/OFWFRedBlackTree.hpp\"\r\n// Macros suck, but it's either TinySTM or ESTM, we can't have both at the same time\r\n#ifdef USE_TINY\r\n#include \"datastructures/treemaps/TinySTMRedBlackTree.hpp\"\r\n#define DATA_FILENAME \"data/set-tree-10k-tiny.txt\"\r\n#else\r\n#include \"datastructures/treemaps/ESTMRedBlackTree.hpp\"\r\n#define DATA_FILENAME \"data/set-tree-10k.txt\"\r\n#endif\r\n\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 10000;                               // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take about \" << totalHours << \" hours to complete\\n\";\r\n\r\n    for (unsigned iratio = 0; iratio < ratioList.size(); iratio++) {\r\n        auto ratio = ratioList[iratio];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            BenchmarkSets bench(nThreads);\r\n            std::cout << \"\\n----- Sets (Trees)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n#ifdef USE_TINY\r\n            results[ic][it][iratio] = bench.benchmark<TinySTMRedBlackTree<uint64_t,uint64_t>,uint64_t>                                     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#else\r\n            results[ic][it][iratio] = bench.benchmark<OFLFRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<OFWFRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<ESTMRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<NatarajanTreeHE<uint64_t,uint64_t>,uint64_t>                                         (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/set-tree-1k.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkSets.hpp\"\r\n#include \"datastructures/treemaps/NatarajanTreeHE.hpp\"\r\n#include \"datastructures/treemaps/OFLFRedBlackTree.hpp\"\r\n#include \"datastructures/treemaps/OFWFRedBlackTree.hpp\"\r\n// Macros suck, but it's either TinySTM or ESTM, we can't have both at the same time\r\n#ifdef USE_TINY\r\n#include \"datastructures/treemaps/TinySTMRedBlackTree.hpp\"\r\n#define DATA_FILENAME \"data/set-tree-1k-tiny.txt\"\r\n#else\r\n//#include \"datastructures/trevor_brown_abtree/TrevorBrownABTree.hpp\"\r\n//#include \"datastructures/trevor_brown_natarajan/TrevorBrownNatarajanTree.hpp\"\r\n#include \"datastructures/treemaps/ESTMRedBlackTree.hpp\"\r\n#define DATA_FILENAME \"data/set-tree-1k.txt\"\r\n#endif\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000;                                // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    std::cout << \"This benchmark is going to take about \" << totalHours << \" hours to complete\\n\";\r\n\r\n    for (unsigned iratio = 0; iratio < ratioList.size(); iratio++) {\r\n        auto ratio = ratioList[iratio];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            BenchmarkSets bench(nThreads);\r\n            std::cout << \"\\n----- Sets (Trees)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n#ifdef USE_TINY\r\n            results[ic][it][iratio] = bench.benchmark<TinySTMRedBlackTree<uint64_t,uint64_t>,uint64_t>                                     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#else\r\n            results[ic][it][iratio] = bench.benchmark<OFLFRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<OFWFRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<ESTMRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<NatarajanTreeHE<uint64_t,uint64_t>,uint64_t>                                         (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][iratio] = bench.benchmark<TrevorBrownABTree<uint64_t>,uint64_t>                                                (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][iratio] = bench.benchmark<TrevorBrownNatarajanTree<uint64_t>,uint64_t>                                         (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/set-tree-1m.cpp",
    "content": "#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n//#include \"datastructures/treemaps/NatarajanTreeHE.hpp\"\r\n#include \"datastructures/treemaps/OFLFRedBlackTree.hpp\"\r\n#include \"datastructures/treemaps/OFWFRedBlackTree.hpp\"\r\n#include \"BenchmarkSets.hpp\"\r\n// Macros suck, but it's either TinySTM or ESTM, we can't have both at the same time\r\n#ifdef USE_TINY\r\n#include \"datastructures/treemaps/TinySTMRedBlackTree.hpp\"\r\n#define DATA_FILENAME \"data/set-tree-1m-tiny.txt\"\r\n#else\r\n#include \"datastructures/treemaps/ESTMRedBlackTree.hpp\"\r\n#define DATA_FILENAME \"data/set-tree-1m.txt\"\r\n#endif\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };     // For the laptop or AWS c5.9xlarge\r\n    vector<int> ratioList = { 1000, 500, 100, 10, 1, 0 };        // Permil ratio: 100%, 50%, 10%, 1%, 0.1%, 0%\r\n    const int numElements = 1000*1000;                           // Number of keys in the set\r\n    const int numRuns = 1;                                       // 5 runs for the paper\r\n    const seconds testLength = 20s;                              // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][ratioList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*ratioList.size());\r\n\r\n    double totalHours = (double)EMAX_CLASS*ratioList.size()*threadList.size()*testLength.count()*numRuns/(60.*60.);\r\n    //std::cout << \"This benchmark needs LARGER LOGS than the default settings to fit the 1M keys\\n\";\r\n    //std::cout << \"Make sure to increase TX_MAX_STORES to 32*1024*1024ULL\\n\";\r\n    std::cout << \"This benchmark is going to take about \" << totalHours << \" hours to complete\\n\";\r\n\r\n    for (unsigned iratio = 0; iratio < ratioList.size(); iratio++) {\r\n        auto ratio = ratioList[iratio];\r\n        for (unsigned it = 0; it < threadList.size(); it++) {\r\n            auto nThreads = threadList[it];\r\n            int ic = 0;\r\n            BenchmarkSets bench(nThreads);\r\n            std::cout << \"\\n----- Sets (Trees)   numElements=\" << numElements << \"   ratio=\" << ratio/10. << \"%   threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s -----\\n\";\r\n#ifdef USE_TINY\r\n            results[ic][it][iratio] = bench.benchmark<TinySTMRedBlackTree<uint64_t,uint64_t>,uint64_t>                                     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n#else\r\n            results[ic][it][iratio] = bench.benchmark<OFLFRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<OFWFRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            results[ic][it][iratio] = bench.benchmark<ESTMRedBlackTree<uint64_t,uint64_t>,uint64_t>                                        (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            ic++;\r\n            //results[ic][it][iratio] = bench.benchmark<NatarajanTreeHE<uint64_t,uint64_t>,uint64_t>                                         (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][iratio] = bench.benchmark<UCSet<CXMutationWF<AVLTree<uint64_t>>,AVLTree<uint64_t>,uint64_t>,uint64_t>          (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][iratio] = bench.benchmark<UCSet<CXMutationWF<TreeSet<uint64_t>>,TreeSet<uint64_t>,uint64_t>,uint64_t>          (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n            //results[ic][it][iratio] = bench.benchmark<UCSet<CXMutationWFTimed<TreeSet<uint64_t>>,TreeSet<uint64_t>,uint64_t>,uint64_t>     (cNames[ic], ratio, testLength, numRuns, numElements, false);\r\n            //ic++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Threads\\t\";\r\n    // Printf class names and ratios for each column\r\n    for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n        auto ratio = ratioList[ir];\r\n        for (int ic = 0; ic < maxClass; ic++) dataFile << cNames[ic] << \"-\" << ratio/10. << \"%\"<< \"\\t\";\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        dataFile << threadList[it] << \"\\t\";\r\n        for (unsigned ir = 0; ir < ratioList.size(); ir++) {\r\n            for (int ic = 0; ic < maxClass; ic++) dataFile << results[ic][it][ir] << \"\\t\";\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/sps-integer.cpp",
    "content": "\r\n/*\r\n * Executes SPS for the following STMs:\r\n * - OneFileLF (lock-free)\r\n * - OneFileWF (bounded wait-free)\r\n * - Elastic STM (blocking)\r\n * - TinySTM (blocking)\r\n * - TL2 (blocking)\r\n */\r\n#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n//#include \"stms/CRWWPSTM.hpp\"\r\n#include \"stms/OneFileLF.hpp\"\r\n#include \"stms/OneFileWF.hpp\"\r\n#include \"BenchmarkSPS.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n#include \"stms/TL2STM.hpp\"\r\n#define DATA_FILENAME \"data/sps-integer-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"stms/TinySTM.hpp\"\r\n#define DATA_FILENAME \"data/sps-integer-tiny.txt\"\r\n#else\r\n#include \"stms/ESTM.hpp\"\r\n#define DATA_FILENAME \"data/sps-integer.txt\"\r\n#endif\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };         // For the laptop or AWS c5.9xlarge\r\n    vector<long> swapsPerTxList = { 1, 4, 8, 16, 32, 64, 128, 256 }; // Number of swapped words per transaction\r\n    const int numRuns = 1;                                           // 5 runs for the paper\r\n    const seconds testLength = 20s;                                  // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][swapsPerTxList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*swapsPerTxList.size());\r\n\r\n    // SPS Benchmarks multi-threaded\r\n    std::cout << \"This benchmark takes about \" << (threadList.size()*swapsPerTxList.size()*numRuns*testLength.count()*3./(60*60)) << \" hours to complete\\n\";\r\n    std::cout << \"\\n----- SPS Benchmark (multi-threaded integer array swap) -----\\n\";\r\n    for (int it = 0; it < threadList.size(); it++) {\r\n        int nThreads = threadList[it];\r\n        for (int iswaps = 0; iswaps < swapsPerTxList.size(); iswaps++) {\r\n            int nWords = swapsPerTxList[iswaps];\r\n            int ic = 0;\r\n            BenchmarkSPS bench(nThreads);\r\n            std::cout << \"\\n----- threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s   arraySize=\" << arraySize << \"   swaps/tx=\" << nWords << \" -----\\n\";\r\n#if defined USE_TL2\r\n            results[ic][it][iswaps] = bench.benchmarkSPSInteger<tl2stm::TL2STM,tl2stm::tmtype>         (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n#elif defined USE_TINY\r\n            // TinySTM starves out and blocks forever when there is too much contention\r\n            if ((nThreads >= 16 && nWords >= 128) || (nThreads >= 32 && nWords >= 32) || nThreads >= 64) {\r\n                cNames[ic] = tinystm::TinySTM::className();\r\n                results[ic][it][iswaps] = 0;\r\n            } else {\r\n                results[ic][it][iswaps] = bench.benchmarkSPSInteger<tinystm::TinySTM,tinystm::tmtype>      (cNames[ic], testLength, nWords, numRuns);\r\n            }\r\n            ic++;\r\n#else\r\n            results[ic][it][iswaps] = bench.benchmarkSPSInteger<oflf::OneFileLF,oflf::tmtype>(cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            results[ic][it][iswaps] = bench.benchmarkSPSInteger<ofwf::OneFileWF,ofwf::tmtype>(cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            // ESTM starves out and blocks forever when there is too much contention\r\n            if ((nThreads >= 16 && nWords >= 128) || (nThreads >= 32 && nWords >= 32) || nThreads >= 64) {\r\n                cNames[ic] = estm::ESTM::className();\r\n                results[ic][it][iswaps] = 0;\r\n            } else {\r\n                results[ic][it][iswaps] = bench.benchmarkSPSInteger<estm::ESTM,estm::tmtype>          (cNames[ic], testLength, nWords, numRuns);\r\n            }\r\n            ic++;\r\n            //results[ic][it][iswaps] = bench.benchmarkSPSInteger<crwwpstm::CRWWPSTM,crwwpstm::tmtype>   (cNames[ic], testLength, nWords, numRuns);\r\n            //iclass++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n        std::cout << \"\\n\";\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Swaps\\t\";\r\n    // Printf class names for each column plus the corresponding thread\r\n    for (int iclass = 0; iclass < maxClass; iclass++) {\r\n        for (int ithread = 0; ithread < threadList.size(); ithread++) {\r\n            int nThreads = threadList[ithread];\r\n            dataFile << cNames[iclass] << \"-\" << nThreads <<\"T\\t\";\r\n        }\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int iswaps = 0; iswaps < swapsPerTxList.size(); iswaps++) {\r\n        dataFile << swapsPerTxList[iswaps] << \"\\t\";\r\n        for (int iclass = 0; iclass < maxClass; iclass++) {\r\n            for (int ithread = 0; ithread < threadList.size(); ithread++) {\r\n                dataFile << results[iclass][ithread][iswaps] << \"\\t\";\r\n            }\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "graphs/sps-object.cpp",
    "content": "/*\r\n * Executes SPS (with objects) for the following STMs:\r\n * - OneFileLF (lock-free)\r\n * - OneFileWF (bounded wait-free)\r\n * - Elastic STM (blocking)\r\n * - TinySTM (blocking)\r\n * - TL2 (blocking)\r\n */\r\n#include <iostream>\r\n#include <fstream>\r\n#include <cstring>\r\n#include \"BenchmarkSPS.hpp\"\r\n//#include \"stms/CRWWPSTM.hpp\"\r\n#include \"stms/OneFileLF.hpp\"\r\n#include \"stms/OneFileWF.hpp\"\r\n// Macros suck, but it's either TL2 or TinySTM or ESTM, we can't have all at the same time\r\n#if defined USE_TL2\r\n#include \"stms/TL2STM.hpp\"\r\n#define DATA_FILENAME \"data/sps-object-tl2.txt\"\r\n#elif defined USE_TINY\r\n#include \"stms/TinySTM.hpp\"\r\n#define DATA_FILENAME \"data/sps-object-tiny.txt\"\r\n#else\r\n#include \"stms/ESTM.hpp\"\r\n#define DATA_FILENAME \"data/sps-object.txt\"\r\n#endif\r\n\r\n\r\nint main(void) {\r\n    const std::string dataFilename {DATA_FILENAME};\r\n    vector<int> threadList = { 1, 2, 4, 8, 16, 32, 48, 64 };         // For the laptop or AWS c5.9xlarge\r\n    vector<long> swapsPerTxList = { 1, 4, 8, 16, 32, 64, 128, 256 }; // Number of replaced objects per transaction\r\n    const int numRuns = 1;                                           // 5 runs for the paper\r\n    const seconds testLength = 10s;                                  // 20s for the paper\r\n    const int EMAX_CLASS = 10;\r\n    uint64_t results[EMAX_CLASS][threadList.size()][swapsPerTxList.size()];\r\n    std::string cNames[EMAX_CLASS];\r\n    int maxClass = 0;\r\n    // Reset results\r\n    std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*swapsPerTxList.size());\r\n\r\n    // SPS Objects Benchmarks multi-threaded\r\n    std::cout << \"This benchmark takes about \" << (threadList.size()*swapsPerTxList.size()*numRuns*testLength.count()*3./(60*60)) << \" hours to complete\\n\";\r\n    std::cout << \"\\n----- SPS Benchmark (multi-threaded object array replace) -----\\n\";\r\n    for (int ithread = 0; ithread < threadList.size(); ithread++) {\r\n        int nThreads = threadList[ithread];\r\n        for (int iswaps = 0; iswaps < swapsPerTxList.size(); iswaps++) {\r\n            int nWords = swapsPerTxList[iswaps];\r\n            int ic = 0;\r\n            BenchmarkSPS bench(nThreads);\r\n            std::cout << \"\\n----- threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s   arraySize=\" << arraySize << \"   swaps/tx=\" << nWords << \" -----\\n\";\r\n#if defined USE_TL2\r\n            results[ic][ithread][iswaps] = bench.benchmarkSPSObject<tl2stm::TL2STM,tl2stm::tmtype,tl2stm::tmbase>            (cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n#elif defined USE_TINY\r\n            // TinySTM starves out and blocks forever when there is too much contention\r\n            if ((nThreads >= 16 && nWords >= 128) || (nThreads >= 32 && nWords >= 32) || nThreads >= 64) {\r\n                cNames[ic] = tinystm::TinySTM::className();\r\n                results[ic][ithread][iswaps] = 0;\r\n            } else {\r\n                results[ic][ithread][iswaps] = bench.benchmarkSPSObject<tinystm::TinySTM,tinystm::tmtype,tinystm::tmbase>        (cNames[ic], testLength, nWords, numRuns);\r\n            }\r\n            ic++;\r\n#else\r\n            results[ic][ithread][iswaps] = bench.benchmarkSPSObject<oflf::OneFileLF,oflf::tmtype,oflf::tmbase>(cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            results[ic][ithread][iswaps] = bench.benchmarkSPSObject<ofwf::OneFileWF,ofwf::tmtype,ofwf::tmbase>(cNames[ic], testLength, nWords, numRuns);\r\n            ic++;\r\n            // ESTM starves out and blocks forever when there is too much contention\r\n            if ((nThreads >= 16 && nWords >= 128) || (nThreads >= 32 && nWords >= 32) || nThreads >= 64) {\r\n                cNames[ic] = estm::ESTM::className();\r\n                results[ic][ithread][iswaps] = 0;\r\n            } else {\r\n                results[ic][ithread][iswaps] = bench.benchmarkSPSObject<estm::ESTM,estm::tmtype,estm::tmbase>                (cNames[ic], testLength, nWords, numRuns);\r\n            }\r\n            ic++;\r\n            //results[iclass][ithread][iswaps] = bench.benchmarkSPSObject<crwwpstm::CRWWPSTM,crwwpstm::tmtype,crwwpstm::tmtbase>    (cNames[iclass], testLength, nWords, numRuns);\r\n            //iclass++;\r\n#endif\r\n            maxClass = ic;\r\n        }\r\n        std::cout << \"\\n\";\r\n    }\r\n\r\n    // Export tab-separated values to a file to be imported in gnuplot or excel\r\n    ofstream dataFile;\r\n    dataFile.open(dataFilename);\r\n    dataFile << \"Swaps\\t\";\r\n    // Printf class names for each column plus the corresponding thread\r\n    for (int ic = 0; ic < maxClass; ic++) {\r\n        for (int it = 0; it < threadList.size(); it++) {\r\n            int nThreads = threadList[it];\r\n            dataFile << cNames[ic] << \"-\" << nThreads <<\"T\\t\";\r\n        }\r\n    }\r\n    dataFile << \"\\n\";\r\n    for (int is = 0; is < swapsPerTxList.size(); is++) {\r\n        dataFile << swapsPerTxList[is] << \"\\t\";\r\n        for (int ic = 0; ic < maxClass; ic++) {\r\n            for (int it = 0; it < threadList.size(); it++) {\r\n                dataFile << results[ic][it][is] << \"\\t\";\r\n            }\r\n        }\r\n        dataFile << \"\\n\";\r\n    }\r\n    dataFile.close();\r\n    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "pdatastructures/README.md",
    "content": "# Persistent Data Structures #\r\n\r\nThis is a copy of cxtm/pdatastructures\r\nIf you change something here then make sure to make the same changes in cxtm/pdatastructures so that they're both in sync."
  },
  {
    "path": "pdatastructures/TMHashMap.hpp",
    "content": "#ifndef _PERSISTENT_TM_RESIZABLE_HASH_MAP_H_\n#define _PERSISTENT_TM_RESIZABLE_HASH_MAP_H_\n\n#include <string>\n\n/**\n * <h1> A Resizable Hash Map for PTMs </h1>\n */\ntemplate<typename K, typename V, typename TM, template <typename> class TMTYPE>\nclass TMHashMap {\n\nprivate:\n    struct Node {\n        TMTYPE<K>     key;\n        TMTYPE<V>     val;\n        TMTYPE<Node*> next {nullptr};\n        Node(const K& k, const V& v) : key{k}, val{v} { } // Copy constructor for k and value\n        Node() {}\n    };\n\n\n    TMTYPE<uint64_t>                    capacity;\n    TMTYPE<uint64_t>                    sizeHM = 0;\n    //TMTYPE<double>\t\t\t\t\tloadFactor = 0.75;\n    static constexpr double             loadFactor = 0.75;\n    alignas(128) TMTYPE<TMTYPE<Node*>*> buckets;      // An array of pointers to Nodes\n\n\npublic:\n    TMHashMap(uint64_t capacity=4) : capacity{capacity} {\n\t\tbuckets = (TMTYPE<Node*>*)TM::pmalloc(capacity*sizeof(TMTYPE<Node*>));\n\t\tfor (int i = 0; i < capacity; i++) buckets[i]=nullptr;\n    }\n\n\n    ~TMHashMap() {\n\t\tfor(int i = 0; i < capacity; i++){\n\t\t\tNode* node = buckets[i];\n\t\t\twhile (node!=nullptr) {\n\t\t\t\tNode* next = node->next;\n\t\t\t\tTM::tmDelete(node);\n\t\t\t\tnode = next;\n\t\t\t}\n\t\t}\n\t\tTM::pfree(buckets);\n    }\n\n\n    static std::string className() { return TM::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        uint64_t newcapacity = 2*capacity;\n        //printf(\"increasing capacity to %d\\n\", newcapacity);\n        TMTYPE<Node*>* newbuckets = (TMTYPE<Node*>*)TM::pmalloc(newcapacity*sizeof(TMTYPE<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while(node!=nullptr){\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        TM::pfree(buckets);\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key, const V& value, V& oldValue, const bool saveOldValue) {\n    \t//printf(\"innerPut %d %d %f\\n\", sizeHM.pload(), capacity.pload(), loadFactor.pload()*capacity.pload());\n        if (sizeHM.pload() > capacity.pload()*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = TM::template tmNew<Node>(key,value);\n                //Node* newnode = TM::template tmNew<Node>();\n                //newnode->key = key;\n                //newnode->val = value;\n                //newnode->next = nullptr;\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM=sizeHM+1;\n                return true;  // New insertion\n            }\n            if (key == node->key) {\n                if (saveOldValue) oldValue = node->val; // Makes a copy of V\n                node->val = value;\n                return false; // Replace value for existing key\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key, V& oldValue, const bool saveOldValue) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (saveOldValue) oldValue = node->val; // Makes a copy of V\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM=sizeHM-1;\n                TM::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key, V& oldValue, const bool saveOldValue) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (saveOldValue) oldValue = node->val; // Makes a copy of V\n                return true;\n            }\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(const K& key) {\n        return TM::template updateTx<bool>([this,key] () {\n            V notused;\n            return innerPut(key,key,notused,false);\n        });\n    }\n\n    // Returns true only if the key was present\n    bool remove(const K& key) {\n        return TM::template updateTx<bool>([this,key] () {\n            V notused;\n            return innerRemove(key,notused,false);\n        });\n    }\n\n    bool contains(const K& key) {\n        return TM::template readTx<bool>([this,key] () {\n            V notused;\n            return innerGet(key,notused,false);\n        });\n    }\n\n    // Used only for benchmarks\n    bool addAll(K** keys, const int size) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n        return true;\n    }\n};\n\n#endif /* _PERSISTENT_TM_RESIZABLE_HASH_MAP_H_ */\n"
  },
  {
    "path": "pdatastructures/TMHashMapByRef.hpp",
    "content": "#ifndef _PERSISTENT_TM_RESIZABLE_HASH_MAPBYREF_H_\n#define _PERSISTENT_TM_RESIZABLE_HASH_MAPBYREF_H_\n\n#include <string>\n\n/**\n * <h1> A Resizable Hash Map for PTMs </h1>\n */\ntemplate<typename K, typename V, typename TM, template <typename> class TMTYPE>\nclass TMHashMapByRef {\n\nprivate:\n    struct Node {\n        TMTYPE<K>     key;\n        TMTYPE<V>     val;\n        TMTYPE<Node*> next {nullptr};\n        Node(const K& k, const V& v) : key{k}, val{v} { } // Copy constructor for k and value\n        Node() {}\n    };\n\n\n    TMTYPE<uint64_t>                    capacity;\n    TMTYPE<uint64_t>                    sizeHM = 0;\n    //TMTYPE<double>\t\t\t\t\tloadFactor = 0.75;\n    static constexpr double             loadFactor = 0.75;\n    alignas(128) TMTYPE<TMTYPE<Node*>*> buckets;      // An array of pointers to Nodes\n\n\npublic:\n    TMHashMapByRef(uint64_t capacity=4) : capacity{capacity} {\n\t\tbuckets = (TMTYPE<Node*>*)TM::pmalloc(capacity*sizeof(TMTYPE<Node*>));\n\t\tfor (int i = 0; i < capacity; i++) buckets[i]=nullptr;\n    }\n\n\n    ~TMHashMapByRef() {\n\t\tfor(int i = 0; i < capacity; i++){\n\t\t\tNode* node = buckets[i];\n\t\t\twhile (node!=nullptr) {\n\t\t\t\tNode* next = node->next;\n\t\t\t\tTM::tmDelete(node);\n\t\t\t\tnode = next;\n\t\t\t}\n\t\t}\n\t\tTM::pfree(buckets);\n    }\n\n\n    static std::string className() { return TM::className() + \"-HashMap\"; }\n\n\n    void rebuild() {\n        uint64_t newcapacity = 2*capacity;\n        //printf(\"increasing capacity to %d\\n\", newcapacity);\n        TMTYPE<Node*>* newbuckets = (TMTYPE<Node*>*)TM::pmalloc(newcapacity*sizeof(TMTYPE<Node*>));\n        for (int i = 0; i < newcapacity; i++) newbuckets[i] = nullptr;\n        for (int i = 0; i < capacity; i++) {\n            Node* node = buckets[i];\n            while(node!=nullptr){\n                Node* next = node->next;\n                auto h = std::hash<K>{}(node->key) % newcapacity;\n                node->next = newbuckets[h];\n                newbuckets[h] = node;\n                node = next;\n            }\n        }\n        TM::pfree(buckets);\n        buckets = newbuckets;\n        capacity = newcapacity;\n    }\n\n\n    /*\n     * Adds a node with a key if the key is not present, otherwise replaces the value.\n     * If saveOldValue is set, it will set 'oldValue' to the previous value, iff there was already a mapping.\n     *\n     * Returns true if there was no mapping for the key, false if there was already a value and it was replaced.\n     */\n    bool innerPut(const K& key, const V& value, V& oldValue, const bool saveOldValue) {\n    \t//printf(\"innerPut %d %d %f\\n\", sizeHM.pload(), capacity.pload(), loadFactor.pload()*capacity.pload());\n        if (sizeHM.pload() > capacity.pload()*loadFactor) rebuild();\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) {\n                Node* newnode = TM::template tmNew<Node>(key,value);\n                //Node* newnode = TM::template tmNew<Node>();\n                //newnode->key = key;\n                //newnode->val = value;\n                //newnode->next = nullptr;\n                if (node == prev) {\n                    buckets[h] = newnode;\n                } else {\n                    prev->next = newnode;\n                }\n                sizeHM=sizeHM+1;\n                return true;  // New insertion\n            }\n            if (key == node->key) {\n                if (saveOldValue) oldValue = node->val; // Makes a copy of V\n                node->val = value;\n                return false; // Replace value for existing key\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Removes a key and its mapping.\n     * Saves the value in 'oldvalue' if 'saveOldValue' is set.\n     *\n     * Returns returns true if a matching key was found\n     */\n    bool innerRemove(const K& key, V& oldValue, const bool saveOldValue) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        Node* prev = node;\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (saveOldValue) oldValue = node->val; // Makes a copy of V\n                if (node == prev) {\n                    buckets[h] = node->next;\n                } else {\n                    prev->next = node->next;\n                }\n                sizeHM=sizeHM-1;\n                TM::tmDelete(node);\n                return true;\n            }\n            prev = node;\n            node = node->next;\n        }\n    }\n\n\n    /*\n     * Returns true if key is present. Saves a copy of 'value' in 'oldValue' if 'saveOldValue' is set.\n     */\n    bool innerGet(const K& key, V& oldValue, const bool saveOldValue) {\n        auto h = std::hash<K>{}(key) % capacity;\n        Node* node = buckets[h];\n        while (true) {\n            if (node == nullptr) return false;\n            if (key == node->key) {\n                if (saveOldValue) oldValue = node->val; // Makes a copy of V\n                return true;\n            }\n            node = node->next;\n        }\n    }\n\n\n    //\n    // Set methods for running the usual tests and benchmarks\n    //\n\n    // Inserts a key only if it's not already present\n    bool add(const K& key) {\n        bool retval = false;\n        TM::template updateTx<bool>([&] () {\n            V notused;\n            retval = innerPut(key,key,notused,false);\n        });\n        return retval;\n    }\n\n    // Returns true only if the key was present\n    bool remove(const K& key) {\n        bool retval = false;\n        TM::template updateTx<bool>([&] () {\n            V notused;\n            retval = innerRemove(key,notused,false);\n        });\n        return retval;\n    }\n\n    bool contains(const K& key) {\n        bool retval = false;\n        TM::template readTx<bool>([&] () {\n            V notused;\n            retval = innerGet(key,notused,false);\n        });\n        return retval;\n    }\n\n    // Used only for benchmarks\n    bool addAll(K** keys, const int size) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n        return true;\n    }\n};\n\n#endif /* _PERSISTENT_TM_RESIZABLE_HASH_MAPByRef_H_ */\n"
  },
  {
    "path": "pdatastructures/TMLinkedListQueue.hpp",
    "content": "#ifndef _TM_LINKED_LIST_QUEUE_H_\n#define _TM_LINKED_LIST_QUEUE_H_\n\n#include <string>\n\n\n/**\n * <h1> A Linked List queue (memory unbounded) for usage with STMs and PTMs </h1>\n *\n */\ntemplate<typename T, typename TM, template <typename> class TMTYPE>\nclass TMLinkedListQueue {\n\nprivate:\n    struct Node {\n        TMTYPE<T*>    item;\n        TMTYPE<Node*> next {nullptr};\n        Node(T* userItem) : item{userItem} { }\n    };\n\n    alignas(128) TMTYPE<Node*>  head {nullptr};\n    alignas(128) TMTYPE<Node*>  tail {nullptr};\n\n\npublic:\n    TMLinkedListQueue() {\n\t\tNode* sentinelNode = TM::template tmNew<Node>(nullptr);\n\t\thead = sentinelNode;\n\t\ttail = sentinelNode;\n    }\n\n\n    ~TMLinkedListQueue() {\n\t\twhile (dequeue() != nullptr); // Drain the queue\n\t\tNode* lhead = head;\n\t\tTM::tmDelete(lhead);\n    }\n\n\n    static std::string className() { return TM::className() + \"-LinkedListQueue\"; }\n\n\n    bool enqueue(T* item) {\n        return TM::template updateTx<bool>([=] () {\n            Node* newNode = TM::template tmNew<Node>(item);\n            tail->next = newNode;\n            tail = newNode;\n            return true;\n        });\n    }\n\n\n    T* dequeue() {\n        return TM::template updateTx<T*>([=] () -> T* {\n            Node* lhead = head;\n            if (lhead == tail) return nullptr;\n            head = lhead->next;\n            TM::tmDelete(lhead);\n            return head->item;\n        });\n    }\n};\n\n#endif /* _TM_LINKED_LIST_QUEUE_H_ */\n"
  },
  {
    "path": "pdatastructures/TMLinkedListSet.hpp",
    "content": "#ifndef _PERSISTENT_TM_LINKED_LIST_SET_H_\n#define _PERSISTENT_TM_LINKED_LIST_SET_H_\n\n#include <string>\n\n\n/**\n * <h1> A Linked List Set meant to be used with PTMs </h1>\n */\ntemplate<typename K, typename TM, template <typename> class TMTYPE>\nclass TMLinkedListSet {\n\nprivate:\n    struct Node {\n        TMTYPE<K>     key;\n        TMTYPE<Node*> next {nullptr};\n        Node(const K& key) : key{key} { }\n        Node(){ }\n    };\n\n    alignas(128) TMTYPE<Node*>  head {nullptr};\n    alignas(128) TMTYPE<Node*>  tail {nullptr};\n\n\npublic:\n    TMLinkedListSet() {\n        TM::template updateTx<bool>([=] () {\n            Node* lhead = TM::template tmNew<Node>();\n            Node* ltail = TM::template tmNew<Node>();\n            head = lhead;\n            head->next = ltail;\n            tail = ltail;\n            return true; // Needed for CX\n        });\n    }\n\n    ~TMLinkedListSet() {\n        TM::template updateTx<bool>([=] () {\n            // Delete all the nodes in the list\n            Node* prev = head;\n            Node* node = prev->next;\n            while (node != tail) {\n                TM::tmDelete(prev);\n                prev = node;\n                node = node->next;\n            }\n            TM::tmDelete(prev);\n            TM::tmDelete(tail.pload());\n            return true; // Needed for CX\n        });\n    }\n\n    static std::string className() { return TM::className() + \"-LinkedListSet\"; }\n\n    /*\n     * Adds a node with a key, returns false if the key is already in the set\n     */\n    bool add(K key) {\n        return TM::template updateTx<bool>([=] () {\n            K lkey = key;\n            Node *prev, *node;\n            find(lkey, prev, node);\n            if (node != tail && lkey == node->key) return false;\n            Node* newNode = TM::template tmNew<Node>(lkey);\n            //Node* newNode = TM::template tmNew<Node>(); newNode->key = lkey; newNode->next = nullptr;\n            prev->next = newNode;\n            newNode->next = node;\n            return true;\n        });\n    }\n\n    /*\n     * Removes a node with an key, returns false if the key is not in the set\n     */\n    bool remove(K key) {\n        return TM::template updateTx<bool>([=] () {\n            K lkey = key;\n            Node *prev, *node;\n            find(lkey, prev, node);\n            if (!(node != tail && lkey == node->key)) return false;\n            prev->next = node->next;\n            TM::tmDelete(node);\n            return true;\n        });\n    }\n\n    /*\n     * Returns true if it finds a node with a matching key\n     */\n    bool contains(K key) {\n        return TM::template readTx<bool>([=] () {\n            K lkey = key;\n            Node *prev, *node;\n            find(lkey, prev, node);\n            return (node != tail && lkey == node->key);\n        });\n    }\n\n    void find(const K& lkey, Node*& prev, Node*& node) {\n        Node* ltail = tail;\n        for (prev = head; (node = prev->next) != ltail; prev = node) {\n            if ( !(node->key < lkey) ) break;\n        }\n    }\n\n    // Used only for benchmarks\n    bool addAll(K** keys, const int size) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n        return true;\n    }\n};\n\n#endif /* _PERSISTENT_TM_LINKED_LIST_SET_H_ */\n"
  },
  {
    "path": "pdatastructures/TMLinkedListSetByRef.hpp",
    "content": "#ifndef _PERSISTENT_TM_LINKED_LIST_SETBYREF_H_\n#define _PERSISTENT_TM_LINKED_LIST_SETBYREF_H_\n\n#include <string>\n\n\n/**\n * <h1> A Linked List Set meant to be used with PTMs </h1>\n */\ntemplate<typename K, typename TM, template <typename> class TMTYPE>\nclass TMLinkedListSetByRef {\n\nprivate:\n    struct Node {\n        TMTYPE<K>     key;\n        TMTYPE<Node*> next {nullptr};\n        Node(const K& key) : key{key} { }\n        Node(){ }\n    };\n\n    alignas(128) TMTYPE<Node*>  head {nullptr};\n    alignas(128) TMTYPE<Node*>  tail {nullptr};\n\n\npublic:\n    TMLinkedListSetByRef() {\n        TM::template updateTx<bool>([=] () {\n            Node* lhead = TM::template tmNew<Node>();\n            Node* ltail = TM::template tmNew<Node>();\n            head = lhead;\n            head->next = ltail;\n            tail = ltail;\n            return true; // Needed for CX\n        });\n    }\n\n    ~TMLinkedListSetByRef() {\n        TM::template updateTx<bool>([=] () {\n            // Delete all the nodes in the list\n            Node* prev = head;\n            Node* node = prev->next;\n            while (node != tail) {\n                TM::tmDelete(prev);\n                prev = node;\n                node = node->next;\n            }\n            TM::tmDelete(prev);\n            TM::tmDelete(tail.pload());\n            return true; // Needed for CX\n        });\n    }\n\n    static std::string className() { return TM::className() + \"-LinkedListSet\"; }\n\n    /*\n     * Adds a node with a key, returns false if the key is already in the set\n     */\n    bool add(K key) {\n        bool retval = false;\n        TM::template updateTx<bool>([&] () {\n            Node *prev, *node;\n            find(key, prev, node);\n            retval = !(node != tail && key == node->key);\n            if (!retval) return;\n            Node* newNode = TM::template tmNew<Node>(key);\n            prev->next = newNode;\n            newNode->next = node;\n        });\n        return retval;\n    }\n\n    /*\n     * Removes a node with an key, returns false if the key is not in the set\n     */\n    bool remove(K key) {\n        bool retval = false;\n        TM::template updateTx<bool>([&] () {\n            Node *prev, *node;\n            find(key, prev, node);\n            retval = (node != tail && key == node->key);\n            if (!retval) return;\n            prev->next = node->next;\n            TM::tmDelete(node);\n        });\n        return retval;\n    }\n\n    /*\n     * Returns true if it finds a node with a matching key\n     */\n    bool contains(K key) {\n        bool retval = false;\n        TM::template readTx<bool>([&] () {\n            Node *prev, *node;\n            find(key, prev, node);\n            retval = (node != tail && key == node->key);\n        });\n        return retval;\n    }\n\n    void find(const K& lkey, Node*& prev, Node*& node) {\n        Node* ltail = tail;\n        for (prev = head; (node = prev->next) != ltail; prev = node) {\n            if ( !(node->key < lkey) ) break;\n        }\n    }\n\n    // Used only for benchmarks\n    bool addAll(K** keys, const int size) {\n        for (int i = 0; i < size; i++) add(*keys[i]);\n        return true;\n    }\n};\n\n#endif /* _PERSISTENT_TM_LINKED_LIST_SETBYREF_H_ */\n"
  },
  {
    "path": "pdatastructures/TMRedBlackTree.hpp",
    "content": "#ifndef _PERSISTENT_TM_RED_BLACK_BST_H_\r\n#define _PERSISTENT_TM_RED_BLACK_BST_H_\r\n\r\n#include <cassert>\r\n#include <stdexcept>\r\n#include <algorithm>\r\n\r\n\r\n// Adapted from Java to C++ from the original at http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\r\ntemplate<typename K, typename V, typename TM, template <typename> class TMTYPE>\r\nclass TMRedBlackTree {\r\n    const int64_t COLOR_RED   = 0;\r\n    const int64_t COLOR_BLACK = 1;\r\n\r\n    struct Node {\r\n        TMTYPE<K>       key;\r\n        TMTYPE<V>       val;\r\n        TMTYPE<Node*>   left {nullptr};\r\n        TMTYPE<Node*>   right {nullptr};\r\n        TMTYPE<int64_t> color;    // color of parent link\r\n        TMTYPE<int64_t> size;     // subtree count\r\n        Node(const K& key, const V& val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\r\n        Node() {}\r\n    };\r\n\r\n    TMTYPE<Node*> root {nullptr};   // root of the BST\r\n\r\n    inline void assignAndFreeIfNull(TMTYPE<Node*>& z, Node* w) {\r\n        Node* tofree = z;\r\n        z = w;\r\n        if (w == nullptr) TM::tmDelete(tofree);\r\n    }\r\n\r\npublic:\r\n    /**\r\n     * Initializes an empty symbol table.\r\n     */\r\n    TMRedBlackTree(int numThreads=0){ }\r\n\r\n    ~TMRedBlackTree() {\r\n        TM::template updateTx<bool>([=] () {\r\n            if (root == nullptr) return true;\r\n            deleteAll(root);\r\n            return true;\r\n        });\r\n    }\r\n\r\n    void deleteAll(Node* rt){\r\n        Node* left = rt->left;\r\n        if(left!=nullptr){\r\n            deleteAll(left);\r\n        }\r\n        Node* right = rt->right;\r\n        if(right!=nullptr){\r\n            deleteAll(right);\r\n        }\r\n        TM::tmDelete(rt);\r\n        return;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Node helper methods.\r\n     ***************************************************************************/\r\n    // is node x red; false if x is null ?\r\n    bool isRed(Node* x) {\r\n        if (x == nullptr) return false;\r\n        return x->color == COLOR_RED;\r\n    }\r\n\r\n    // number of node in subtree rooted at x; 0 if x is null\r\n    int size(Node* x) {\r\n        if (x == nullptr) return 0;\r\n        return x->size;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the number of key-value pairs in this symbol table.\r\n     * @return the number of key-value pairs in this symbol table\r\n     */\r\n    int size() {\r\n        return size(root);\r\n    }\r\n\r\n    /**\r\n     * Is this symbol table empty?\r\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\r\n     */\r\n    bool isEmpty() {\r\n        return root == nullptr;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Standard BST search->\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the value associated with the given key.\r\n     * @param key the key\r\n     * @return the value associated with the given key if the key is in the symbol table\r\n     *     and {@code null} if the key is not in the symbol table\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerGet(K key, V& oldValue, const bool saveOldValue) {\r\n        bool found = get(root, key);\r\n        if (!found) return false;\r\n        //if (saveOldValue) oldValue = *val; // Copy of V\r\n        return true;\r\n    }\r\n\r\n    // value associated with the given key in subtree rooted at x; null if no such key\r\n    bool get(Node* x, K& key) {\r\n        while (x != nullptr) {\r\n            if      (key < x->key) x = x->left;\r\n            else if (x->key < key) x = x->right;\r\n            else              return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Does this symbol table contain the given key?\r\n     * @param key the key\r\n     * @return {@code true} if this symbol table contains {@code key} and\r\n     *     {@code false} otherwise\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool containsKey(const K& key) {\r\n        return get(key) != nullptr;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree insertion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\r\n     * value with the new value if the symbol table already contains the specified key.\r\n     * Deletes the specified key (and its associated value) from this symbol table\r\n     * if the specified value is {@code null}.\r\n     *\r\n     * @param key the key\r\n     * @param val the value\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    bool innerPut(const K& key, const V& value) {\r\n    \tbool ret = false;\r\n        root = put(root, key, value, ret);\r\n        root->color = COLOR_BLACK;\r\n        return ret;\r\n    }\r\n\r\n    // insert the key-value pair in the subtree rooted at h\r\n    Node* put(Node* h, const K& key, const V& val, bool& ret) {\r\n        if (h == nullptr) {\r\n            ret = true;\r\n            return TM::template tmNew<Node>(key, val, COLOR_RED, 1);\r\n        }\r\n        if      (key < h->key) h->left  = put(h->left,  key, val, ret);\r\n        else if (h->key < key) h->right = put(h->right, key, val, ret);\r\n        else              h->val   = val;\r\n        // fix-up any right-leaning links\r\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\r\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n\r\n        return h;\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree deletion.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Removes the smallest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMin() {\r\n        if (isEmpty()) return;\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteMin(root));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the minimum key rooted at h\r\n    Node* deleteMin(Node* h) {\r\n        if (h->left == nullptr)\r\n            return nullptr;\r\n        if (!isRed(h->left) && !isRed(h->left->left))\r\n            h = moveRedLeft(h);\r\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\r\n        return balance(h);\r\n    }\r\n\r\n\r\n    /**\r\n     * Removes the largest key and associated value from the symbol table.\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    void deleteMax() {\r\n        if (isEmpty()) return;\r\n\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right))\r\n            root->color = COLOR_RED;\r\n\r\n        root = deleteMax(root);\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the maximum key rooted at h\r\n    Node* deleteMax(Node* h) {\r\n        if (isRed(h->left))\r\n            h = rotateRight(h);\r\n\r\n        if (h->right == nullptr)\r\n            return nullptr;\r\n\r\n        if (!isRed(h->right) && !isRed(h->right->left))\r\n            h = moveRedRight(h);\r\n\r\n        h->right = deleteMax(h->right);\r\n\r\n        return balance(h);\r\n    }\r\n\r\n    /**\r\n     * Removes the specified key and its associated value from this symbol table\r\n     * (if the key is in this symbol table).\r\n     *\r\n     * @param  key the key\r\n     */\r\n    void innerRemove(K key) {\r\n        // if both children of root are black, set root to red\r\n        if (!isRed(root->left) && !isRed(root->right)) root->color = COLOR_RED;\r\n        assignAndFreeIfNull(root, deleteKey(root, key));\r\n        if (!isEmpty()) root->color = COLOR_BLACK;\r\n        // assert check();\r\n    }\r\n\r\n    // delete the key-value pair with the given key rooted at h\r\n    Node* deleteKey(Node* h, const K& key) {\r\n        // assert get(h, key) != null;\r\n        if (key < h->key)  {\r\n            if (!isRed(h->left) && !isRed(h->left->left)) {\r\n                h = moveRedLeft(h);\r\n            }\r\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\r\n        } else {\r\n            if (isRed(h->left)) {\r\n                h = rotateRight(h);\r\n            }\r\n            if (key == h->key && (h->right == nullptr)) {\r\n                return nullptr;\r\n            }\r\n            if (!isRed(h->right) && !isRed(h->right->left)) {\r\n                h = moveRedRight(h);\r\n            }\r\n            if (key == h->key) {\r\n                Node* x = min(h->right);\r\n                h->key = x->key;\r\n                h->val = x->val;\r\n                // h->val = get(h->right, min(h->right).key);\r\n                // h->key = min(h->right).key;\r\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\r\n            } else {\r\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\r\n            }\r\n        }\r\n        return balance(h);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Red-black tree helper functions.\r\n     ***************************************************************************/\r\n\r\n    // make a left-leaning link lean to the right\r\n    Node* rotateRight(Node* h) {\r\n        // assert (h != null) && isRed(h->left);\r\n        Node* x = h->left;\r\n        h->left = x->right;\r\n        x->right = h;\r\n        x->color = x->right->color;\r\n        x->right->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // make a right-leaning link lean to the left\r\n    Node* rotateLeft(Node* h) {\r\n        // assert (h != null) && isRed(h->right);\r\n        Node* x = h->right;\r\n        h->right = x->left;\r\n        x->left = h;\r\n        x->color = x->left->color;\r\n        x->left->color = COLOR_RED;\r\n        x->size = h->size;\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return x;\r\n    }\r\n\r\n    // flip the colors of a node and its two children\r\n    void flipColors(Node* h) {\r\n        // h must have opposite color of its two children\r\n        // assert (h != null) && (h->left != null) && (h->right != null);\r\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\r\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\r\n        h->color = !h->color;\r\n        h->left->color = !h->left->color;\r\n        h->right->color = !h->right->color;\r\n    }\r\n\r\n    // Assuming that h is red and both h->left and h->left.left\r\n    // are black, make h->left or one of its children red.\r\n    Node* moveRedLeft(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\r\n\r\n        flipColors(h);\r\n        if (isRed(h->right->left)) {\r\n            h->right = rotateRight(h->right);\r\n            h = rotateLeft(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // Assuming that h is red and both h->right and h->right.left\r\n    // are black, make h->right or one of its children red.\r\n    Node* moveRedRight(Node* h) {\r\n        // assert (h != null);\r\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\r\n        flipColors(h);\r\n        if (isRed(h->left->left)) {\r\n            h = rotateRight(h);\r\n            flipColors(h);\r\n        }\r\n        return h;\r\n    }\r\n\r\n    // restore red-black tree invariant\r\n    Node* balance(Node* h) {\r\n        // assert (h != null);\r\n\r\n        if (isRed(h->right))                        h = rotateLeft(h);\r\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\r\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\r\n\r\n        h->size = size(h->left) + size(h->right) + 1;\r\n        return h;\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Utility functions.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the height of the BST (for debugging).\r\n     * @return the height of the BST (a 1-node tree has height 0)\r\n     */\r\n    int height() {\r\n        return height(root);\r\n    }\r\n    int height(Node* x) {\r\n        if (x == nullptr) return -1;\r\n        return 1 + std::max(height(x->left), height(x->right));\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Ordered symbol table methods.\r\n     ***************************************************************************/\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table.\r\n     * @return the smallest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* min() {\r\n        if (isEmpty()) return nullptr;\r\n        return min(root).key;\r\n    }\r\n\r\n    // the smallest key in subtree rooted at x; null if no such key\r\n    Node* min(Node* x) {\r\n        // assert x != null;\r\n        if (x->left == nullptr) return x;\r\n        else                return min(x->left);\r\n    }\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table.\r\n     * @return the largest key in the symbol table\r\n     * @throws NoSuchElementException if the symbol table is empty\r\n     */\r\n    K* max() {\r\n        if (isEmpty()) return nullptr;\r\n        return max(root).key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x; null if no such key\r\n    Node* max(Node* x) {\r\n        // assert x != null;\r\n        if (x->right == nullptr) return x;\r\n        else                 return max(x->right);\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the largest key in the symbol table less than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* floor(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = floor(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the largest key in the subtree rooted at x less than or equal to the given key\r\n    Node* floor(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (key < x->key)  return floor(x->left, key);\r\n        Node* t = floor(x->right, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\r\n     * @param key the key\r\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\r\n     * @throws NoSuchElementException if there is no such key\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    K* ceiling(const K& key) {\r\n        if (key == nullptr) return nullptr;\r\n        if (isEmpty()) return nullptr;\r\n        Node* x = ceiling(root, key);\r\n        if (x == nullptr) return nullptr;\r\n        else           return x->key;\r\n    }\r\n\r\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\r\n    Node* ceiling(Node* x, const K& key) {\r\n        if (x == nullptr) return nullptr;\r\n        if (key == x->key) return x;\r\n        if (x->key < key)  return ceiling(x->right, key);\r\n        Node* t = ceiling(x->left, key);\r\n        if (t != nullptr) return t;\r\n        else           return x;\r\n    }\r\n\r\n    /**\r\n     * Return the kth smallest key in the symbol table.\r\n     * @param k the order statistic\r\n     * @return the {@code k}th smallest key in the symbol table\r\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\r\n     *     <em>n</em>1\r\n     */\r\n    K* select(int k) {\r\n        if (k < 0 || k >= size()) {\r\n            return nullptr;\r\n        }\r\n        Node x = select(root, k);\r\n        return x->key;\r\n    }\r\n\r\n    // the key of rank k in the subtree rooted at x\r\n    Node* select(Node* x, int k) {\r\n        // assert x != null;\r\n        // assert k >= 0 && k < size(x);\r\n        int t = size(x->left);\r\n        if      (t > k) return select(x->left,  k);\r\n        else if (t < k) return select(x->right, k-t-1);\r\n        else            return x;\r\n    }\r\n\r\n    /**\r\n     * Return the number of keys in the symbol table strictly less than {@code key}.\r\n     * @param key the key\r\n     * @return the number of keys in the symbol table strictly less than {@code key}\r\n     * @throws IllegalArgumentException if {@code key} is {@code null}\r\n     */\r\n    int rank(const K& key) {\r\n        if (key == nullptr) return -1;\r\n        return rank(key, root);\r\n    }\r\n\r\n    // number of keys less than key in the subtree rooted at x\r\n    int rank(const K& key, Node* x) {\r\n        if (x == nullptr) return 0;\r\n        if      (key < x->key) return rank(key, x->left);\r\n        else if (x->key < key) return 1 + size(x->left) + rank(key, x->right);\r\n        else              return size(x->left);\r\n    }\r\n\r\n    /***************************************************************************\r\n     *  Range count and range search->\r\n     ***************************************************************************/\r\n\r\n\r\n    /**\r\n     * Returns the number of keys in the symbol table in the given range.\r\n     *\r\n     * @param  lo minimum endpoint\r\n     * @param  hi maximum endpoint\r\n     * @return the number of keys in the sybol table between {@code lo}\r\n     *    (inclusive) and {@code hi} (inclusive)\r\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\r\n     *    is {@code null}\r\n     */\r\n    int size(const K& lo, const K& hi) {\r\n        if (lo == nullptr) return 0;\r\n        if (hi == nullptr) return 0;\r\n\r\n        if (hi < lo) return 0;\r\n        if (containsKey(hi)) return rank(hi) - rank(lo) + 1;\r\n        else              return rank(hi) - rank(lo);\r\n    }\r\n\r\n\r\n    /***************************************************************************\r\n     *  Check integrity of red-black tree data structure.\r\n     ***************************************************************************/\r\n    bool check() {\r\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\r\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\r\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\r\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\r\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\r\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\r\n    }\r\n\r\n    // does this binary tree satisfy symmetric order?\r\n    // Note: this test also ensures that data structure is a binary tree since order is strict\r\n    bool isBST() {\r\n        return isBST(root, nullptr, nullptr);\r\n    }\r\n\r\n    // is the tree rooted at x a BST with all keys strictly between min and max\r\n    // (if min or max is null, treat as empty constraint)\r\n    // Credit: Bob Dondero's elegant solution\r\n    bool isBST(Node* x, K* min, K* max) {\r\n        if (x == nullptr) return true;\r\n        // TODO: port these two lines\r\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\r\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\r\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\r\n    }\r\n\r\n    // are the size fields correct?\r\n    bool isSizeConsistent() { return isSizeConsistent(root); }\r\n    bool isSizeConsistent(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\r\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\r\n    }\r\n\r\n    /*\r\n    // check that ranks are consistent\r\n    bool isRankConsistent() {\r\n        for (int i = 0; i < size(); i++)\r\n            if (i != rank(select(i))) return false;\r\n        for (K* key : keys())\r\n            if (key.compareTo(select(rank(key))) != 0) return false;\r\n        return true;\r\n    }\r\n    */\r\n\r\n    // Does the tree have no red right links, and at most one (left)\r\n    // red links in a row on any path?\r\n    bool is23() { return is23(root); }\r\n    bool is23(Node* x) {\r\n        if (x == nullptr) return true;\r\n        if (isRed(x->right)) return false;\r\n        if (x != root && isRed(x) && isRed(x->left))\r\n            return false;\r\n        return is23(x->left) && is23(x->right);\r\n    }\r\n\r\n    // do all paths from root to leaf have same number of black edges?\r\n    bool isBalanced() {\r\n        int black = 0;     // number of black links on path from root to min\r\n        Node x = root;\r\n        while (x != nullptr) {\r\n            if (!isRed(x)) black++;\r\n            x = x->left;\r\n        }\r\n        return isBalanced(root, black);\r\n    }\r\n\r\n    // does every path from the root to a leaf have the given number of black links?\r\n    bool isBalanced(Node* x, int black) {\r\n        if (x == nullptr) return black == 0;\r\n        if (!isRed(x)) black--;\r\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\r\n    }\r\n\r\n\r\n\r\n    // Inserts a key only if it's not already present\r\n    bool add(K key, const int tid=0) {\r\n        return TM::template updateTx<bool>([=] () {\r\n            return innerPut(key,key);\r\n        });\r\n    }\r\n\r\n    // Returns true only if the key was present\r\n    bool remove(K key, const int tid=0) {\r\n        return TM::template updateTx<bool>([=] () {\r\n            V notused;\r\n            bool retval = innerGet(key,notused,false);\r\n            if (retval) innerRemove(key);\r\n            return retval;\r\n        });\r\n    }\r\n\r\n    bool contains(K key, const int tid=0) {\r\n        return TM::template readTx<bool>([=] () {\r\n            V notused;\r\n            return innerGet(key,notused,false);\r\n        });\r\n    }\r\n\r\n    void addAll(K** keys, int size, const int tid=0) {\r\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\r\n    }\r\n\r\n    static std::string className() { return TM::className() + \"-RedBlackTree\"; }\r\n\r\n};\r\n\r\n#endif   // _PERSISTENT_TM_RED_BLACK_BST_H_\r\n"
  },
  {
    "path": "pdatastructures/TMRedBlackTreeByRef.hpp",
    "content": "#ifndef _PERSISTENT_TM_RED_BLACK_TREEBYREF_H_\n#define _PERSISTENT_TM_RED_BLACK_TREEBYREF_H_\n\n#include <cassert>\n#include <stdexcept>\n#include <algorithm>\n\n\n// Adapted from Java to C++ from the original at http://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/RedBlackBST.java\ntemplate<typename K, typename V, typename TM, template <typename> class TMTYPE>\nclass TMRedBlackTreeByRef {\n    const int64_t COLOR_RED   = 0;\n    const int64_t COLOR_BLACK = 1;\n\n    struct Node {\n        TMTYPE<K>       key;\n        TMTYPE<V>       val;\n        TMTYPE<Node*>   left {nullptr};\n        TMTYPE<Node*>   right {nullptr};\n        TMTYPE<int64_t> color;    // color of parent link\n        TMTYPE<int64_t> size;     // subtree count\n        Node(const K& key, const V& val, int64_t color, int64_t size) : key{key}, val{val}, color{color}, size{size} {}\n        Node() {}\n    };\n\n    TMTYPE<Node*> root {nullptr};   // root of the BST\n\n    inline void assignAndFreeIfNull(TMTYPE<Node*>& z, Node* w) {\n        Node* tofree = z;\n        z = w;\n        if (w == nullptr) TM::tmDelete(tofree);\n    }\n\npublic:\n    /**\n     * Initializes an empty symbol table.\n     */\n    TMRedBlackTreeByRef(int numThreads=0){ }\n\n    ~TMRedBlackTreeByRef() {\n        // The transaction log is not enough to delete everything if there are too many, so we delete 1000 per transaction\n        for (int i = 0; i < 1000; i++) {\n            TM::template updateTx([=] () {\n                if (root == nullptr) return;\n                deleteMin();\n            });\n        }\n    }\n\n    /***************************************************************************\n     *  Node helper methods.\n     ***************************************************************************/\n    // is node x red; false if x is null ?\n    bool isRed(Node* x) {\n        if (x == nullptr) return false;\n        return x->color == COLOR_RED;\n    }\n\n    // number of node in subtree rooted at x; 0 if x is null\n    int size(Node* x) {\n        if (x == nullptr) return 0;\n        return x->size;\n    }\n\n\n    /**\n     * Returns the number of key-value pairs in this symbol table.\n     * @return the number of key-value pairs in this symbol table\n     */\n    int size() {\n        return size(root);\n    }\n\n    /**\n     * Is this symbol table empty?\n     * @return {@code true} if this symbol table is empty and {@code false} otherwise\n     */\n    bool isEmpty() {\n        return root == nullptr;\n    }\n\n\n    /***************************************************************************\n     *  Standard BST search->\n     ***************************************************************************/\n\n    /**\n     * Returns the value associated with the given key.\n     * @param key the key\n     * @return the value associated with the given key if the key is in the symbol table\n     *     and {@code null} if the key is not in the symbol table\n     * @throws IllegalArgumentException if {@code key} is {@code null}\n     */\n    bool innerGet(K key, V& oldValue, const bool saveOldValue) {\n        bool found = get(root, key);\n        if (!found) return false;\n        //if (saveOldValue) oldValue = *val; // Copy of V\n        return true;\n    }\n\n    // value associated with the given key in subtree rooted at x; null if no such key\n    bool get(Node* x, K& key) {\n        while (x != nullptr) {\n            if      (key < x->key) x = x->left;\n            else if (x->key < key) x = x->right;\n            else              return true;\n        }\n        return false;\n    }\n\n    /**\n     * Does this symbol table contain the given key?\n     * @param key the key\n     * @return {@code true} if this symbol table contains {@code key} and\n     *     {@code false} otherwise\n     * @throws IllegalArgumentException if {@code key} is {@code null}\n     */\n    bool containsKey(const K& key) {\n        return get(key) != nullptr;\n    }\n\n    /***************************************************************************\n     *  Red-black tree insertion.\n     ***************************************************************************/\n\n    /**\n     * Inserts the specified key-value pair into the symbol table, overwriting the old\n     * value with the new value if the symbol table already contains the specified key.\n     * Deletes the specified key (and its associated value) from this symbol table\n     * if the specified value is {@code null}.\n     *\n     * @param key the key\n     * @param val the value\n     * @throws IllegalArgumentException if {@code key} is {@code null}\n     */\n    bool innerPut(const K& key, const V& value) {\n    \tbool ret = false;\n        root = put(root, key, value, ret);\n        root->color = COLOR_BLACK;\n        return ret;\n    }\n\n    // insert the key-value pair in the subtree rooted at h\n    Node* put(Node* h, const K& key, const V& val, bool& ret) {\n        if (h == nullptr) {\n            ret = true;\n            return TM::template tmNew<Node>(key, val, COLOR_RED, 1);\n            //Node* newNode = TM::template tmNew<Node>();\n            //newNode->key = key;\n            //newNode->val = val;\n            //newNode->left = nullptr;\n            //newNode->right = nullptr;\n            //newNode->color = COLOR_RED;\n            //newNode->size = 1;\n            //return newNode;\n        }\n        if      (key < h->key) h->left  = put(h->left,  key, val, ret);\n        else if (h->key < key) h->right = put(h->right, key, val, ret);\n        else              h->val   = val;\n        // fix-up any right-leaning links\n        if (isRed(h->right) && !isRed(h->left))       h = rotateLeft(h);\n        if (isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);\n        if (isRed(h->left)  &&  isRed(h->right))      flipColors(h);\n        h->size = size(h->left) + size(h->right) + 1;\n\n        return h;\n    }\n\n    /***************************************************************************\n     *  Red-black tree deletion.\n     ***************************************************************************/\n\n    /**\n     * Removes the smallest key and associated value from the symbol table.\n     * @throws NoSuchElementException if the symbol table is empty\n     */\n    void deleteMin() {\n        if (isEmpty()) return;\n        // if both children of root are black, set root to red\n        if (!isRed(root->left) && !isRed(root->right))\n            root->color = COLOR_RED;\n        assignAndFreeIfNull(root, deleteMin(root));\n        if (!isEmpty()) root->color = COLOR_BLACK;\n        // assert check();\n    }\n\n    // delete the key-value pair with the minimum key rooted at h\n    Node* deleteMin(Node* h) {\n        if (h->left == nullptr)\n            return nullptr;\n        if (!isRed(h->left) && !isRed(h->left->left))\n            h = moveRedLeft(h);\n        assignAndFreeIfNull(h->left, deleteMin(h->left));\n        return balance(h);\n    }\n\n\n    /**\n     * Removes the largest key and associated value from the symbol table.\n     * @throws NoSuchElementException if the symbol table is empty\n     */\n    void deleteMax() {\n        if (isEmpty()) return;\n\n        // if both children of root are black, set root to red\n        if (!isRed(root->left) && !isRed(root->right))\n            root->color = COLOR_RED;\n\n        root = deleteMax(root);\n        if (!isEmpty()) root->color = COLOR_BLACK;\n        // assert check();\n    }\n\n    // delete the key-value pair with the maximum key rooted at h\n    Node* deleteMax(Node* h) {\n        if (isRed(h->left))\n            h = rotateRight(h);\n\n        if (h->right == nullptr)\n            return nullptr;\n\n        if (!isRed(h->right) && !isRed(h->right->left))\n            h = moveRedRight(h);\n\n        h->right = deleteMax(h->right);\n\n        return balance(h);\n    }\n\n    /**\n     * Removes the specified key and its associated value from this symbol table\n     * (if the key is in this symbol table).\n     *\n     * @param  key the key\n     */\n    void innerRemove(K key) {\n        // if both children of root are black, set root to red\n        if (!isRed(root->left) && !isRed(root->right)) root->color = COLOR_RED;\n        assignAndFreeIfNull(root, deleteKey(root, key));\n        if (!isEmpty()) root->color = COLOR_BLACK;\n        // assert check();\n    }\n\n    // delete the key-value pair with the given key rooted at h\n    Node* deleteKey(Node* h, const K& key) {\n        // assert get(h, key) != null;\n        if (key < h->key)  {\n            if (!isRed(h->left) && !isRed(h->left->left)) {\n                h = moveRedLeft(h);\n            }\n            assignAndFreeIfNull(h->left, deleteKey(h->left, key));\n        } else {\n            if (isRed(h->left)) {\n                h = rotateRight(h);\n            }\n            if (key == h->key && (h->right == nullptr)) {\n                return nullptr;\n            }\n            if (!isRed(h->right) && !isRed(h->right->left)) {\n                h = moveRedRight(h);\n            }\n            if (key == h->key) {\n                Node* x = min(h->right);\n                h->key = x->key;\n                h->val = x->val;\n                // h->val = get(h->right, min(h->right).key);\n                // h->key = min(h->right).key;\n                assignAndFreeIfNull(h->right, deleteMin(h->right));\n            } else {\n                assignAndFreeIfNull(h->right, deleteKey(h->right, key));\n            }\n        }\n        return balance(h);\n    }\n\n    /***************************************************************************\n     *  Red-black tree helper functions.\n     ***************************************************************************/\n\n    // make a left-leaning link lean to the right\n    Node* rotateRight(Node* h) {\n        // assert (h != null) && isRed(h->left);\n        Node* x = h->left;\n        h->left = x->right;\n        x->right = h;\n        x->color = x->right->color;\n        x->right->color = COLOR_RED;\n        x->size = h->size;\n        h->size = size(h->left) + size(h->right) + 1;\n        return x;\n    }\n\n    // make a right-leaning link lean to the left\n    Node* rotateLeft(Node* h) {\n        // assert (h != null) && isRed(h->right);\n        Node* x = h->right;\n        h->right = x->left;\n        x->left = h;\n        x->color = x->left->color;\n        x->left->color = COLOR_RED;\n        x->size = h->size;\n        h->size = size(h->left) + size(h->right) + 1;\n        return x;\n    }\n\n    // flip the colors of a node and its two children\n    void flipColors(Node* h) {\n        // h must have opposite color of its two children\n        // assert (h != null) && (h->left != null) && (h->right != null);\n        // assert (!isRed(h) &&  isRed(h->left) &&  isRed(h->right))\n        //    || (isRed(h)  && !isRed(h->left) && !isRed(h->right));\n        h->color = !h->color;\n        h->left->color = !h->left->color;\n        h->right->color = !h->right->color;\n    }\n\n    // Assuming that h is red and both h->left and h->left.left\n    // are black, make h->left or one of its children red.\n    Node* moveRedLeft(Node* h) {\n        // assert (h != null);\n        // assert isRed(h) && !isRed(h->left) && !isRed(h->left.left);\n\n        flipColors(h);\n        if (isRed(h->right->left)) {\n            h->right = rotateRight(h->right);\n            h = rotateLeft(h);\n            flipColors(h);\n        }\n        return h;\n    }\n\n    // Assuming that h is red and both h->right and h->right.left\n    // are black, make h->right or one of its children red.\n    Node* moveRedRight(Node* h) {\n        // assert (h != null);\n        // assert isRed(h) && !isRed(h->right) && !isRed(h->right.left);\n        flipColors(h);\n        if (isRed(h->left->left)) {\n            h = rotateRight(h);\n            flipColors(h);\n        }\n        return h;\n    }\n\n    // restore red-black tree invariant\n    Node* balance(Node* h) {\n        // assert (h != null);\n\n        if (isRed(h->right))                        h = rotateLeft(h);\n        if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);\n        if (isRed(h->left) && isRed(h->right))      flipColors(h);\n\n        h->size = size(h->left) + size(h->right) + 1;\n        return h;\n    }\n\n\n    /***************************************************************************\n     *  Utility functions.\n     ***************************************************************************/\n\n    /**\n     * Returns the height of the BST (for debugging).\n     * @return the height of the BST (a 1-node tree has height 0)\n     */\n    int height() {\n        return height(root);\n    }\n    int height(Node* x) {\n        if (x == nullptr) return -1;\n        return 1 + std::max(height(x->left), height(x->right));\n    }\n\n    /***************************************************************************\n     *  Ordered symbol table methods.\n     ***************************************************************************/\n\n    /**\n     * Returns the smallest key in the symbol table.\n     * @return the smallest key in the symbol table\n     * @throws NoSuchElementException if the symbol table is empty\n     */\n    K* min() {\n        if (isEmpty()) return nullptr;\n        return min(root).key;\n    }\n\n    // the smallest key in subtree rooted at x; null if no such key\n    Node* min(Node* x) {\n        // assert x != null;\n        if (x->left == nullptr) return x;\n        else                return min(x->left);\n    }\n\n    /**\n     * Returns the largest key in the symbol table.\n     * @return the largest key in the symbol table\n     * @throws NoSuchElementException if the symbol table is empty\n     */\n    K* max() {\n        if (isEmpty()) return nullptr;\n        return max(root).key;\n    }\n\n    // the largest key in the subtree rooted at x; null if no such key\n    Node* max(Node* x) {\n        // assert x != null;\n        if (x->right == nullptr) return x;\n        else                 return max(x->right);\n    }\n\n\n    /**\n     * Returns the largest key in the symbol table less than or equal to {@code key}.\n     * @param key the key\n     * @return the largest key in the symbol table less than or equal to {@code key}\n     * @throws NoSuchElementException if there is no such key\n     * @throws IllegalArgumentException if {@code key} is {@code null}\n     */\n    K* floor(const K& key) {\n        if (key == nullptr) return nullptr;\n        if (isEmpty()) return nullptr;\n        Node* x = floor(root, key);\n        if (x == nullptr) return nullptr;\n        else           return x->key;\n    }\n\n    // the largest key in the subtree rooted at x less than or equal to the given key\n    Node* floor(Node* x, const K& key) {\n        if (x == nullptr) return nullptr;\n        if (key == x->key) return x;\n        if (key < x->key)  return floor(x->left, key);\n        Node* t = floor(x->right, key);\n        if (t != nullptr) return t;\n        else           return x;\n    }\n\n    /**\n     * Returns the smallest key in the symbol table greater than or equal to {@code key}.\n     * @param key the key\n     * @return the smallest key in the symbol table greater than or equal to {@code key}\n     * @throws NoSuchElementException if there is no such key\n     * @throws IllegalArgumentException if {@code key} is {@code null}\n     */\n    K* ceiling(const K& key) {\n        if (key == nullptr) return nullptr;\n        if (isEmpty()) return nullptr;\n        Node* x = ceiling(root, key);\n        if (x == nullptr) return nullptr;\n        else           return x->key;\n    }\n\n    // the smallest key in the subtree rooted at x greater than or equal to the given key\n    Node* ceiling(Node* x, const K& key) {\n        if (x == nullptr) return nullptr;\n        if (key == x->key) return x;\n        if (x->key < key)  return ceiling(x->right, key);\n        Node* t = ceiling(x->left, key);\n        if (t != nullptr) return t;\n        else           return x;\n    }\n\n    /**\n     * Return the kth smallest key in the symbol table.\n     * @param k the order statistic\n     * @return the {@code k}th smallest key in the symbol table\n     * @throws IllegalArgumentException unless {@code k} is between 0 and\n     *     <em>n</em>1\n     */\n    K* select(int k) {\n        if (k < 0 || k >= size()) {\n            return nullptr;\n        }\n        Node x = select(root, k);\n        return x->key;\n    }\n\n    // the key of rank k in the subtree rooted at x\n    Node* select(Node* x, int k) {\n        // assert x != null;\n        // assert k >= 0 && k < size(x);\n        int t = size(x->left);\n        if      (t > k) return select(x->left,  k);\n        else if (t < k) return select(x->right, k-t-1);\n        else            return x;\n    }\n\n    /**\n     * Return the number of keys in the symbol table strictly less than {@code key}.\n     * @param key the key\n     * @return the number of keys in the symbol table strictly less than {@code key}\n     * @throws IllegalArgumentException if {@code key} is {@code null}\n     */\n    int rank(const K& key) {\n        if (key == nullptr) return -1;\n        return rank(key, root);\n    }\n\n    // number of keys less than key in the subtree rooted at x\n    int rank(const K& key, Node* x) {\n        if (x == nullptr) return 0;\n        if      (key < x->key) return rank(key, x->left);\n        else if (x->key < key) return 1 + size(x->left) + rank(key, x->right);\n        else              return size(x->left);\n    }\n\n    /***************************************************************************\n     *  Range count and range search->\n     ***************************************************************************/\n\n\n    /**\n     * Returns the number of keys in the symbol table in the given range.\n     *\n     * @param  lo minimum endpoint\n     * @param  hi maximum endpoint\n     * @return the number of keys in the sybol table between {@code lo}\n     *    (inclusive) and {@code hi} (inclusive)\n     * @throws IllegalArgumentException if either {@code lo} or {@code hi}\n     *    is {@code null}\n     */\n    int size(const K& lo, const K& hi) {\n        if (lo == nullptr) return 0;\n        if (hi == nullptr) return 0;\n\n        if (hi < lo) return 0;\n        if (containsKey(hi)) return rank(hi) - rank(lo) + 1;\n        else              return rank(hi) - rank(lo);\n    }\n\n\n    /***************************************************************************\n     *  Check integrity of red-black tree data structure.\n     ***************************************************************************/\n    bool check() {\n        if (!isBST())            std::cout << \"Not in symmetric order\\n\";\n        if (!isSizeConsistent()) std::cout << \"Subtree counts not consistent\\n\";\n        //if (!isRankConsistent()) std::cout << \"Ranks not consistent\\n\";\n        if (!is23())             std::cout << \"Not a 2-3 tree\\n\";\n        if (!isBalanced())       std::cout << \"Not balanced\\n\";\n        return isBST() && isSizeConsistent() && is23() && isBalanced();\n    }\n\n    // does this binary tree satisfy symmetric order?\n    // Note: this test also ensures that data structure is a binary tree since order is strict\n    bool isBST() {\n        return isBST(root, nullptr, nullptr);\n    }\n\n    // is the tree rooted at x a BST with all keys strictly between min and max\n    // (if min or max is null, treat as empty constraint)\n    // Credit: Bob Dondero's elegant solution\n    bool isBST(Node* x, K* min, K* max) {\n        if (x == nullptr) return true;\n        // TODO: port these two lines\n        //if (min != nullptr && x->key.compareTo(min) <= 0) return false;\n        //if (max != nullptr && x->key.compareTo(max) >= 0) return false;\n        return isBST(x->left, min, x->key) && isBST(x->right, x->key, max);\n    }\n\n    // are the size fields correct?\n    bool isSizeConsistent() { return isSizeConsistent(root); }\n    bool isSizeConsistent(Node* x) {\n        if (x == nullptr) return true;\n        if (x->size != size(x->left) + size(x->right) + 1) return false;\n        return isSizeConsistent(x->left) && isSizeConsistent(x->right);\n    }\n\n    /*\n    // check that ranks are consistent\n    bool isRankConsistent() {\n        for (int i = 0; i < size(); i++)\n            if (i != rank(select(i))) return false;\n        for (K* key : keys())\n            if (key.compareTo(select(rank(key))) != 0) return false;\n        return true;\n    }\n    */\n\n    // Does the tree have no red right links, and at most one (left)\n    // red links in a row on any path?\n    bool is23() { return is23(root); }\n    bool is23(Node* x) {\n        if (x == nullptr) return true;\n        if (isRed(x->right)) return false;\n        if (x != root && isRed(x) && isRed(x->left))\n            return false;\n        return is23(x->left) && is23(x->right);\n    }\n\n    // do all paths from root to leaf have same number of black edges?\n    bool isBalanced() {\n        int black = 0;     // number of black links on path from root to min\n        Node x = root;\n        while (x != nullptr) {\n            if (!isRed(x)) black++;\n            x = x->left;\n        }\n        return isBalanced(root, black);\n    }\n\n    // does every path from the root to a leaf have the given number of black links?\n    bool isBalanced(Node* x, int black) {\n        if (x == nullptr) return black == 0;\n        if (!isRed(x)) black--;\n        return isBalanced(x->left, black) && isBalanced(x->right, black);\n    }\n\n\n\n    // Inserts a key only if it's not already present\n    bool add(K key, const int tid=0) {\n        bool retval = false;\n        TM::template updateTx<bool>([&] () {\n        \tretval = innerPut(key,key);\n        });\n        return retval;\n    }\n\n    // Returns true only if the key was present\n    bool remove(K key, const int tid=0) {\n        bool retval = false;\n        TM::template updateTx<bool>([&] () {\n            V notused;\n            retval = innerGet(key,notused,false);\n            if (retval) innerRemove(key);\n        });\n        return retval;\n    }\n\n    bool contains(K key, const int tid=0) {\n        bool retval = false;\n        TM::template readTx<bool>([&] () {\n            V notused;\n            retval = innerGet(key,notused,false);\n        });\n        return retval;\n    }\n\n    void addAll(K** keys, int size, const int tid=0) {\n        for (int i = 0; i < size; i++) add(*keys[i], tid);\n    }\n\n    static std::string className() { return TM::className() + \"-RedBlackTree\"; }\n\n};\n\n#endif   // _PERSISTENT_TM_RED_BLACK_TREEBYREF_H_\n"
  },
  {
    "path": "pdatastructures/pqueues/HazardPointers.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _HAZARD_POINTERS_H_\r\n#define _HAZARD_POINTERS_H_\r\n\r\n#include <atomic>\r\n#include <iostream>\r\n#include <functional>\r\n#include <vector>\r\n\r\n\r\ntemplate<typename T>\r\nclass HazardPointers {\r\n\r\nprivate:\r\n    static const int      HP_MAX_THREADS = 128;\r\n    static const int      HP_MAX_HPS = 128;     // This is named 'K' in the HP paper\r\n    static const int      CLPAD = 128/sizeof(std::atomic<T*>);\r\n    static const int      HP_THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    static const int      MAX_RETIRED = HP_MAX_THREADS*HP_MAX_HPS; // Maximum number of retired objects per thread\r\n\r\n    const int             maxHPs;\r\n    const int             maxThreads;\r\n\r\n    alignas(128) std::atomic<T*>*      hp[HP_MAX_THREADS];\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<T*>       retiredList[HP_MAX_THREADS*CLPAD];\r\n    std::function<void(T*,int)> defdeleter = [](T* t, int tid){ delete t; };\r\n    std::function<void(T*,int)>& deleter;\r\npublic:\r\n\r\n    HazardPointers(int maxHPs, int maxThreads) : maxHPs{maxHPs}, maxThreads{maxThreads}, deleter{defdeleter} {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            hp[ithread] = new std::atomic<T*>[HP_MAX_HPS];\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[ithread][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    HazardPointers(int maxHPs, int maxThreads, std::function<void(T*,int)>& deleter) : maxHPs{maxHPs}, maxThreads{maxThreads}, deleter{deleter} {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            hp[ithread] = new std::atomic<T*>[HP_MAX_HPS];\r\n            for (int ihp = 0; ihp < HP_MAX_HPS; ihp++) {\r\n                hp[ithread][ihp].store(nullptr, std::memory_order_relaxed);\r\n            }\r\n        }\r\n    }\r\n\r\n    ~HazardPointers() {\r\n        for (int ithread = 0; ithread < HP_MAX_THREADS; ithread++) {\r\n            delete[] hp[ithread];\r\n            // Clear the current retired nodes\r\n            for (unsigned iret = 0; iret < retiredList[ithread*CLPAD].size(); iret++) {\r\n                delete retiredList[ithread*CLPAD][iret];\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by maxHPs)\r\n     */\r\n    void clear(const int tid) {\r\n        for (int ihp = 0; ihp < maxHPs; ihp++) {\r\n            hp[tid][ihp].store(nullptr, std::memory_order_release);\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    void clearOne(int ihp, const int tid) {\r\n        hp[tid][ihp].store(nullptr, std::memory_order_release);\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: lock-free\r\n     */\r\n    T* protect(int index, const std::atomic<T*>& atom, const int tid) {\r\n        T* n = nullptr;\r\n        T* ret;\r\n\t\twhile ((ret = atom.load()) != n) {\r\n\t\t\thp[tid][index].store(ret);\r\n\t\t\tn = ret;\r\n\t\t}\r\n\t\treturn ret;\r\n    }\r\n\r\n    T* get(int index, const int tid){\r\n        return hp[tid][index].load();\r\n    }\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtr(int index, T* ptr, const int tid) {\r\n        hp[tid][index].store(ptr);\r\n        return ptr;\r\n    }\r\n\r\n\r\n\r\n    /**\r\n     * This returns the same value that is passed as ptr, which is sometimes useful\r\n     * Progress Condition: wait-free population oblivious\r\n     */\r\n    T* protectPtrRelease(int index, T* ptr, const int tid) {\r\n        hp[tid][index].store(ptr, std::memory_order_release);\r\n        return ptr;\r\n    }\r\n\r\n\r\n    /**\r\n     * Progress Condition: wait-free bounded (by the number of threads squared)\r\n     */\r\n    void retire(T* ptr, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(ptr);\r\n        if (retiredList[tid*CLPAD].size() < HP_THRESHOLD_R) return;\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            auto obj = retiredList[tid*CLPAD][iret];\r\n            bool canDelete = true;\r\n            for (int tid = 0; tid < maxThreads && canDelete; tid++) {\r\n                for (int ihp = maxHPs-1; ihp >= 0; ihp--) {\r\n                    if (hp[tid][ihp].load() == obj) {\r\n                        canDelete = false;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            if (canDelete) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                deleter(obj,tid);\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _HAZARD_POINTERS_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/MichaelScottQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _MICHAEL_SCOTT_QUEUE_HP_H_\r\n#define _MICHAEL_SCOTT_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"HazardPointers.hpp\"\r\n\r\n\r\n/**\r\n * <h1> Michael-Scott Queue </h1>\r\n *\r\n * enqueue algorithm: MS enqueue\r\n * dequeue algorithm: MS dequeue\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Pointers (lock-free)\r\n *\r\n *\r\n * Maged Michael and Michael Scott's Queue with Hazard Pointers\r\n * <p>\r\n * Lock-Free Linked List as described in Maged Michael and Michael Scott's paper:\r\n * {@link http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf}\r\n * <a href=\"http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf\">\r\n * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms</a>\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n */\r\ntemplate<typename T>\r\nclass MichaelScottQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        T item;\r\n        std::atomic<Node*> next;\r\n\r\n        Node(T userItem) : item{userItem}, next{nullptr} { }\r\n\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    bool casTail(Node *cmp, Node *val) {\r\n\t\treturn tail.compare_exchange_strong(cmp, val);\r\n\t}\r\n\r\n    bool casHead(Node *cmp, Node *val) {\r\n        return head.compare_exchange_strong(cmp, val);\r\n    }\r\n\r\n    // Pointers to head and tail of the list\r\n    alignas(128) std::atomic<Node*> head;\r\n    alignas(128) std::atomic<Node*> tail;\r\n\r\n    static const int MAX_THREADS = 128;\r\n    const int maxThreads;\r\n\r\n    // We need two hazard pointers for dequeue()\r\n    HazardPointers<Node> hp {2, maxThreads};\r\n    const int kHpTail = 0;\r\n    const int kHpHead = 0;\r\n    const int kHpNext = 1;\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    MichaelScottQueue(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        Node* sentinelNode = new Node(EMPTY);\r\n        head.store(sentinelNode, std::memory_order_relaxed);\r\n        tail.store(sentinelNode, std::memory_order_relaxed);\r\n    }\r\n\r\n\r\n    ~MichaelScottQueue() {\r\n        while (dequeue(0) != EMPTY);   // Drain the queue\r\n        delete head.load();            // Delete the last node\r\n    }\r\n\r\n    static std::string className() { return \"MichaelScottQueue\"; }\r\n\r\n    void enqueue(T item, const int tid) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        Node* newNode = new Node(item);\r\n        while (true) {\r\n            Node* ltail = hp.protectPtr(kHpTail, tail, tid);\r\n            if (ltail == tail.load()) {\r\n                Node* lnext = ltail->next.load();\r\n                if (lnext == nullptr) {\r\n                    // It seems this is the last node, so add the newNode here\r\n                    // and try to move the tail to the newNode\r\n                    if (ltail->casNext(nullptr, newNode)) {\r\n                        casTail(ltail, newNode);\r\n                        hp.clear(tid);\r\n                        return;\r\n                    }\r\n                } else {\r\n                    casTail(ltail, lnext);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    T dequeue(const int tid) {\r\n        Node* node = hp.protect(kHpHead, head, tid);\r\n        while (node != tail.load()) {\r\n            Node* lnext = hp.protect(kHpNext, node->next, tid);\r\n            if (casHead(node, lnext)) {\r\n                T item = lnext->item;  // Another thread may clean up lnext after we do hp.clear()\r\n                hp.clear(tid);\r\n                hp.retire(node, tid);\r\n                return item;\r\n            }\r\n            node = hp.protect(kHpHead, head, tid);\r\n        }\r\n        hp.clear(tid);\r\n        return EMPTY;                  // Queue is empty\r\n    }\r\n};\r\n\r\n#endif /* _MICHAEL_SCOTT_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/PFriedmanQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _PERSISTENT_FRIEDMAN_QUEUE_HP_H_\r\n#define _PERSISTENT_FRIEDMAN_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"common/pfences.h\"\r\n#include \"HazardPointers.hpp\"\r\n\r\n// Comment this define to use the system's new/delete volatile allocator\r\n//#define USE_PMDK_ALLOC\r\n\r\n#ifdef USE_PMDK_ALLOC\r\n#include <libpmemobj++/p.hpp>\r\n#include <libpmemobj++/transaction.hpp>\r\n#include <libpmemobj++/pool.hpp>\r\n#include <libpmemobj++/allocator.hpp>\r\n#include <mutex>\r\nusing namespace pmem::obj;\r\nauto gpopf = pool_base::create(\"/dev/shm/pmdk_shared_friedman\", \"\", (size_t)(800*1024*1024));\r\nstd::mutex glockf {};\r\n#endif\r\n\r\n/**\r\n * <h1> Persistent lock-free Queue </h1>\r\n *\r\n * WARNING: this doesn't do memory reclamation, which means that when we enabled PMDK as the allocator,\r\n * it blows away all the memory quickly (just 2 threads is enough).\r\n * I'm not sure how to do proper memory reclamation with this, seen as returnedValues still holds pointers to the items.\r\n * I guess the only way to do it is to have pointers to copy of the items, and delete/retire the old ones before overwritting.\r\n * This in turn creates more pressure on the memory allocator... ohh well.\r\n *\r\n * This is the lock-free queue shown by Michal Friedman, Maurice Herlihy, Virendra Marathe, Erez Petrank.\r\n * https://dl.acm.org/citation.cfm?id=3178490\r\n *\r\n * Consistency: Durable Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Pointers (lock-free)\r\n *\r\n * To understand what the PWB/PFENCE/PSYNC are, take a look at\r\n * \"Preserving Happens-Before in persistent memory\":\r\n * https://www.cs.rochester.edu/u/jhi1/papers/2016-spaa-transform\r\n *\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n */\r\ntemplate<typename T>\r\nclass PFriedmanQueue {\r\n\r\nprivate:\r\n    static const int MAX_THREADS = 128;\r\n\r\n    struct Node {\r\n        T                   value;\r\n        std::atomic<Node*>  next {nullptr};\r\n        std::atomic<int>    deqThreadID {-1};\r\n        Node(T item) : value{item} { }\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n        bool casDeqTID(int cmp, int val) {\r\n            return deqThreadID.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    bool casTail(Node *cmp, Node *val) {\r\n\t\treturn tail.compare_exchange_strong(cmp, val);\r\n\t}\r\n\r\n    bool casHead(Node *cmp, Node *val) {\r\n        return head.compare_exchange_strong(cmp, val);\r\n    }\r\n\r\n    //\r\n    // Persistent variables\r\n    //\r\n\r\n    // Pointers to head and tail of the list\r\n    alignas(128) std::atomic<Node*> head {nullptr};\r\n    alignas(128) std::atomic<Node*> tail {nullptr};\r\n    alignas(128) std::atomic<T*> returnedValues[MAX_THREADS];\r\n\r\n\r\n    // Set to true when the constructor completed sucessfully\r\n    bool constructorInProgress = true;\r\n    // Will be set to true when the destructor is called, in case there is a crash during destructor\r\n    bool destructorInProgress = false;\r\n    const int maxThreads;\r\n\r\n    template<typename TN>\r\n    static void internalDelete(TN* obj) {\r\n#ifdef USE_PMDK_ALLOC\r\n        if (obj == nullptr) return;\r\n        obj->~TN();\r\n        glockf.lock();\r\n        transaction::exec_tx(gpopf, [obj] () {\r\n            pmemobj_tx_free(pmemobj_oid(obj));\r\n        });\r\n        glockf.unlock();\r\n#else\r\n        delete obj;\r\n#endif\r\n    }\r\n\r\n    template<typename TN, typename... Args>\r\n    static TN* internalNew(Args&&... args) {\r\n#ifdef USE_PMDK_ALLOC\r\n        glockf.lock();\r\n        void *addr = nullptr;\r\n        transaction::exec_tx(gpopf, [&addr] () {\r\n            auto oid = pmemobj_tx_alloc(sizeof(TN), 0);\r\n            addr = pmemobj_direct(oid);\r\n        });\r\n        glockf.unlock();\r\n        return new (addr) TN(std::forward<Args>(args)...); // placement new\r\n#else\r\n        return new TN(std::forward<Args>(args)...);\r\n#endif\r\n    }\r\n\r\n    std::function<void(Node*,int)> mydeleter = [](Node* node, int tid){ internalDelete(node); };\r\n\r\n    // We need two hazard pointers for dequeue()\r\n    // This variable is a non-volatile pointer to a volatile object\r\n    HazardPointers<Node>* hp  = new HazardPointers<Node>{2, maxThreads,mydeleter};\r\n    static const int kHpTail = 0;\r\n    static const int kHpHead = 0;\r\n    static const int kHpNext = 1;\r\n\r\n\r\n    /*\r\n     * To be called when restarting after a failure\r\n     * We tried to follow the description in section 5.3 of the paper as much as possible\r\n     */\r\n    void recover() {\r\n        // TODO: not yet implemented...\r\n        if (destructorInProgress) {\r\n            if (head.load(std::memory_order_relaxed) != nullptr) {\r\n                while (dequeue(0) != EMPTY); // Drain the queue\r\n                head.store(nullptr, std::memory_order_relaxed);\r\n                PWB(&head);\r\n                PFENCE();\r\n                internalDelete(head.load(std::memory_order_relaxed));  // Delete the last node\r\n            }\r\n            PSYNC();\r\n            delete hp;\r\n            return;\r\n        }\r\n        hp = new HazardPointers<Node>{2, maxThreads,mydeleter};\r\n\r\n        // TODO: place recovery of head and recovery of tail here...\r\n\r\n\r\n        // If both head is null then a failure occurred during constructor\r\n        if (head.load(std::memory_order_relaxed) == nullptr) {\r\n            Node* sentinelNode = internalNew<Node>(T{});\r\n            head.store(sentinelNode, std::memory_order_relaxed);\r\n            PWB(&head);\r\n            PFENCE();\r\n        }\r\n        // If tail is null, then fix it by setting it to head\r\n        if (tail.load(std::memory_order_relaxed) == nullptr) {\r\n            tail.store(head.load(std::memory_order_relaxed), std::memory_order_relaxed);\r\n            PWB(&tail);\r\n            PFENCE();\r\n        }\r\n        // Advance the tail if needed\r\n        Node* ltail = tail.load(std::memory_order_relaxed);\r\n        Node* lnext = ltail->next.load(std::memory_order_relaxed);\r\n        if (lnext != nullptr) {\r\n            tail.store(lnext, std::memory_order_relaxed);\r\n            PWB(&tail);\r\n        }\r\n        PSYNC();\r\n    }\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    // This is \"DurableQueue()\" of Figure 1 of the paper.\r\n    // Unfortunately, this code is incorrect without some kind of \"validation\" flag, so we added it\r\n    PFriedmanQueue(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        if (!constructorInProgress) return;\r\n        Node* node = internalNew<Node>(T{});\r\n        PWB(node); // We're assuming this flushes the whole node\r\n        PFENCE();\r\n        head = node;\r\n        PWB(&head);\r\n        PFENCE();\r\n        tail = node;\r\n        PWB(&tail);\r\n        PFENCE();\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            returnedValues[i].store(nullptr, std::memory_order_release);\r\n            PWB(&returnedValues[i]);\r\n            PFENCE();\r\n        }\r\n        constructorInProgress = false;\r\n        PWB(&constructorInProgress);\r\n        PFENCE();\r\n    }\r\n\r\n    // There is no destructor in the original code, therefore we had to make one\r\n    ~PFriedmanQueue() {\r\n        destructorInProgress = true;\r\n        PWB(&destructorInProgress);\r\n        PFENCE();\r\n        recover();  // Re-using the same code from the recovery method\r\n    }\r\n\r\n    static std::string className() { return \"PFriedmanQueue\"; }\r\n\r\n    /*\r\n     * Code taken from enq() in figure 2 of the paper.\r\n     * Progress: lock-free\r\n     * Uncontended: 2 PWB, 2 PFENCE, 2 CAS,\r\n     */\r\n    void enqueue(T item, const int tid) {\r\n        Node* node = internalNew<Node>(item);\r\n        PWB(&node->value); // We flush multiple variables, just in case they are not on the same cache line\r\n        PWB(&node->next);\r\n        PFENCE();             // This isn't really needed, but it's in the paper so we leave it\r\n        while (true) {\r\n            Node* last = hp->protectPtr(kHpTail, tail, tid);\r\n            if (last == tail.load()) {\r\n                Node* next = last->next.load();\r\n                if (next == nullptr) {\r\n                    if (last->casNext(nullptr, node)) {\r\n                        PWB(&last->next);\r\n                        PSYNC(); // This isn't really needed because of the following CAS, but it's in the paper\r\n                        casTail(last, node);\r\n                        hp->clear(tid);\r\n                        return;\r\n                    }\r\n                } else {\r\n                    PWB(&last->next);\r\n                    PSYNC(); // This isn't really needed because of the following CAS, but it's in the paper\r\n                    casTail(last, next);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /*\r\n     * Code taken from deq() in figure 3 of the paper.\r\n     * Progress: lock-free\r\n     * Uncontended: 4 PWB, 4 PFENCE, 2 CAS, 1 MFENCE (for the seq-cst store in returnedValues[tid])\r\n     */\r\n    T dequeue(const int tid) {\r\n        T* newReturnedValue = internalNew<T>();\r\n        PWB(newReturnedValue); // Flush the contents of T. We're assuming T is on the same cache line\r\n        PFENCE();\r\n        returnedValues[tid] = newReturnedValue;\r\n        PWB(&returnedValues[tid]);\r\n        PFENCE();\r\n        while (true) {\r\n            Node* first = hp->protectPtr(kHpHead, head, tid);\r\n            Node* last = tail;\r\n            if (first == head) {\r\n                Node* next = first->next.load();\r\n                if (first == last) {\r\n                    if (next == nullptr) {\r\n                        *returnedValues[tid] = EMPTY;\r\n                        PWB(returnedValues[tid].load());\r\n                        PSYNC();\r\n                        hp->clear(tid);\r\n                        return EMPTY;\r\n                    }\r\n                    PWB(&last->next);\r\n                    PFENCE();\r\n                    casTail(last, next);\r\n                } else {\r\n                    T value = next->value;\r\n                    if (next->casDeqTID(-1, tid)) {\r\n                        PWB(&(first->next.load()->deqThreadID));\r\n                        PFENCE();\r\n                        *returnedValues[tid] = value;\r\n                        PWB(returnedValues[tid].load());\r\n                        PSYNC();\r\n                        if (casHead(first, next));// hp->retire(first, tid);\r\n                        hp->clear(tid);\r\n                        return *returnedValues[tid];\r\n                    } else {\r\n                        T* address = returnedValues[next->deqThreadID];\r\n                        if (head == first) { //same context\r\n                            PWB(&(first->next.load()->deqThreadID));\r\n                            PFENCE();\r\n                            *address = value;\r\n                            PWB(address);\r\n                            PFENCE();\r\n                            if (casHead(first, next));// hp->retire(first, tid);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_FRIEDMAN_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/PMDKLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2019\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_PMDK_LINKED_LIST_QUEUE_H_\r\n#define _PERSISTENT_PMDK_LINKED_LIST_QUEUE_H_\r\n\r\n#include <stdexcept>\r\n\r\n#include \"ptms/PMDKTM.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using PMDK PTM (blocking) </h1>\r\n */\r\ntemplate<typename T>\r\nclass PMDKLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        pmdk::persist<T> item;\r\n        pmdk::persist<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n    };\r\n\r\n    alignas(128) pmdk::persist<Node*>  head {nullptr};\r\n    alignas(128) pmdk::persist<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    PMDKLinkedListQueue(unsigned int maxThreads=0) {\r\n        pmdk::PMDKTM::updateTx([&] () {\r\n            Node* sentinelNode = pmdk::PMDKTM::tmNew<Node>(EMPTY);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n        });\r\n    }\r\n\r\n\r\n    ~PMDKLinkedListQueue() {\r\n        pmdk::PMDKTM::updateTx([&] () {\r\n            while (dequeue() != EMPTY); // Drain the queue\r\n            Node* lhead = head;\r\n            pmdk::PMDKTM::tmDelete(lhead);\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"PMDK-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T item, const int tid=0) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        pmdk::PMDKTM::updateTx([&] () {\r\n            Node* newNode = pmdk::PMDKTM::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n        });\r\n        return true;\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T dequeue(const int tid=0) {\r\n        T item = EMPTY;\r\n        pmdk::PMDKTM::updateTx<T*>([&] () {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return;\r\n            head = lhead->next;\r\n            pmdk::PMDKTM::tmDelete(lhead);\r\n            item = head->item;\r\n        });\r\n        return item;\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_ROMULUS_LOG_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/PMichaelScottQueue.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2018, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _PERSISTENT_MICHAEL_SCOTT_QUEUE_HP_H_\r\n#define _PERSISTENT_MICHAEL_SCOTT_QUEUE_HP_H_\r\n\r\n#include <atomic>\r\n#include <stdexcept>\r\n#include \"common/pfences.h\"\r\n#include \"HazardPointers.hpp\"\r\n\r\n// Comment this define to go back to using the regular new/delete volatile allocator\r\n//#define USE_PMDK_ALLOC\r\n\r\n#ifdef USE_PMDK_ALLOC\r\n#include <libpmemobj++/p.hpp>\r\n#include <libpmemobj++/transaction.hpp>\r\n#include <libpmemobj++/pool.hpp>\r\n#include <libpmemobj++/allocator.hpp>\r\n#include <mutex>\r\nusing namespace pmem::obj;\r\nauto gpop = pool_base::create(\"/dev/shm/pmdk_shared\", \"\", (size_t)(400*1024*1024));\r\nstd::mutex glock {};\r\n#endif\r\n\r\n/**\r\n * <h1> Persistent Michael-Scott Queue </h1>\r\n *\r\n * enqueue algorithm: MS enqueue + CR modifications\r\n * dequeue algorithm: MS dequeue + CR modifications\r\n * Consistency: Durable Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Pointers (lock-free)\r\n *\r\n * This Queue is a modification to persistence of the original lock-free algorithm\r\n * by Maged Michael and Michael Scott. We reduced the number of PWB() and PFENCE()\r\n * as much as possible and we've added the logic for the recovery.\r\n * The enqueue()/dequeue() methods don't need a recovery method, but the constructor\r\n * and destructor are (by definition) not lock-free and therefore need to handle\r\n * proper recovery.\r\n *\r\n * To understand what the PWB/PFENCE/PSYNC are, take a look at\r\n * \"Preserving Happens-Before in persistent memory\":\r\n * https://www.cs.rochester.edu/u/jhi1/papers/2016-spaa-transform\r\n *\r\n * We're assuming that CAS has persistent semantics similar to PFENCE() that\r\n * doesn't act on the load/store of the CAS itself, only on the other loads\r\n * and stores. In other words, it's as if a CAS is equivalent to a:\r\n *   PFENCE();\r\n *   CAS()     // concurrent\r\n *   PFENCE();\r\n * The reason we assume this, is because on x86, LOCK instructions and\r\n * read-modify-write instructions like CAS, ensure order for CLFLUSHOPT and\r\n * CLWB (PWBs). For more details see Intel's manual for CLFLUSHOPT:\r\n * https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf\r\n *\r\n * This algorithm was designed such that on enqueue(), a successful CAS on ltail->next\r\n * implies that the PWB()s for newNode->item, newNode->next and tail have been done,\r\n * and a successful CAS on tail means that the PWB() on ltail->next has been done.\r\n *\r\n * As for the PWB() and PSYNC() before returning, they're not always needed but\r\n * it helps to reason about in terms of composability.\r\n * The only way to observe effects from this queue is to call enqueue() or\r\n * dequeue(), therefore, the next call to the same method will flush the cache\r\n * line and persist it.\r\n * However, if you want to do something like:\r\n *   q.enqueue(a);\r\n *   a_is_persisted = true;\r\n *   PWB(&a_is_persisted);\r\n * then the only way to guarantee correct ordering, is to have the PWB() and\r\n * a PSYNC() or PFENCE() before returning from enqueue()/dequeue().\r\n *\r\n * Related to the above, there is a trick on enqueue(). Instead of adding the\r\n * PWB(&tail) and PSYNC(), we don't do that thanks to happens-before relations.\r\n * Namely, for enqueue() to return it means the CAS on tail has been done, and\r\n * although the value of tail may not be persisted, the CAS on tail guarantees\r\n * that the value of the node->next is persisted. This means that if a crash\r\n * occurs and even if a_is_persisted is persisted and the change to tail occurring\r\n * on the enqueue does not, it's still ok because the node->next is persisted\r\n * which will allow the recover() of the queue to advance the tail and persist\r\n * it as well.\r\n * Unfortunately, for the dequeue(), no such trick is possible on the head,\r\n * therefore, we really do need the PWB(&head) and PSYNC() before returning\r\n * from dequeue().\r\n *\r\n * About the constructor:\r\n * As long as the allocator returns a zeroed-out memory region, the 'head' and\r\n * 'tail' will be nullptr even if there is a crash immediately at the start of\r\n * the call to the constructor. If the allocator can't guarantee that the data\r\n * is zero-ed out, then there is no 100% safe way to distinguish between a\r\n * proper initialization and trash immediately after* allocating the queue.\r\n * A crash occurring after the 'head' and 'tail' are made persistent (with nullptr)\r\n *is always recoverable, although there are a few different cases:\r\n * - If the head is nullptr then the sentinel node must be allocated;\r\n * - If the head is non-null but tail is null, then the sentinel was allocated\r\n *   and assigned to head but not to tail;\r\n * - If both head and tail are non-null and tail->next is non-null then tail is\r\n *   not pointing to the last node and we need to advance tail;\r\n *\r\n * About the destructor:\r\n * The destructor must first drain the queue to avoid leaking as much as possible.\r\n * Then, it needs to de-allocate the last node and zero-out the head to make\r\n * sure then in the event of a failure, the recovery operation will not try to\r\n * \"recover\" the queue, therefore, we have a persistent variable named 'destructorInProgress'\r\n * which is set before starting the destruction operation.\r\n * After destructorInProgress has been set to true and ordered with a PFENCE(),\r\n * we can clear head, and only then can we de-allocate the last node.\r\n *\r\n * All allocation and de-allocation operations in this queue are prone to\r\n * leaking, if the failure occurs immediately before a de-allocation or\r\n * immediately after an allocation. There is no way around this problem without\r\n * transactions, and seen as we're trying to get lock-free progress, the\r\n * transactional mechanism would have to be also lock-free, and there is no\r\n * lock-free persistent transactional engine published (yet).\r\n *\r\n * Even though this is portable C++ code, this is meant for x86 and may not work correctly on other architectures.\r\n *\r\n * Maged Michael and Michael Scott's Queue with Hazard Pointers:\r\n * <p>\r\n * Lock-Free Linked List as described in Maged Michael and Michael Scott's paper:\r\n * {@link http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf}\r\n * <a href=\"http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf\">\r\n * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms</a>\r\n * <p>\r\n * The paper on Hazard Pointers is named \"Hazard Pointers: Safe Memory\r\n * Reclamation for Lock-Free objects\" and it is available here:\r\n * http://web.cecs.pdx.edu/~walpole/class/cs510/papers/11.pdf\r\n *\r\n *\r\n * TODO: test this on persistence\r\n *\r\n */\r\ntemplate<typename T>\r\nclass PMichaelScottQueue {\r\n\r\nprivate:\r\n    static const int MAX_THREADS = 128;\r\n\r\n    struct Node {\r\n        T item;\r\n        std::atomic<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n        bool casNext(Node *cmp, Node *val) {\r\n            return next.compare_exchange_strong(cmp, val);\r\n        }\r\n    };\r\n\r\n    bool casTail(Node *cmp, Node *val) {\r\n\t\treturn tail.compare_exchange_strong(cmp, val);\r\n\t}\r\n\r\n    bool casHead(Node *cmp, Node *val) {\r\n        return head.compare_exchange_strong(cmp, val);\r\n    }\r\n\r\n    //\r\n    // Persistent variables\r\n    //\r\n\r\n    // Pointers to head and tail of the list\r\n    alignas(128) std::atomic<Node*> head {nullptr};\r\n    alignas(128) std::atomic<Node*> tail {nullptr};\r\n    // Will be set to true when the destructor is called, in case there is a crash during destructor\r\n    bool destructorInProgress = false;\r\n    const int maxThreads;\r\n\r\n    template<typename TN>\r\n    static void internalDelete(TN* obj) {\r\n#ifdef USE_PMDK_ALLOC\r\n        if (obj == nullptr) return;\r\n        obj->~TN();\r\n        glock.lock();\r\n        transaction::exec_tx(gpop, [obj] () {\r\n            pmemobj_tx_free(pmemobj_oid(obj));\r\n        });\r\n        glock.unlock();\r\n#else\r\n        delete obj;\r\n#endif\r\n    }\r\n\r\n    template<typename TN, typename... Args>\r\n    static TN* internalNew(Args&&... args) {\r\n#ifdef USE_PMDK_ALLOC\r\n        glock.lock();\r\n        void *addr = nullptr;\r\n        transaction::exec_tx(gpop, [&addr] () {\r\n            auto oid = pmemobj_tx_alloc(sizeof(TN), 0);\r\n            addr = pmemobj_direct(oid);\r\n        });\r\n        glock.unlock();\r\n        return new (addr) TN(std::forward<Args>(args)...); // placement new\r\n#else\r\n        return new TN(std::forward<Args>(args)...);\r\n#endif\r\n    }\r\n\r\n    std::function<void(Node*,int)> mydeleter = [](Node* node, int tid){ internalDelete(node); };\r\n\r\n    // We need two hazard pointers for dequeue()\r\n    // This variable is a non-volatile pointer to a volatile object\r\n    HazardPointers<Node>* hp  = new HazardPointers<Node>{2, maxThreads,mydeleter};\r\n    static const int kHpTail = 0;\r\n    static const int kHpHead = 0;\r\n    static const int kHpNext = 1;\r\n\r\n\r\n    /*\r\n     * To be called when restarting after a failure\r\n     */\r\n    void recover() {\r\n        if (destructorInProgress) {\r\n            if (head.load(std::memory_order_relaxed) != nullptr) {\r\n                while (dequeue(0) != EMPTY); // Drain the queue\r\n                head.store(nullptr, std::memory_order_relaxed);\r\n                PWB(&head);\r\n                PFENCE();\r\n                internalDelete(head.load(std::memory_order_relaxed));  // Delete the last node\r\n            }\r\n            PSYNC();\r\n            return;\r\n        }\r\n        hp = new HazardPointers<Node>{2, maxThreads,mydeleter};\r\n        // If both head is null then a failure occurred during constructor\r\n        if (head.load(std::memory_order_relaxed) == nullptr) {\r\n            Node* sentinelNode = internalNew<Node>(T{});\r\n            head.store(sentinelNode, std::memory_order_relaxed);\r\n            PWB(&head);\r\n            PFENCE();\r\n        }\r\n        // If tail is null, then fix it by setting it to head\r\n        if (tail.load(std::memory_order_relaxed) == nullptr) {\r\n            tail.store(head.load(std::memory_order_relaxed), std::memory_order_relaxed);\r\n            PWB(&tail);\r\n            PFENCE();\r\n        }\r\n        // Advance the tail if needed\r\n        Node* ltail = tail.load(std::memory_order_relaxed);\r\n        Node* lnext = ltail->next.load(std::memory_order_relaxed);\r\n        if (lnext != nullptr) {\r\n            tail.store(lnext, std::memory_order_relaxed);\r\n            PWB(&tail);\r\n        }\r\n        PSYNC();\r\n    }\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    PMichaelScottQueue(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\r\n        PWB(&head);\r\n        PWB(&tail);\r\n        PFENCE();\r\n        recover();  // re-use the same code as the recovery method\r\n    }\r\n\r\n    ~PMichaelScottQueue() {\r\n        destructorInProgress = true;\r\n        PWB(&destructorInProgress);\r\n        PFENCE();\r\n        recover();  // Re-use the same code as in the recovery method\r\n    }\r\n\r\n    static std::string className() { return \"PMichaelScottQueue\"; }\r\n\r\n    /*\r\n     * Uncontended: at least 3 PWB()s, 2 CAS\r\n     */\r\n    void enqueue(T item, const int tid) {\r\n        Node* newNode = internalNew<Node>(item);\r\n        PWB(&newNode->item);\r\n        PWB(&newNode->next); // Just in case 'item' and 'next' are not on the same cache line\r\n        while (true) {\r\n            Node* ltail = hp->protectPtr(kHpTail, tail, tid);\r\n            if (ltail == tail.load()) {\r\n                Node* lnext = ltail->next.load();\r\n                if (lnext == nullptr) {\r\n                    PWB(&tail);\r\n                    if (ltail->casNext(nullptr, newNode)) {\r\n                        PWB(&ltail->next);\r\n                        casTail(ltail, newNode);\r\n                        hp->clear(tid);\r\n                        return;\r\n                    }\r\n                } else {\r\n                    PWB(&ltail->next);\r\n                    casTail(ltail, lnext);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /*\r\n     * Uncontended: at least 2 PWB()s, 1 CAS, and 1 PSYNC()\r\n     */\r\n    T dequeue(const int tid) {\r\n        Node* node = hp->protect(kHpHead, head, tid);\r\n        while (node != tail.load()) {\r\n            Node* lnext = hp->protect(kHpNext, node->next, tid);\r\n            PWB(&tail);\r\n            PWB(&head);\r\n            if (casHead(node, lnext)) {\r\n                PWB(&head);\r\n                PSYNC();\r\n                T item = lnext->item;  // Another thread may clean up lnext after we do hp->clear()\r\n                hp->clear(tid);\r\n                hp->retire(node, tid);  // TODO: replace the internal de-allocator with an NVM de-allocator\r\n                return item;\r\n            }\r\n            node = hp->protect(kHpHead, head, tid);\r\n        }\r\n        hp->clear(tid);\r\n        return EMPTY;                  // Queue is empty\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_MICHAEL_SCOTT_QUEUE_HP_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/POFLFLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2019\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_OF_LF_LINKED_LIST_QUEUE_H_\r\n#define _PERSISTENT_OF_LF_LINKED_LIST_QUEUE_H_\r\n\r\n#include <stdexcept>\r\n\r\n#include \"ptms/OneFilePTMLF.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using OneFile PTM (Lock-Free) </h1>\r\n *\r\n * enqueue algorithm: sequential implementation + OF-LF\r\n * dequeue algorithm: sequential implementation + OF-LF\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into OF-LF)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass POFLFLinkedListQueue : public poflf::tmbase {\r\n\r\nprivate:\r\n    struct Node : poflf::tmbase {\r\n        poflf::tmtype<T> item;\r\n        poflf::tmtype<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n    };\r\n\r\n    poflf::tmtype<Node*>  head {nullptr};\r\n    poflf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    POFLFLinkedListQueue(unsigned int maxThreads=0) {\r\n        poflf::updateTx([=] () {\r\n            Node* sentinelNode = poflf::tmNew<Node>(EMPTY);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n        });\r\n    }\r\n\r\n\r\n    ~POFLFLinkedListQueue() {\r\n        poflf::updateTx([=] () {\r\n            while (dequeue() != EMPTY); // Drain the queue\r\n            Node* lhead = head;\r\n            poflf::tmDelete(lhead);\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"POF-LF-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T item, const int tid=0) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return poflf::updateTx<bool>([this,item] () -> bool {\r\n            Node* newNode = poflf::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T dequeue(const int tid=0) {\r\n        return poflf::updateTx<T>([this] () -> T {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return EMPTY;\r\n            head = lhead->next;\r\n            poflf::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_OF_LF_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/POFLFMPLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2019\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_OF_LF_MP_LINKED_LIST_QUEUE_H_\r\n#define _PERSISTENT_OF_LF_MP_LINKED_LIST_QUEUE_H_\r\n\r\n#include <stdexcept>\r\n\r\n#include \"ptms/OneFilePTMLFMultiProcess.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using OneFile Multi-Process PTM (Lock-Free) </h1>\r\n *\r\n * enqueue algorithm: sequential implementation + OF-LF\r\n * dequeue algorithm: sequential implementation + OF-LF\r\n * Consistency: Linearizable\r\n * enqueue() progress: lock-free\r\n * dequeue() progress: lock-free\r\n * Memory Reclamation: Hazard Eras (integrated into OF-LF)\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass POFLFMPLinkedListQueue : public onefileptmlfmp::tmbase {\r\n\r\nprivate:\r\n    struct Node : onefileptmlfmp::tmbase {\r\n        onefileptmlfmp::tmtype<T> item;\r\n        onefileptmlfmp::tmtype<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n    };\r\n\r\n    onefileptmlfmp::tmtype<Node*>  head {nullptr};\r\n    onefileptmlfmp::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    POFLFMPLinkedListQueue(unsigned int maxThreads=0) {\r\n        onefileptmlfmp::updateTx([=] () {\r\n            Node* sentinelNode = onefileptmlfmp::tmNew<Node>(EMPTY);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n        });\r\n    }\r\n\r\n\r\n    ~POFLFMPLinkedListQueue() {\r\n        onefileptmlfmp::updateTx([=] () {\r\n            while (dequeue() != EMPTY); // Drain the queue\r\n            Node* lhead = head;\r\n            onefileptmlfmp::tmDelete(lhead);\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"POF-LF-MP-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T item, const int tid=0) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return onefileptmlfmp::updateTx<bool>([this,item] () -> bool {\r\n            Node* newNode = onefileptmlfmp::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T dequeue(const int tid=0) {\r\n        return onefileptmlfmp::updateTx<T>([this] () -> T {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return EMPTY;\r\n            head = lhead->next;\r\n            onefileptmlfmp::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_OF_LF_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/POFWFLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2019\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_OF_WF_LINKED_LIST_QUEUE_H_\r\n#define _PERSISTENT_OF_WF_LINKED_LIST_QUEUE_H_\r\n\r\n#include <stdexcept>\r\n\r\n#include \"ptms/OneFilePTMWF.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using OneFile PTM (Wait-Free) </h1>\r\n *\r\n * enqueue algorithm: sequential implementation + OF-WF\r\n * dequeue algorithm: sequential implementation + OF-WF\r\n * Consistency: Linearizable\r\n * enqueue() progress: wait-free\r\n * dequeue() progress: wait-free\r\n * enqueue min ops: 2 DCAS + 1 CAS\r\n * dequeue min ops: 1 DCAS + 1 CAS\r\n */\r\ntemplate<typename T>\r\nclass POFWFLinkedListQueue : public pofwf::tmbase {\r\n\r\nprivate:\r\n    struct Node : pofwf::tmbase {\r\n        pofwf::tmtype<T> item;\r\n        pofwf::tmtype<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n    };\r\n\r\n    pofwf::tmtype<Node*>  head {nullptr};\r\n    pofwf::tmtype<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    POFWFLinkedListQueue(unsigned int maxThreads=0) {\r\n        pofwf::updateTx([=] () {\r\n            Node* sentinelNode = pofwf::tmNew<Node>(EMPTY);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n        });\r\n    }\r\n\r\n\r\n    ~POFWFLinkedListQueue() {\r\n        pofwf::updateTx([=] () {\r\n            while (dequeue() != EMPTY); // Drain the queue\r\n            Node* lhead = head;\r\n            pofwf::tmDelete(lhead);\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"POF-WF-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T item, const int tid=0) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        return pofwf::updateTx<bool>([this,item] () -> bool {\r\n            Node* newNode = pofwf::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n            return true;\r\n        });\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: wait-free\r\n     */\r\n    T dequeue(const int tid=0) {\r\n        return pofwf::updateTx<T>([this] () -> T {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return EMPTY;\r\n            head = lhead->next;\r\n            pofwf::tmDelete(lhead);\r\n            return head->item;\r\n        });\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_OF_WF_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/RomLRLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_ROMULUS_LR_LINKED_LIST_QUEUE_H_\r\n#define _PERSISTENT_ROMULUS_LR_LINKED_LIST_QUEUE_H_\r\n\r\n#include <stdexcept>\r\n\r\n#include \"ptms/romuluslr/RomulusLR.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using Romulus Left-Right PTM (blocking) </h1>\r\n */\r\ntemplate<typename T>\r\nclass RomLRLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        romuluslr::persist<T> item;\r\n        romuluslr::persist<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n    };\r\n\r\n    alignas(128) romuluslr::persist<Node*>  head {nullptr};\r\n    alignas(128) romuluslr::persist<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    RomLRLinkedListQueue(unsigned int maxThreads=0) {\r\n        romuluslr::RomulusLR::updateTx([&] () {\r\n            Node* sentinelNode = romuluslr::RomulusLR::tmNew<Node>(EMPTY);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n        });\r\n    }\r\n\r\n\r\n    ~RomLRLinkedListQueue() {\r\n        romuluslr::RomulusLR::updateTx([&] () {\r\n            while (dequeue() != EMPTY); // Drain the queue\r\n            Node* lhead = head;\r\n            romuluslr::RomulusLR::tmDelete(lhead);\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"RomulusLR-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T item, const int tid=0) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        romuluslr::RomulusLR::updateTx([&] () {\r\n            Node* newNode = romuluslr::RomulusLR::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n        });\r\n        return true;\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: lock-free\r\n     */\r\n    T dequeue(const int tid=0) {\r\n        T item = EMPTY;\r\n        romuluslr::RomulusLR::updateTx<T>([&] () {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return;\r\n            head = lhead->next;\r\n            romuluslr::RomulusLR::tmDelete(lhead);\r\n            item = head->item;\r\n        });\r\n        return item;\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_ROMULUS_LR_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "pdatastructures/pqueues/RomLogLinkedListQueue.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _PERSISTENT_ROMULUS_LOG_LINKED_LIST_QUEUE_H_\r\n#define _PERSISTENT_ROMULUS_LOG_LINKED_LIST_QUEUE_H_\r\n\r\n#include <stdexcept>\r\n\r\n#include \"ptms/romuluslog/RomulusLog.hpp\"\r\n\r\n/**\r\n * <h1> A Linked List queue using RomulusLog PTM (blocking) </h1>\r\n */\r\ntemplate<typename T>\r\nclass RomLogLinkedListQueue {\r\n\r\nprivate:\r\n    struct Node {\r\n        romuluslog::persist<T> item;\r\n        romuluslog::persist<Node*> next {nullptr};\r\n        Node(T userItem) : item{userItem} { }\r\n    };\r\n\r\n    alignas(128) romuluslog::persist<Node*>  head {nullptr};\r\n    alignas(128) romuluslog::persist<Node*>  tail {nullptr};\r\n\r\n\r\npublic:\r\n    T EMPTY {};\r\n\r\n    RomLogLinkedListQueue(unsigned int maxThreads=0) {\r\n        romuluslog::RomulusLog::updateTx([&] () {\r\n            Node* sentinelNode = romuluslog::RomulusLog::tmNew<Node>(EMPTY);\r\n            head = sentinelNode;\r\n            tail = sentinelNode;\r\n        });\r\n    }\r\n\r\n\r\n    ~RomLogLinkedListQueue() {\r\n        romuluslog::RomulusLog::updateTx([&] () {\r\n            while (dequeue() != EMPTY); // Drain the queue\r\n            Node* lhead = head;\r\n            romuluslog::RomulusLog::tmDelete(lhead);\r\n        });\r\n    }\r\n\r\n\r\n    static std::string className() { return \"RomulusLog-LinkedListQueue\"; }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     * Always returns true\r\n     */\r\n    bool enqueue(T item, const int tid=0) {\r\n        if (item == EMPTY) throw std::invalid_argument(\"item can not be nullptr\");\r\n        romuluslog::RomulusLog::updateTx([&] () {\r\n            Node* newNode = romuluslog::RomulusLog::tmNew<Node>(item);\r\n            tail->next = newNode;\r\n            tail = newNode;\r\n        });\r\n        return true;\r\n    }\r\n\r\n\r\n    /*\r\n     * Progress Condition: blocking\r\n     */\r\n    T dequeue(const int tid=0) {\r\n        T item = EMPTY;\r\n        romuluslog::RomulusLog::updateTx<T>([&] () {\r\n            Node* lhead = head;\r\n            if (lhead == tail) return;\r\n            head = lhead->next;\r\n            romuluslog::RomulusLog::tmDelete(lhead);\r\n            item = head->item;\r\n        });\r\n        return item;\r\n    }\r\n};\r\n\r\n#endif /* _PERSISTENT_ROMULUS_LOG_LINKED_LIST_QUEUE_H_ */\r\n"
  },
  {
    "path": "ptms/OneFilePTMLF.hpp",
    "content": "/*\n * Copyright 2017-2019\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _PERSISTENT_ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_H_\n#define _PERSISTENT_ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_H_\n\n#include <atomic>\n#include <cassert>\n#include <iostream>\n#include <vector>\n#include <functional>\n#include <cstring>\n#include <sys/mman.h>   // Needed if we use mmap()\n#include <sys/types.h>  // Needed by open() and close()\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>     // Needed by close()\n\n// Please keep this file in sync (as much as possible) with stms/OneFileLF.hpp\n\n// Macros needed for persistence\n#ifdef PWB_IS_CLFLUSH\n  /*\n   * More info at http://elixir.free-electrons.com/linux/latest/source/arch/x86/include/asm/special_insns.h#L213\n   * Intel programming manual at https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf\n   * Use these for Broadwell CPUs (cervino server)\n   */\n  #define PWB(addr)              __asm__ volatile(\"clflush (%0)\" :: \"r\" (addr) : \"memory\")                  // Broadwell only works with this.\n  #define PFENCE()               {}                                                                         // No ordering fences needed for CLFLUSH (section 7.4.6 of Intel manual)\n  #define PSYNC()                {}                                                                         // For durability it's not obvious, but CLFLUSH seems to be enough, and PMDK uses the same approach\n#elif PWB_IS_CLWB\n  /* Use this for CPUs that support clwb, such as the SkyLake SP series (c5 compute intensive instances in AWS are an example of it) */\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; xsaveopt %0\" : \"+m\" (*(volatile char *)(addr)))  // clwb() only for Ice Lake onwards\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#elif PWB_IS_NOP\n  /* pwbs are not needed for shared memory persistency (i.e. persistency across process failure) */\n  #define PWB(addr)              {}\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#elif PWB_IS_CLFLUSHOPT\n  /* Use this for CPUs that support clflushopt, which is most recent x86 */\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; clflush %0\" : \"+m\" (*(volatile char *)(addr)))    // clflushopt (Kaby Lake)\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#else\n#error \"You must define what PWB is. Choose PWB_IS_CLFLUSHOPT if you don't know what your CPU is capable of\"\n#endif\n\n\n/*\n * Differences between POneFileLF and the non-persistent OneFileLF:\n * - A secondary redo log (PWriteSet) is placed in persistent memory before attempting a 'commit'.\n * - The set of the request in helpApply() is always done with a CAS to enforce ordering on the PWBs of the DCAS;\n * - The persistent logs are allocated in PM, same as all user allocations from tmNew(), 'curTx', and 'request'\n */\nnamespace poflf {\n\n//\n// User configurable variables.\n// Feel free to change these if you need larger transactions, more allocations per transacation, or more threads.\n//\n\n// Maximum number of registered threads that can execute transactions\nstatic const int REGISTRY_MAX_THREADS = 128;\n// Maximum number of stores in the WriteSet per transaction\nstatic const uint64_t TX_MAX_STORES = 40*1024;\n// Number of buckets in the hashmap of the WriteSet.\nstatic const uint64_t HASH_BUCKETS = 2048;\n\n// Persistent-specific configuration\n// Name of persistent file mapping\nstatic const char * PFILE_NAME = \"/dev/shm/ponefilelf_shared\";\n// Start address of mapped persistent memory\nstatic uint8_t* PREGION_ADDR = (uint8_t*)0x7fea00000000;\n// Size of persistent memory. Part of it will be used by the redo logs\nstatic const uint64_t PREGION_SIZE = 1024*1024*1024ULL;   // 1 GB by default\n// End address of mapped persistent memory\nstatic uint8_t* PREGION_END = (PREGION_ADDR+PREGION_SIZE);\n// Maximum number of root pointers available for the user\nstatic const uint64_t MAX_ROOT_POINTERS = 100;\n\n\n// DCAS / CAS2 macro\n#define DCAS(ptr, o1, o2, n1, n2)                               \\\n({                                                              \\\n    char __ret;                                                 \\\n    __typeof__(o2) __junk;                                      \\\n    __typeof__(*(ptr)) __old1 = (o1);                           \\\n    __typeof__(o2) __old2 = (o2);                               \\\n    __typeof__(*(ptr)) __new1 = (n1);                           \\\n    __typeof__(o2) __new2 = (n2);                               \\\n    asm volatile(\"lock cmpxchg16b %2;setz %1\"                   \\\n                   : \"=d\"(__junk), \"=a\"(__ret), \"+m\" (*ptr)     \\\n                   : \"b\"(__new1), \"c\"(__new2),                  \\\n                     \"a\"(__old1), \"d\"(__old2));                 \\\n    __ret; })\n\n\n// Functions to convert between a transaction identifier (uint64_t) and a pair of {sequence,index}\nstatic inline uint64_t seqidx2trans(uint64_t seq, uint64_t idx) {\n    return (seq << 10) | idx;\n}\nstatic inline uint64_t trans2seq(uint64_t trans) {\n    return trans >> 10;\n}\nstatic inline uint64_t trans2idx(uint64_t trans) {\n    return trans & 0x3FF; // 10 bits\n}\n\n// Flush each cache line in a range\nstatic inline void flushFromTo(void* from, void* to) noexcept {\n    const uint64_t cache_line_size = 64;\n    uint8_t* ptr = (uint8_t*)(((uint64_t)from) & (~(cache_line_size-1)));\n    for (; ptr < (uint8_t*)to; ptr += cache_line_size) PWB(ptr);\n}\n\n\n//\n// Thread Registry stuff\n//\nextern void thread_registry_deregister_thread(const int tid);\n\n// An helper class to do the checkin and checkout of the thread registry\nstruct ThreadCheckInCheckOut {\n    static const int NOT_ASSIGNED = -1;\n    int tid { NOT_ASSIGNED };\n    ~ThreadCheckInCheckOut() {\n        if (tid == NOT_ASSIGNED) return;\n        thread_registry_deregister_thread(tid);\n    }\n};\n\nextern thread_local ThreadCheckInCheckOut tl_tcico;\n\n// Forward declaration of global/singleton instance\nclass ThreadRegistry;\nextern ThreadRegistry gThreadRegistry;\n\n/*\n * <h1> Registry for threads </h1>\n *\n * This is singleton type class that allows assignement of a unique id to each thread.\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\n * corresponding slot to be used by a later thread.\n */\nclass ThreadRegistry {\nprivate:\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\n\npublic:\n    ThreadRegistry() {\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\n            usedTID[it].store(false, std::memory_order_relaxed);\n        }\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    int register_thread_new(void) {\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\n            bool unused = false;\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\n            // Increase the current maximum to cover our thread id\n            int curMax = maxTid.load();\n            while (curMax <= tid) {\n                maxTid.compare_exchange_strong(curMax, tid+1);\n                curMax = maxTid.load();\n            }\n            tl_tcico.tid = tid;\n            return tid;\n        }\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\n        assert(false);\n    }\n\n    // Progress condition: wait-free population oblivious\n    inline void deregister_thread(const int tid) {\n        usedTID[tid].store(false, std::memory_order_release);\n    }\n\n    // Progress condition: wait-free population oblivious\n    static inline uint64_t getMaxThreads(void) {\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    static inline int getTID(void) {\n        int tid = tl_tcico.tid;\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\n        return gThreadRegistry.register_thread_new();\n    }\n};\n\n\n// Forward declaration needed by EsLoco\ntemplate<typename T> struct tmtype;\n\n// We need to split the contents from the methods due to compilation dependencies\ntemplate<typename T> struct tmtypebase {\n    // Stores the actual value as an atomic\n    std::atomic<uint64_t>  val;\n    // Lets hope this comes immediately after 'val' in memory mapping, otherwise the DCAS() will fail\n    std::atomic<uint64_t>  seq;\n};\n\n\n/*\n * EsLoco is an Extremely Simple memory aLOCatOr\n *\n * It is based on intrusive singly-linked lists (a free-list), one for each power of two size.\n * All blocks are powers of two, the smallest size enough to contain the desired user data plus the block header.\n * There is an array named 'freelists' where each entry is a pointer to the head of a stack for that respective block size.\n * Blocks are allocated in powers of 2 of words (64bit words).\n * Each block has an header with two words: the size of the node (in words), the pointer to the next node.\n * The minimum block size is 4 words, with 2 for the header and 2 for the user.\n * When there is no suitable block in the freelist, it will create a new block from the remaining pool.\n *\n * EsLoco was designed for usage in PTMs but it doesn't have to be used only for that.\n * Average number of stores for an allocation is 1.\n * Average number of stores for a de-allocation is 2.\n *\n * Memory layout:\n * ------------------------------------------------------------------------\n * | poolTop | freelists[0] ... freelists[61] | ... allocated objects ... |\n * ------------------------------------------------------------------------\n */\ntemplate <template <typename> class P>\nclass EsLoco {\nprivate:\n    struct block {\n        P<block*>   next;   // Pointer to next block in free-list (when block is in free-list)\n        P<uint64_t> size;   // Exponent of power of two of the size of this block in bytes.\n    };\n\n    const bool debugOn = false;\n\n    // Volatile data\n    uint8_t* poolAddr {nullptr};\n    uint64_t poolSize {0};\n\n    // Pointer to array of persistent heads of free-list\n    block* freelists {nullptr};\n    // Volatile pointer to persistent pointer to last unused address (the top of the pool)\n    P<uint8_t*>* poolTop {nullptr};\n\n    // Number of blocks in the freelists array.\n    // Each entry corresponds to an exponent of the block size: 2^4, 2^5, 2^6... 2^40\n    static const int kMaxBlockSize = 50; // 1024 TB of memory should be enough\n\n    // For powers of 2, returns the highest bit, otherwise, returns the next highest bit\n    uint64_t highestBit(uint64_t val) {\n        uint64_t b = 0;\n        while ((val >> (b+1)) != 0) b++;\n        if (val > (1ULL << b)) return b+1;\n        return b;\n    }\n\n    uint8_t* aligned(uint8_t* addr) {\n        return (uint8_t*)((size_t)addr & (~0x3FULL)) + 128;\n    }\n\npublic:\n    void init(void* addressOfMemoryPool, size_t sizeOfMemoryPool, bool clearPool=true) {\n        // Align the base address of the memory pool\n        poolAddr = aligned((uint8_t*)addressOfMemoryPool);\n        poolSize = sizeOfMemoryPool + (uint8_t*)addressOfMemoryPool - poolAddr;\n        // The first thing in the pool is a pointer to the top of the pool\n        poolTop = (P<uint8_t*>*)poolAddr;\n        // The second thing in the pool is the array of freelists\n        freelists = (block*)(poolAddr + sizeof(*poolTop));\n        if (clearPool) {\n            std::memset(poolAddr, 0, poolSize);\n            for (int i = 0; i < kMaxBlockSize; i++) freelists[i].next.pstore(nullptr);\n            // The size of the freelists array in bytes is sizeof(block)*kMaxBlockSize\n            // Align to cache line boundary (DCAS needs 16 byte alignment)\n            poolTop->pstore(aligned(poolAddr + sizeof(*poolTop) + sizeof(block)*kMaxBlockSize));\n        }\n        if (debugOn) printf(\"Starting EsLoco with poolAddr=%p and poolSize=%ld, up to %p\\n\", poolAddr, poolSize, poolAddr+poolSize);\n    }\n\n    // Resets the metadata of the allocator back to its defaults\n    void reset() {\n        std::memset(poolAddr, 0, sizeof(block)*kMaxBlockSize);\n        poolTop->pstore(nullptr);\n    }\n\n    // Returns the number of bytes that may (or may not) have allocated objects, from the base address to the top address\n    uint64_t getUsedSize() {\n        return poolTop->pload() - poolAddr;\n    }\n\n    // Takes the desired size of the object in bytes.\n    // Returns pointer to memory in pool, or nullptr.\n    // Does on average 1 store to persistent memory when re-utilizing blocks.\n    void* malloc(size_t size) {\n        P<uint8_t*>* top = (P<uint8_t*>*)(((uint8_t*)poolTop));\n        block* flists = (block*)(((uint8_t*)freelists));\n        // Adjust size to nearest (highest) power of 2\n        uint64_t bsize = highestBit(size + sizeof(block));\n        if (debugOn) printf(\"malloc(%ld) requested,  block size exponent = %ld\\n\", size, bsize);\n        block* myblock = nullptr;\n        // Check if there is a block of that size in the corresponding freelist\n        if (flists[bsize].next.pload() != nullptr) {\n            if (debugOn) printf(\"Found available block in freelist\\n\");\n            // Unlink block\n            myblock = flists[bsize].next;\n            flists[bsize].next = myblock->next;          // pstore()\n        } else {\n            if (debugOn) printf(\"Creating new block from top, currently at %p\\n\", top->pload());\n            // Couldn't find a suitable block, get one from the top of the pool if there is one available\n            if (top->pload() + (1<<bsize) > poolSize + poolAddr) {\n                printf(\"EsLoco: Out of memory for %ld bytes allocation\\n\", size);\n                return nullptr;\n            }\n            myblock = (block*)top->pload();\n            top->pstore(top->pload() + (1<<bsize));      // pstore()\n            myblock->size = bsize;                       // pstore()\n        }\n        if (debugOn) printf(\"returning ptr = %p\\n\", (void*)((uint8_t*)myblock + sizeof(block)));\n        // Return the block, minus the header\n        return (void*)((uint8_t*)myblock + sizeof(block));\n    }\n\n    // Takes a pointer to an object and puts the block on the free-list.\n    // Does on average 2 stores to persistent memory.\n    void free(void* ptr) {\n        if (ptr == nullptr) return;\n        block* flists = (block*)(((uint8_t*)freelists));\n        block* myblock = (block*)((uint8_t*)ptr - sizeof(block));\n        if (debugOn) printf(\"free(%p)  block size exponent = %ld\\n\", ptr, myblock->size.pload());\n        // Insert the block in the corresponding freelist\n        myblock->next = flists[myblock->size].next;      // pstore()\n        flists[myblock->size].next = myblock;            // pstore()\n    }\n};\n\n\n// Needed by our benchmarks\nstruct tmbase {\n};\n\n\n// An entry in the persistent write-set\nstruct PWriteSetEntry {\n    void*    addr;  // Address of value+sequence to change\n    uint64_t val;   // Desired value to change to\n};\n\n\n// The persistent write-set (undo log)\nstruct PWriteSet {\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\n    std::atomic<uint64_t> request {0};            // Can be moved to CLOSED by other threads, using a CAS\n    PWriteSetEntry        plog[TX_MAX_STORES];    // Redo log of stores\n\n    // Applies all entries in the log. Called only by recover() which is non-concurrent.\n    void applyFromRecover() {\n        // We're assuming that 'val' is the size of a uint64_t\n        for (uint64_t i = 0; i < numStores; i++) {\n            *((uint64_t*)plog[i].addr) = plog[i].val;\n            PWB(plog[i].addr);\n        }\n    }\n};\n\n\n// The persistent metadata is a 'header' that contains all the logs and the persistent curTx variable.\n// It is located at the start of the persistent region, and the remaining region contains the data available for the allocator to use.\nstruct PMetadata {\n    static const uint64_t   MAGIC_ID = 0x1337babe;\n    std::atomic<uint64_t>   curTx {seqidx2trans(1,0)};\n    std::atomic<uint64_t>   pad1[15];\n    tmtypebase<void*>       rootPtrs[MAX_ROOT_POINTERS];\n    PWriteSet               plog[REGISTRY_MAX_THREADS];\n    uint64_t                id {0};\n    uint64_t                pad2 {0};\n};\n\n\n// A single entry in the write-set\nstruct WriteSetEntry {\n    void*          addr {nullptr};  // Address of value+sequence to change\n    uint64_t       val;             // Desired value to change to\n    WriteSetEntry* next {nullptr};  // Pointer to next node in the (intrusive) hash map\n};\n\nextern thread_local bool tl_is_read_only;\n\n\n// The write-set is a log of the words modified during the transaction.\n// This log is an array with an intrusive hashmap of size HASH_BUCKETS.\nstruct WriteSet {\n    static const uint64_t MAX_ARRAY_LOOKUP = 30;  // Beyond this, it seems to be faster to use the hashmap\n    WriteSetEntry         log[TX_MAX_STORES];     // Redo log of stores\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\n    WriteSetEntry*        buckets[HASH_BUCKETS];  // Intrusive HashMap for fast lookup in large(r) transactions\n\n    WriteSet() {\n        numStores = 0;\n        for (int i = 0; i < HASH_BUCKETS; i++) buckets[i] = &log[TX_MAX_STORES-1];\n    }\n\n    // Copies the current write set to persistent memory\n    inline void persistAndFlushLog(PWriteSet* const pwset) {\n        for (uint64_t i = 0; i < numStores; i++) {\n            pwset->plog[i].addr = log[i].addr;\n            pwset->plog[i].val = log[i].val;\n        }\n        pwset->numStores = numStores;\n        // Flush the log and the numStores variable\n        flushFromTo(&pwset->numStores, &pwset->plog[numStores+1]);\n    }\n\n    // Uses the log to flush the modifications to NVM.\n    // We assume tmtype does not cross cache line boundaries.\n    inline void flushModifications() {\n        for (uint64_t i = 0; i < numStores; i++) PWB(log[i].addr);\n    }\n\n    // Each address on a different bucket\n    inline uint64_t hash(const void* addr) const {\n        return (((uint64_t)addr) >> 3) % HASH_BUCKETS;\n    }\n\n    // Adds a modification to the redo log\n    inline void addOrReplace(void* addr, uint64_t val) {\n        if (tl_is_read_only) tl_is_read_only = false;\n        const uint64_t hashAddr = hash(addr);\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < numStores; idx++) {\n                if (log[idx].addr == addr) {\n                    log[idx].val = val;\n                    return;\n                }\n            }\n        } else {\n            // Lookup in hashmap\n            WriteSetEntry* be = buckets[hashAddr];\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\n                while (be != nullptr) {\n                    if (be->addr == addr) {\n                        be->val = val;\n                        return;\n                    }\n                    be = be->next;\n                }\n            }\n        }\n        // Add to array\n        WriteSetEntry* e = &log[numStores++];\n        assert(numStores < TX_MAX_STORES);\n        e->addr = addr;\n        e->val = val;\n        // Add to hashmap\n        WriteSetEntry* be = buckets[hashAddr];\n        // Clear if entry is from previous tx\n        e->next = (be < e && hash(be->addr) == hashAddr) ? be : nullptr;\n        buckets[hashAddr] = e;\n    }\n\n    // Does a lookup on the WriteSet for an addr.\n    // If the numStores is lower than MAX_ARRAY_LOOKUP, the lookup is done on the log, otherwise, the lookup is done on the hashmap.\n    // If it's not in the write-set, return lval.\n    inline uint64_t lookupAddr(const void* addr, uint64_t lval) {\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < numStores; idx++) {\n                if (log[idx].addr == addr) return log[idx].val;\n            }\n        } else {\n            // Lookup in hashmap\n            const uint64_t hashAddr = hash(addr);\n            WriteSetEntry* be = buckets[hashAddr];\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\n                while (be != nullptr) {\n                    if (be->addr == addr) return be->val;\n                    be = be->next;\n                }\n            }\n        }\n        return lval;\n    }\n\n    // Assignment operator, used when making a copy of a WriteSet to help another thread\n    WriteSet& operator = (const WriteSet &other) {\n        numStores = other.numStores;\n        for (uint64_t i = 0; i < numStores; i++) log[i] = other.log[i];\n        return *this;\n    }\n\n    // Applies all entries in the log as DCASes.\n    // Seq must match for DCAS to succeed. This method is on the \"hot-path\".\n    inline void apply(uint64_t seq, const int tid) {\n        for (uint64_t i = 0; i < numStores; i++) {\n            // Use an heuristic to give each thread 8 consecutive DCAS to apply\n            WriteSetEntry& e = log[(tid*8 + i) % numStores];\n            tmtypebase<uint64_t>* tmte = (tmtypebase<uint64_t>*)e.addr;\n            uint64_t lval = tmte->val.load(std::memory_order_acquire);\n            uint64_t lseq = tmte->seq.load(std::memory_order_acquire);\n            if (lseq < seq) DCAS((uint64_t*)e.addr, lval, lseq, e.val, seq);\n        }\n    }\n};\n\n\n// Forward declaration\nstruct OpData;\n// This is used by addOrReplace() to know which OpDesc instance to use for the current transaction\nextern thread_local OpData* tl_opdata;\n\n\n// Its purpose is to hold thread-local data\nstruct OpData {\n    uint64_t      curTx {0};              // Used during a transaction to keep the value of curTx read in beginTx() (owner thread only)\n    uint64_t      nestedTrans {0};        // Thread-local: Number of nested transactions\n    PWriteSet*    pWriteSet {nullptr};    // Pointer to the redo log in persistent memory\n    uint64_t      padding[16-3];          // Padding to avoid false-sharing in nestedTrans and curTx\n};\n\n\n// Used to identify aborted transactions\nstruct AbortedTx {};\nstatic constexpr AbortedTx AbortedTxException {};\n\nclass OneFileLF;\nextern OneFileLF gOFLF;\n\n\n/**\n * <h1> One-File PTM (Lock-Free) </h1>\n *\n * One-File is a Persistent Software Transacional Memory with lock-free progress, meant to\n * implement lock-free data structures. It has integrated lock-free memory\n * reclamation using an optimistic memory scheme\n *\n * OF is a word-based PTM and it uses double-compare-and-swap (DCAS).\n *\n * Right now it has several limitations, some will be fixed in the future, some may be hard limitations of this approach:\n * - We can't have stack allocated tmtype<> variables. For example, we can't created inside a transaction \"tmtpye<uint64_t> tmp = a;\",\n *   it will give weird errors because of stack allocation.\n * - We need DCAS but it can be emulated with LL/SC or even with single-word CAS\n *   if we do redirection to a (lock-free) pool with SeqPtrs;\n */\nclass OneFileLF {\nprivate:\n    static const bool                    debug = false;\n    OpData                              *opData;\n    int                                  fd {-1};\n\npublic:\n    EsLoco<tmtype>                       esloco {};\n    PMetadata*                           pmd {nullptr};\n    std::atomic<uint64_t>*               curTx {nullptr};              // Pointer to persistent memory location of curTx (it's in PMetadata)\n    WriteSet*                            writeSets;                    // Two write-sets for each thread\n\n    OneFileLF() {\n        opData = new OpData[REGISTRY_MAX_THREADS];\n        writeSets = new WriteSet[REGISTRY_MAX_THREADS];\n        mapPersistentRegion(PFILE_NAME, PREGION_ADDR, PREGION_SIZE);\n    }\n\n    ~OneFileLF() {\n        delete[] opData;\n        delete[] writeSets;\n    }\n\n    static std::string className() { return \"OneFilePTM-LF\"; }\n\n    void mapPersistentRegion(const char* filename, uint8_t* regionAddr, const uint64_t regionSize) {\n        // Check that the header with the logs leaves at least half the memory available to the user\n        if (sizeof(PMetadata) > regionSize/2) {\n            printf(\"ERROR: the size of the logs in persistent memory is so large that it takes more than half the whole persistent memory\\n\");\n            printf(\"Please reduce some of the settings in OneFilePTMLF.hpp and try again\\n\");\n            assert(false);\n        }\n        bool reuseRegion = false;\n        // Check if the file already exists or not\n        struct stat buf;\n        if (stat(filename, &buf) == 0) {\n            // File exists\n            fd = open(filename, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            reuseRegion = true;\n        } else {\n            // File doesn't exist\n            fd = open(filename, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            if (lseek(fd, regionSize-1, SEEK_SET) == -1) {\n                perror(\"lseek() error\");\n            }\n            if (write(fd, \"\", 1) == -1) {\n                perror(\"write() error\");\n            }\n        }\n        // mmap() memory range\n        void* got_addr = (uint8_t *)mmap(regionAddr, regionSize, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);\n        if (got_addr == MAP_FAILED || got_addr != regionAddr) {\n            printf(\"got_addr = %p  instead of %p\\n\", got_addr, regionAddr);\n            perror(\"ERROR: mmap() is not working !!! \");\n            assert(false);\n        }\n        // Check if the header is consistent and only then can we attempt to re-use, otherwise we clear everything that's there\n        pmd = reinterpret_cast<PMetadata*>(regionAddr);\n        if (reuseRegion) reuseRegion = (pmd->id == PMetadata::MAGIC_ID);\n        // Map pieces of persistent Metadata to pointers in volatile memory\n        for (uint64_t i = 0; i < REGISTRY_MAX_THREADS; i++) opData[i].pWriteSet = &(pmd->plog[i]);\n        curTx = &(pmd->curTx);\n        // If the file has just been created or if the header is not consistent, clear everything.\n        // Otherwise, re-use and recover to a consistent state.\n        if (reuseRegion) {\n            esloco.init(regionAddr+sizeof(PMetadata), regionSize-sizeof(PMetadata), false);\n            //recover(); // Not needed on x86\n        } else {\n            // Start by resetting all tmtypes::seq in the metadata region\n            std::memset(regionAddr, 0, sizeof(PMetadata));\n            new (regionAddr) PMetadata();\n            esloco.init(regionAddr+sizeof(PMetadata), regionSize-sizeof(PMetadata), true);\n            PFENCE();\n            pmd->id = PMetadata::MAGIC_ID;\n            PWB(&pmd->id);\n            PFENCE();\n        }\n    }\n\n    // Progress Condition: lock-free\n    // The while-loop retarts only if there was at least one other thread completing a transaction\n    void beginTx(OpData& myopd, const int tid) {\n        tl_is_read_only = true;\n        while (true) {\n            myopd.curTx = curTx->load(std::memory_order_acquire);\n            helpApply(myopd.curTx, tid);\n            // Reset the write-set after (possibly) helping another transaction complete\n            writeSets[tid].numStores = 0;\n            // Start over if there is already a new transaction\n            if (myopd.curTx == curTx->load(std::memory_order_acquire)) return;\n        }\n    }\n\n    // Progress condition: wait-free population-oblivious\n    // Attempts to publish our write-set (commit the transaction) and then applies the write-set.\n    // Returns true if my transaction was committed.\n    inline bool commitTx(OpData& myopd, const int tid) {\n        // If it's a read-only transaction, then commit immediately\n        if (writeSets[tid].numStores == 0) return true;\n        // Give up if the curTx has changed sinced our transaction started\n        if (myopd.curTx != curTx->load(std::memory_order_acquire)) return false;\n        // Move our request to OPEN, using the sequence of the previous transaction +1\n        const uint64_t seq = trans2seq(myopd.curTx);\n        const uint64_t newTx = seqidx2trans(seq+1,tid);\n        myopd.pWriteSet->request.store(newTx, std::memory_order_release);\n        // Copy the write-set to persistent memory and flush it\n        writeSets[tid].persistAndFlushLog(myopd.pWriteSet);\n        // Attempt to CAS curTx to our OpDesc instance (tid) incrementing the seq in it\n        uint64_t lcurTx = myopd.curTx;\n        if (debug) printf(\"tid=%i  attempting CAS on curTx from (%ld,%ld) to (%ld,%ld)\\n\", tid, trans2seq(lcurTx), trans2idx(lcurTx), seq+1, (uint64_t)tid);\n        if (!curTx->compare_exchange_strong(lcurTx, newTx)) return false;\n        PWB(curTx);\n        // Execute each store in the write-set using DCAS() and close the request\n        helpApply(newTx, tid);\n        // We should need a PSYNC() here to provide durable linearizabilty, but the CAS of the state in helpApply() acts as a PSYNC() (on x86).\n        if (debug) printf(\"Committed transaction (%ld,%ld) with %ld stores\\n\", seq+1, (uint64_t)tid, writeSets[tid].numStores);\n        return true;\n    }\n\n    // Same as beginTx/endTx transaction, but with lambdas, and it handles AbortedTx exceptions\n    template<typename R, typename F> R transaction(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = opData[tid];\n        if (myopd.nestedTrans > 0) return func();\n        ++myopd.nestedTrans;\n        tl_opdata = &myopd;\n        R retval {};\n        while (true) {\n            beginTx(myopd, tid);\n            try {\n                retval = func();\n            } catch (AbortedTx&) {\n                continue;\n            }\n            if (commitTx(myopd, tid)) break;\n        }\n        tl_opdata = nullptr;\n        --myopd.nestedTrans;\n        return retval;\n    }\n\n    // Same as above, but returns void\n    template<typename F> void transaction(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = opData[tid];\n        if (myopd.nestedTrans > 0) {\n            func();\n            return;\n        }\n        ++myopd.nestedTrans;\n        tl_opdata = &myopd;\n        while (true) {\n            beginTx(myopd, tid);\n            try {\n                func();\n            } catch (AbortedTx&) {\n                continue;\n            }\n            if (commitTx(myopd, tid)) break;\n        }\n        tl_opdata = nullptr;\n        --myopd.nestedTrans;\n    }\n\n    // It's silly that these have to be static, but we need them for the (SPS) benchmarks due to templatization\n    template<typename R, typename F> static R updateTx(F&& func) { return gOFLF.transaction<R>(func); }\n    template<typename R, typename F> static R readTx(F&& func) { return gOFLF.transaction<R>(func); }\n    template<typename F> static void updateTx(F&& func) { gOFLF.transaction(func); }\n    template<typename F> static void readTx(F&& func) { gOFLF.transaction(func); }\n\n    template <typename T, typename... Args> static T* tmNew(Args&&... args) {\n    //template <typename T> static T* tmNew() {\n        T* ptr = (T*)gOFLF.esloco.malloc(sizeof(T));\n        //new (ptr) T;  // new placement\n        new (ptr) T(std::forward<Args>(args)...);\n        return ptr;\n    }\n\n    template<typename T> static void tmDelete(T* obj) {\n        if (obj == nullptr) return;\n        obj->~T(); // Execute destructor as part of the current transaction\n        tmFree(obj);\n    }\n\n    static void* tmMalloc(size_t size) {\n        if (tl_opdata == nullptr) {\n            printf(\"ERROR: Can not allocate outside a transaction\\n\");\n            return nullptr;\n        }\n        void* obj = gOFLF.esloco.malloc(size);\n        return obj;\n    }\n\n    static void tmFree(void* obj) {\n        if (obj == nullptr) return;\n        if (tl_opdata == nullptr) {\n            printf(\"ERROR: Can not de-allocate outside a transaction\\n\");\n            return;\n        }\n        gOFLF.esloco.free(obj);\n    }\n\n    static void* pmalloc(size_t size) {\n        return gOFLF.esloco.malloc(size);\n    }\n\n    static void pfree(void* obj) {\n        if (obj == nullptr) return;\n        gOFLF.esloco.free(obj);\n    }\n\n    template <typename T> static inline T* get_object(int idx) {\n        tmtype<T*>* ptr = (tmtype<T*>*)&(gOFLF.pmd->rootPtrs[idx]);\n        return ptr->pload();\n    }\n\n    template <typename T> static inline void put_object(int idx, T* obj) {\n        tmtype<T*>* ptr = (tmtype<T*>*)&(gOFLF.pmd->rootPtrs[idx]);\n        ptr->pstore(obj);\n    }\n\nprivate:\n    // Progress condition: wait-free population oblivious\n    inline void helpApply(uint64_t lcurTx, const int tid) {\n        const uint64_t idx = trans2idx(lcurTx);\n        const uint64_t seq = trans2seq(lcurTx);\n        OpData& opd = opData[idx];\n        // Nothing to apply unless the request matches the curTx\n        if (lcurTx != opd.pWriteSet->request.load(std::memory_order_acquire)) return;\n        if (idx != tid) {\n            // Make a copy of the write-set and check if it is consistent\n            writeSets[tid] = writeSets[idx];\n            std::atomic_thread_fence(std::memory_order_acquire);\n            if (lcurTx != curTx->load()) return;\n            if (lcurTx != opd.pWriteSet->request.load(std::memory_order_acquire)) return;\n        }\n        if (debug) printf(\"Applying %ld stores in write-set\\n\", writeSets[tid].numStores);\n        writeSets[tid].apply(seq, tid);\n        writeSets[tid].flushModifications();\n        if (opd.pWriteSet->request.load() == lcurTx) {\n            const uint64_t newReq = seqidx2trans(seq+1,idx);\n            opd.pWriteSet->request.compare_exchange_strong(lcurTx, newReq);\n        }\n    }\n\n    // Upon restart, re-applies the last transaction, so as to guarantee that\n    // we have a consistent state in persistent memory.\n    // This is not used on x86 because the DCAS has atomicity writting to persistent memory.\n    void recover() {\n        uint64_t lcurTx = curTx->load(std::memory_order_acquire);\n        opData[trans2idx(lcurTx)].pWriteSet->applyFromRecover();\n        PSYNC();\n    }\n};\n\n\n\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\ntemplate<typename T> struct tmtype : tmtypebase<T> {\n    tmtype() { }\n\n    tmtype(T initVal) { pstore(initVal); }\n\n    // Casting operator\n    operator T() { return pload(); }\n\n    // Prefix increment operator: ++x\n    void operator++ () { pstore(pload()+1); }\n    // Prefix decrement operator: --x\n    void operator-- () { pstore(pload()-1); }\n    void operator++ (int) { pstore(pload()+1); }\n    void operator-- (int) { pstore(pload()-1); }\n\n    // Equals operator: first downcast to T and then compare\n    bool operator == (const T& otherval) const { return pload() == otherval; }\n\n    // Difference operator: first downcast to T and then compare\n    bool operator != (const T& otherval) const { return pload() != otherval; }\n\n    // Relational operators\n    bool operator < (const T& rhs) { return pload() < rhs; }\n    bool operator > (const T& rhs) { return pload() > rhs; }\n    bool operator <= (const T& rhs) { return pload() <= rhs; }\n    bool operator >= (const T& rhs) { return pload() >= rhs; }\n\n    // Operator arrow ->\n    T operator->() { return pload(); }\n\n    // Copy constructor\n    tmtype<T>(const tmtype<T>& other) { pstore(other.pload()); }\n\n    // Assignment operator from an tmtype\n    tmtype<T>& operator=(const tmtype<T>& other) {\n        pstore(other.pload());\n        return *this;\n    }\n\n    // Assignment operator from a value\n    tmtype<T>& operator=(T value) {\n        pstore(value);\n        return *this;\n    }\n\n    // Operator &\n    T* operator&() {\n        return (T*)this;\n    }\n\n    // Meant to be called when know we're the only ones touching\n    // these contents, for example, in the constructor of an object, before\n    // making the object visible to other threads.\n    inline void isolated_store(T newVal) {\n        tmtypebase<T>::val.store((uint64_t)newVal, std::memory_order_relaxed);\n    }\n\n    // We don't need to check curTx here because we're not de-referencing\n    // the val. It's only after a load() that the val may be de-referenced\n    // (in user code), therefore we do the check on load() only.\n    inline void pstore(T newVal) {\n        OpData* const myopd = tl_opdata;\n        if (myopd == nullptr) { // Looks like we're outside a transaction\n            tmtypebase<T>::val.store((uint64_t)newVal, std::memory_order_relaxed);\n        } else {\n            gOFLF.writeSets[tl_tcico.tid].addOrReplace(this, (uint64_t)newVal);\n        }\n    }\n\n    // We have to check if there is a new ongoing transaction and if so, abort\n    // this execution immediately for two reasons:\n    // 1. Memory Reclamation: the val we're returning may be a pointer to an\n    // object that has since been retired and deleted, therefore we can't allow\n    // user code to de-reference it;\n    // 2. Invariant Conservation: The val we're reading may be from a newer\n    // transaction, which implies that it may break an invariant in the user code.\n    // See examples of invariant breaking in this post:\n    // http://concurrencyfreaks.com/2013/11/stampedlocktryoptimisticread-and.html\n    inline T pload() const {\n        T lval = (T)tmtypebase<T>::val.load(std::memory_order_acquire);\n        OpData* const myopd = tl_opdata;\n        if (myopd == nullptr) return lval;\n        if ((uint8_t*)this < PREGION_ADDR || (uint8_t*)this > PREGION_END) return lval;\n        uint64_t lseq = tmtypebase<T>::seq.load(std::memory_order_acquire);\n        if (lseq > trans2seq(myopd->curTx)) throw AbortedTxException;\n        if (tl_is_read_only) return lval;\n        return (T)gOFLF.writeSets[tl_tcico.tid].lookupAddr(this, (uint64_t)lval);\n    }\n};\n\n\n//\n// Wrapper methods to the global TM instance. The user should use these:\n//\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gOFLF.transaction<R>(func); }\ntemplate<typename R, typename F> static R readTx(F&& func) { return gOFLF.transaction<R>(func); }\ntemplate<typename F> static void updateTx(F&& func) { gOFLF.transaction(func); }\ntemplate<typename F> static void readTx(F&& func) { gOFLF.transaction(func); }\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return OneFileLF::tmNew<T>(std::forward<Args>(args)...); }\ntemplate<typename T> void tmDelete(T* obj) { OneFileLF::tmDelete<T>(obj); }\ntemplate<typename T> static T* get_object(int idx) { return OneFileLF::get_object<T>(idx); }\ntemplate<typename T> static void put_object(int idx, T* obj) { OneFileLF::put_object<T>(idx, obj); }\ninline static void* tmMalloc(size_t size) { return OneFileLF::tmMalloc(size); }\ninline static void tmFree(void* obj) { OneFileLF::tmFree(obj); }\n\n\n//\n// Place these in a .cpp if you include this header from multiple files (compilation units)\n//\nOneFileLF gOFLF {};\nthread_local OpData* tl_opdata {nullptr};\n// Global/singleton to hold all the thread registry functionality\nThreadRegistry gThreadRegistry {};\n// During a transaction, this is true up until the first store()\nthread_local bool tl_is_read_only {false};\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\nthread_local ThreadCheckInCheckOut tl_tcico {};\n// Helper function for thread de-registration\nvoid thread_registry_deregister_thread(const int tid) {\n    gThreadRegistry.deregister_thread(tid);\n}\n\n}\n#endif /* _PERSISTENT_ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_H_ */\n"
  },
  {
    "path": "ptms/OneFilePTMLFMultiProcess.hpp",
    "content": "/*\n * Copyright 2017-2019\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _PERSISTENT_ONE_FILE_LOCK_FREE_MULTI_PROCESS_TRANSACTIONAL_MEMORY_H_\n#define _PERSISTENT_ONE_FILE_LOCK_FREE_MULTI_PROCESS_TRANSACTIONAL_MEMORY_H_\n\n#include <atomic>\n#include <cassert>\n#include <iostream>\n#include <vector>\n#include <functional>\n#include <cstring>\n#include <sys/mman.h>   // Needed if we use mmap()\n#include <sys/types.h>  // Needed by open() and close()\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>     // Needed by close()\n#include <pthread.h>    // Needed by robust mutexes\n\n// Please keep this file in sync (as much as possible) with stms/OneFileLF.hpp\n\n// Macros needed for persistence\n#ifdef PWB_IS_CLFLUSH\n  /*\n   * More info at http://elixir.free-electrons.com/linux/latest/source/arch/x86/include/asm/special_insns.h#L213\n   * Intel programming manual at https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf\n   * Use these for Broadwell CPUs (cervino server)\n   */\n  #define PWB(addr)              __asm__ volatile(\"clflush (%0)\" :: \"r\" (addr) : \"memory\")                  // Broadwell only works with this.\n  #define PFENCE()               {}                                                                         // No ordering fences needed for CLFLUSH (section 7.4.6 of Intel manual)\n  #define PSYNC()                {}                                                                         // For durability it's not obvious, but CLFLUSH seems to be enough, and PMDK uses the same approach\n#elif PWB_IS_CLWB\n  /* Use this for CPUs that support clwb, such as the SkyLake SP series (c5 compute intensive instances in AWS are an example of it) */\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; xsaveopt %0\" : \"+m\" (*(volatile char *)(addr)))  // clwb() only for Ice Lake onwards\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#elif PWB_IS_NOP\n  /* pwbs are not needed for shared memory persistency (i.e. persistency across process failure) */\n  #define PWB(addr)              {}\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#elif PWB_IS_CLFLUSHOPT\n  /* Use this for CPUs that support clflushopt, which is most recent x86 */\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; clflush %0\" : \"+m\" (*(volatile char *)(addr)))    // clflushopt (Kaby Lake)\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#else\n#error \"You must define what PWB is. Choose PWB_IS_CLFLUSHOPT if you don't know what your CPU is capable of\"\n#endif\n\n\n/*\n * Differences between POneFileLF and the non-persistent OneFileLF:\n * - A secondary redo log (PWriteSet) is placed in persistent memory before attempting a 'commit'.\n * - The set of the request in helpApply() is always done with a CAS to enforce ordering on the PWBs of the DCAS;\n * - The persistent logs are allocated in PM, same as all user allocations from tmNew(), 'curTx', and 'request'\n */\nnamespace onefileptmlfmp {\n\n//\n// User configurable variables.\n// Feel free to change these if you need larger transactions, more allocations per transacation, or more threads.\n//\n\n// Maximum number of registered threads that can execute transactions\nstatic const int REGISTRY_MAX_THREADS = 128;\n// Maximum number of stores in the WriteSet per transaction\nstatic const uint64_t TX_MAX_STORES = 40*1024;\n// Number of buckets in the hashmap of the WriteSet.\nstatic const uint64_t HASH_BUCKETS = 2048;\n\n// Persistent-specific configuration\n// Name of persistent file mapping\nstatic const char * PFILE_NAME = \"/dev/shm/ponefilelfmp_shared\";\n// Start address of mapped persistent memory\nstatic uint8_t* PREGION_ADDR = (uint8_t*)0x70ea00000000;\n// Size of persistent memory. Part of it will be used by the redo logs\nstatic const uint64_t PREGION_SIZE = 1024*1024*1024ULL;   // 1 GB by default\n// End address of mapped persistent memory\nstatic uint8_t* PREGION_END = (PREGION_ADDR+PREGION_SIZE);\n// Maximum number of root pointers available for the user\nstatic const uint64_t MAX_ROOT_POINTERS = 100;\n\n\n// DCAS / CAS2 macro\n#define DCAS(ptr, o1, o2, n1, n2)                               \\\n({                                                              \\\n    char __ret;                                                 \\\n    __typeof__(o2) __junk;                                      \\\n    __typeof__(*(ptr)) __old1 = (o1);                           \\\n    __typeof__(o2) __old2 = (o2);                               \\\n    __typeof__(*(ptr)) __new1 = (n1);                           \\\n    __typeof__(o2) __new2 = (n2);                               \\\n    asm volatile(\"lock cmpxchg16b %2;setz %1\"                   \\\n                   : \"=d\"(__junk), \"=a\"(__ret), \"+m\" (*ptr)     \\\n                   : \"b\"(__new1), \"c\"(__new2),                  \\\n                     \"a\"(__old1), \"d\"(__old2));                 \\\n    __ret; })\n\n\n// Functions to convert between a transaction identifier (uint64_t) and a pair of {sequence,index}\nstatic inline uint64_t seqidx2trans(uint64_t seq, uint64_t idx) {\n    return (seq << 10) | idx;\n}\nstatic inline uint64_t trans2seq(uint64_t trans) {\n    return trans >> 10;\n}\nstatic inline uint64_t trans2idx(uint64_t trans) {\n    return trans & 0x3FF; // 10 bits\n}\n\n// Flush each cache line in a range\nstatic inline void flushFromTo(void* from, void* to) noexcept {\n    const uint64_t cache_line_size = 64;\n    uint8_t* ptr = (uint8_t*)(((uint64_t)from) & (~(cache_line_size-1)));\n    for (; ptr < (uint8_t*)to; ptr += cache_line_size) PWB(ptr);\n}\n\n\n//\n// Thread Registry stuff\n//\nextern void thread_registry_deregister_thread(const int tid);\n\n// An helper class to do the checkin and checkout of the thread registry\nstruct ThreadCheckInCheckOut {\n    static const int NOT_ASSIGNED = -1;\n    int tid { NOT_ASSIGNED };\n    ~ThreadCheckInCheckOut() {\n        if (tid == NOT_ASSIGNED) return;\n        thread_registry_deregister_thread(tid);\n    }\n};\n\nextern thread_local ThreadCheckInCheckOut tl_tcico;\n\n// Forward declaration of global/singleton instance\nclass ThreadRegistry;\nextern ThreadRegistry gThreadRegistry;\n\n/*\n * <h1> Registry for threads </h1>\n *\n * This is singleton type class that allows assignement of a unique id to each thread.\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\n * corresponding slot to be used by a later thread.\n */\nclass ThreadRegistry {\nprivate:\n    pthread_mutex_t*        usedTID;   // (pointer to) Which TIDs are in use by threads\n    std::atomic<int64_t>*   maxTid;    // (pointer to) Highest TID (+1) in use by threads\n\npublic:\n    void initRobustMutex(pthread_mutex_t* rmutex) {\n        pthread_mutexattr_t ma;\n        pthread_mutexattr_init(&ma);\n        pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);\n        pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);\n        pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ADAPTIVE_NP);\n        pthread_mutex_init(rmutex, &ma);\n        pthread_mutexattr_destroy(&ma);\n    }\n\n    void init(pthread_mutex_t* usedTID, std::atomic<int64_t>* maxTid, bool clearPool) {\n        this->usedTID = usedTID;\n        this->maxTid = maxTid;\n        if (clearPool) {\n            for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\n                initRobustMutex(&usedTID[it]);\n            }\n        }\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    int register_thread_new(void) {\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\n            if (pthread_mutex_trylock(&usedTID[tid]) == EBUSY) continue;\n            // Increase the current maximum to cover our thread id\n            int64_t curMax = maxTid->load();\n            while (curMax <= tid) {\n                maxTid->compare_exchange_strong(curMax, tid+1);\n                curMax = maxTid->load();\n            }\n            tl_tcico.tid = tid;\n            //printf(\"got thread id %d\\n\", tid);\n            return tid;\n        }\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\n        assert(false);\n    }\n\n    // Progress condition: wait-free population oblivious\n    inline void deregister_thread(const int tid) {\n        pthread_mutex_unlock(&usedTID[tid]);\n    }\n\n    // Progress condition: wait-free population oblivious\n    static inline uint64_t getMaxThreads(void) {\n        return gThreadRegistry.maxTid->load(std::memory_order_acquire);\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    static inline int getTID(void) {\n        int tid = tl_tcico.tid;\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\n        return gThreadRegistry.register_thread_new();\n    }\n};\n\n\n// Forward declaration needed by EsLoco\ntemplate<typename T> struct tmtype;\n\n// We need to split the contents from the methods due to compilation dependencies\ntemplate<typename T> struct tmtypebase {\n    // Stores the actual value as an atomic\n    std::atomic<uint64_t>  val;\n    // Lets hope this comes immediately after 'val' in memory mapping, otherwise the DCAS() will fail\n    std::atomic<uint64_t>  seq;\n};\n\n\n/*\n * EsLoco is an Extremely Simple memory aLOCatOr\n *\n * It is based on intrusive singly-linked lists (a free-list), one for each power of two size.\n * All blocks are powers of two, the smallest size enough to contain the desired user data plus the block header.\n * There is an array named 'freelists' where each entry is a pointer to the head of a stack for that respective block size.\n * Blocks are allocated in powers of 2 of words (64bit words).\n * Each block has an header with two words: the size of the node (in words), the pointer to the next node.\n * The minimum block size is 4 words, with 2 for the header and 2 for the user.\n * When there is no suitable block in the freelist, it will create a new block from the remaining pool.\n *\n * EsLoco was designed for usage in PTMs but it doesn't have to be used only for that.\n * Average number of stores for an allocation is 1.\n * Average number of stores for a de-allocation is 2.\n *\n * Memory layout:\n * ------------------------------------------------------------------------\n * | poolTop | freelists[0] ... freelists[61] | ... allocated objects ... |\n * ------------------------------------------------------------------------\n */\ntemplate <template <typename> class P>\nclass EsLoco {\nprivate:\n    struct block {\n        P<block*>   next;   // Pointer to next block in free-list (when block is in free-list)\n        P<uint64_t> size;   // Exponent of power of two of the size of this block in bytes.\n    };\n\n    const bool debugOn = false;\n\n    // Volatile data\n    uint8_t* poolAddr {nullptr};\n    uint64_t poolSize {0};\n\n    // Pointer to array of persistent heads of free-list\n    block* freelists {nullptr};\n    // Volatile pointer to persistent pointer to last unused address (the top of the pool)\n    P<uint8_t*>* poolTop {nullptr};\n\n    // Number of blocks in the freelists array.\n    // Each entry corresponds to an exponent of the block size: 2^4, 2^5, 2^6... 2^40\n    static const int kMaxBlockSize = 50; // 1024 TB of memory should be enough\n\n    // For powers of 2, returns the highest bit, otherwise, returns the next highest bit\n    uint64_t highestBit(uint64_t val) {\n        uint64_t b = 0;\n        while ((val >> (b+1)) != 0) b++;\n        if (val > (1ULL << b)) return b+1;\n        return b;\n    }\n\n    uint8_t* aligned(uint8_t* addr) {\n        return (uint8_t*)((size_t)addr & (~0x3FULL)) + 128;\n    }\n\npublic:\n    void init(void* addressOfMemoryPool, size_t sizeOfMemoryPool, bool clearPool=true) {\n        // Align the base address of the memory pool\n        poolAddr = aligned((uint8_t*)addressOfMemoryPool);\n        poolSize = sizeOfMemoryPool + (uint8_t*)addressOfMemoryPool - poolAddr;\n        // The first thing in the pool is a pointer to the top of the pool\n        poolTop = (P<uint8_t*>*)poolAddr;\n        // The second thing in the pool is the array of freelists\n        freelists = (block*)(poolAddr + sizeof(*poolTop));\n        if (clearPool) {\n            std::memset(poolAddr, 0, poolSize);\n            for (int i = 0; i < kMaxBlockSize; i++) freelists[i].next.pstore(nullptr);\n            // The size of the freelists array in bytes is sizeof(block)*kMaxBlockSize\n            // Align to cache line boundary (DCAS needs 16 byte alignment)\n            poolTop->pstore(aligned(poolAddr + sizeof(*poolTop) + sizeof(block)*kMaxBlockSize));\n        }\n        if (debugOn) printf(\"Starting EsLoco with poolAddr=%p and poolSize=%ld, up to %p\\n\", poolAddr, poolSize, poolAddr+poolSize);\n    }\n\n    // Resets the metadata of the allocator back to its defaults\n    void reset() {\n        std::memset(poolAddr, 0, sizeof(block)*kMaxBlockSize);\n        poolTop->pstore(nullptr);\n    }\n\n    // Returns the number of bytes that may (or may not) have allocated objects, from the base address to the top address\n    uint64_t getUsedSize() {\n        return poolTop->pload() - poolAddr;\n    }\n\n    // Takes the desired size of the object in bytes.\n    // Returns pointer to memory in pool, or nullptr.\n    // Does on average 1 store to persistent memory when re-utilizing blocks.\n    void* malloc(size_t size) {\n        P<uint8_t*>* top = (P<uint8_t*>*)(((uint8_t*)poolTop));\n        block* flists = (block*)(((uint8_t*)freelists));\n        // Adjust size to nearest (highest) power of 2\n        uint64_t bsize = highestBit(size + sizeof(block));\n        if (debugOn) printf(\"malloc(%ld) requested,  block size exponent = %ld\\n\", size, bsize);\n        block* myblock = nullptr;\n        // Check if there is a block of that size in the corresponding freelist\n        if (flists[bsize].next.pload() != nullptr) {\n            if (debugOn) printf(\"Found available block in freelist\\n\");\n            // Unlink block\n            myblock = flists[bsize].next;\n            flists[bsize].next = myblock->next;          // pstore()\n        } else {\n            if (debugOn) printf(\"Creating new block from top, currently at %p\\n\", top->pload());\n            // Couldn't find a suitable block, get one from the top of the pool if there is one available\n            if (top->pload() + (1<<bsize) > poolSize + poolAddr) {\n                printf(\"EsLoco: Out of memory for %ld bytes allocation\\n\", size);\n                return nullptr;\n            }\n            myblock = (block*)top->pload();\n            top->pstore(top->pload() + (1<<bsize));      // pstore()\n            myblock->size = bsize;                       // pstore()\n        }\n        if (debugOn) printf(\"returning ptr = %p\\n\", (void*)((uint8_t*)myblock + sizeof(block)));\n        // Return the block, minus the header\n        return (void*)((uint8_t*)myblock + sizeof(block));\n    }\n\n    // Takes a pointer to an object and puts the block on the free-list.\n    // Does on average 2 stores to persistent memory.\n    void free(void* ptr) {\n        if (ptr == nullptr) return;\n        block* flists = (block*)(((uint8_t*)freelists));\n        block* myblock = (block*)((uint8_t*)ptr - sizeof(block));\n        if (debugOn) printf(\"free(%p)  block size exponent = %ld\\n\", ptr, myblock->size.pload());\n        // Insert the block in the corresponding freelist\n        myblock->next = flists[myblock->size].next;      // pstore()\n        flists[myblock->size].next = myblock;            // pstore()\n    }\n};\n\n\n// Needed by our benchmarks\nstruct tmbase {\n};\n\n\n// An entry in the persistent write-set\nstruct PWriteSetEntry {\n    void*    addr;  // Address of value+sequence to change\n    uint64_t val;   // Desired value to change to\n};\n\n\n// The persistent write-set (undo log)\nstruct PWriteSet {\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\n    std::atomic<uint64_t> request {0};            // Can be moved to CLOSED by other threads, using a CAS\n    PWriteSetEntry        plog[TX_MAX_STORES];    // Redo log of stores\n\n    // Applies all entries in the log. Called only by recover() which is non-concurrent.\n    void applyFromRecover() {\n        // We're assuming that 'val' is the size of a uint64_t\n        for (uint64_t i = 0; i < numStores; i++) {\n            *((uint64_t*)plog[i].addr) = plog[i].val;\n            PWB(plog[i].addr);\n        }\n    }\n};\n\n\n// A single entry in the write-set\nstruct WriteSetEntry {\n    void*          addr {nullptr};  // Address of value+sequence to change\n    uint64_t       val;             // Desired value to change to\n    WriteSetEntry* next {nullptr};  // Pointer to next node in the (intrusive) hash map\n};\n\nextern thread_local bool tl_is_read_only;\n\n\n// The write-set is a log of the words modified during the transaction.\n// This log is an array with an intrusive hashmap of size HASH_BUCKETS.\nstruct WriteSet {\n    static const uint64_t MAX_ARRAY_LOOKUP = 30;  // Beyond this, it seems to be faster to use the hashmap\n    WriteSetEntry         log[TX_MAX_STORES];     // Redo log of stores\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\n    WriteSetEntry*        buckets[HASH_BUCKETS];  // Intrusive HashMap for fast lookup in large(r) transactions\n\n    WriteSet() {\n        numStores = 0;\n        for (int i = 0; i < HASH_BUCKETS; i++) buckets[i] = &log[TX_MAX_STORES-1];\n    }\n\n    // Copies the current write set to persistent memory\n    inline void persistAndFlushLog(PWriteSet* const pwset) {\n        for (uint64_t i = 0; i < numStores; i++) {\n            pwset->plog[i].addr = log[i].addr;\n            pwset->plog[i].val = log[i].val;\n        }\n        pwset->numStores = numStores;\n        // Flush the log and the numStores variable\n        flushFromTo(&pwset->numStores, &pwset->plog[numStores+1]);\n    }\n\n    // Uses the log to flush the modifications to NVM.\n    // We assume tmtype does not cross cache line boundaries.\n    inline void flushModifications() {\n        for (uint64_t i = 0; i < numStores; i++) PWB(log[i].addr);\n    }\n\n    // Each address on a different bucket\n    inline uint64_t hash(const void* addr) const {\n        return (((uint64_t)addr) >> 3) % HASH_BUCKETS;\n    }\n\n    // Adds a modification to the redo log\n    inline void addOrReplace(void* addr, uint64_t val) {\n        if (tl_is_read_only) tl_is_read_only = false;\n        const uint64_t hashAddr = hash(addr);\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < numStores; idx++) {\n                if (log[idx].addr == addr) {\n                    log[idx].val = val;\n                    return;\n                }\n            }\n        } else {\n            // Lookup in hashmap\n            WriteSetEntry* be = buckets[hashAddr];\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\n                while (be != nullptr) {\n                    if (be->addr == addr) {\n                        be->val = val;\n                        return;\n                    }\n                    be = be->next;\n                }\n            }\n        }\n        // Add to array\n        WriteSetEntry* e = &log[numStores++];\n        assert(numStores < TX_MAX_STORES);\n        e->addr = addr;\n        e->val = val;\n        // Add to hashmap\n        WriteSetEntry* be = buckets[hashAddr];\n        // Clear if entry is from previous tx\n        e->next = (be < e && hash(be->addr) == hashAddr) ? be : nullptr;\n        buckets[hashAddr] = e;\n    }\n\n    // Does a lookup on the WriteSet for an addr.\n    // If the numStores is lower than MAX_ARRAY_LOOKUP, the lookup is done on the log, otherwise, the lookup is done on the hashmap.\n    // If it's not in the write-set, return lval.\n    inline uint64_t lookupAddr(const void* addr, uint64_t lval) {\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < numStores; idx++) {\n                if (log[idx].addr == addr) return log[idx].val;\n            }\n        } else {\n            // Lookup in hashmap\n            const uint64_t hashAddr = hash(addr);\n            WriteSetEntry* be = buckets[hashAddr];\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\n                while (be != nullptr) {\n                    if (be->addr == addr) return be->val;\n                    be = be->next;\n                }\n            }\n        }\n        return lval;\n    }\n\n    // Assignment operator, used when making a copy of a WriteSet to help another thread\n    WriteSet& operator = (const WriteSet &other) {\n        numStores = other.numStores;\n        for (uint64_t i = 0; i < numStores; i++) log[i] = other.log[i];\n        return *this;\n    }\n\n    // Applies all entries in the log as DCASes.\n    // Seq must match for DCAS to succeed. This method is on the \"hot-path\".\n    inline void apply(uint64_t seq, const int tid) {\n        for (uint64_t i = 0; i < numStores; i++) {\n            // Use an heuristic to give each thread 8 consecutive DCAS to apply\n            WriteSetEntry& e = log[(tid*8 + i) % numStores];\n            tmtypebase<uint64_t>* tmte = (tmtypebase<uint64_t>*)e.addr;\n            uint64_t lval = tmte->val.load(std::memory_order_acquire);\n            uint64_t lseq = tmte->seq.load(std::memory_order_acquire);\n            if (lseq < seq) DCAS((uint64_t*)e.addr, lval, lseq, e.val, seq);\n        }\n    }\n};\n\n\n// The persistent metadata is a 'header' that contains all the logs and the persistent curTx variable.\n// It is located at the start of the persistent region, and the remaining region contains the data available for the allocator to use.\nstruct PMetadata {\n    static const uint64_t   MAGIC_ID = 0x1337babe;\n    std::atomic<uint64_t>   curTx {seqidx2trans(1,0)};\n    std::atomic<uint64_t>   pad1[15];\n    pthread_mutex_t         usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\n    std::atomic<int64_t>    maxTid {-1};                     // Highest TID (+1) in use by threads\n    uint64_t                pad2 {0};\n    tmtypebase<void*>       rootPtrs[MAX_ROOT_POINTERS];\n    PWriteSet               plog[REGISTRY_MAX_THREADS];\n    WriteSet                writeSets[REGISTRY_MAX_THREADS];\n    uint64_t                id {0};\n    uint64_t                pad3 {0};\n};\n\n\n// Forward declaration\nstruct OpData;\n// This is used by addOrReplace() to know which OpDesc instance to use for the current transaction\nextern thread_local OpData* tl_opdata;\n\n\n// Its purpose is to hold thread-local data\nstruct OpData {\n    uint64_t      curTx {0};              // Used during a transaction to keep the value of curTx read in beginTx() (owner thread only)\n    uint64_t      nestedTrans {0};        // Thread-local: Number of nested transactions\n    PWriteSet*    pWriteSet {nullptr};    // Pointer to the redo log in persistent memory\n    uint64_t      padding[16-3];          // Padding to avoid false-sharing in nestedTrans and curTx\n};\n\n\n// Used to identify aborted transactions\nstruct AbortedTx {};\nstatic constexpr AbortedTx AbortedTxException {};\n\nclass OneFileLF;\nextern OneFileLF gOFLF;\n\n\n/**\n * <h1> One-File PTM (Lock-Free) </h1>\n *\n * One-File is a Persistent Software Transacional Memory with lock-free progress, meant to\n * implement lock-free data structures. It has integrated lock-free memory\n * reclamation using an optimistic memory scheme\n *\n * OF is a word-based PTM and it uses double-compare-and-swap (DCAS).\n *\n * Right now it has several limitations, some will be fixed in the future, some may be hard limitations of this approach:\n * - We can't have stack allocated tmtype<> variables. For example, we can't created inside a transaction \"tmtpye<uint64_t> tmp = a;\",\n *   it will give weird errors because of stack allocation.\n * - We need DCAS but it can be emulated with LL/SC or even with single-word CAS\n *   if we do redirection to a (lock-free) pool with SeqPtrs;\n */\nclass OneFileLF {\nprivate:\n    static const bool                    debug = false;\n    OpData                              *opData;\n    int                                  fd {-1};\n\npublic:\n    EsLoco<tmtype>                       esloco {};\n    PMetadata*                           pmd {nullptr};\n    std::atomic<uint64_t>*               curTx {nullptr};              // Pointer to persistent memory location of curTx (it's in PMetadata)\n    WriteSet*                            writeSets;                    // One write-set for each thread\n\n    OneFileLF() {\n        opData = new OpData[REGISTRY_MAX_THREADS];\n        mapPersistentRegion(PFILE_NAME, PREGION_ADDR, PREGION_SIZE);\n    }\n\n    ~OneFileLF() {\n        delete[] opData;\n    }\n\n    static std::string className() { return \"OneFilePTM-MultiProcess-LF\"; }\n\n    void mapPersistentRegion(const char* filename, uint8_t* regionAddr, const uint64_t regionSize) {\n        // Check that the header with the logs leaves at least half the memory available to the user\n        if (sizeof(PMetadata) > regionSize/2) {\n            printf(\"ERROR: the size of the logs in persistent memory is so large that it takes more than half the whole persistent memory\\n\");\n            printf(\"Please reduce some of the settings in OneFilePTMMultiProcess.hpp and try again\\n\");\n            assert(false);\n        }\n        bool reuseRegion = false;\n        // Check if the file already exists or not\n        struct stat buf;\n        if (stat(filename, &buf) == 0) {\n            // File exists\n            fd = open(filename, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            reuseRegion = true;\n        } else {\n            // File doesn't exist\n            fd = open(filename, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            if (lseek(fd, regionSize-1, SEEK_SET) == -1) {\n                perror(\"lseek() error\");\n            }\n            if (write(fd, \"\", 1) == -1) {\n                perror(\"write() error\");\n            }\n        }\n        // mmap() memory range\n        void* got_addr = (uint8_t *)mmap(regionAddr, regionSize, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);\n        if (got_addr == MAP_FAILED || got_addr != regionAddr) {\n            printf(\"got_addr = %p  instead of %p\\n\", got_addr, regionAddr);\n            perror(\"ERROR: mmap() is not working !!! \");\n            assert(false);\n        }\n        // Check if the header is consistent and only then can we attempt to re-use, otherwise we clear everything that's there\n        pmd = reinterpret_cast<PMetadata*>(regionAddr);\n        if (reuseRegion) reuseRegion = (pmd->id == PMetadata::MAGIC_ID);\n        // Map pieces of persistent Metadata to pointers in volatile memory\n        for (uint64_t i = 0; i < REGISTRY_MAX_THREADS; i++) opData[i].pWriteSet = &(pmd->plog[i]);\n        curTx = &pmd->curTx;\n        writeSets = (WriteSet*)&pmd->writeSets;\n        // If the file has just been created or if the header is not consistent, clear everything.\n        // Otherwise, re-use and recover to a consistent state.\n        if (reuseRegion) {\n            gThreadRegistry.init((pthread_mutex_t*)&pmd->usedTID, &pmd->maxTid, false);\n            esloco.init(regionAddr+sizeof(PMetadata), regionSize-sizeof(PMetadata), false);\n            //recover(); // Not needed on x86\n        } else {\n            // Start by resetting all tmtypes::seq in the metadata region\n            std::memset(regionAddr, 0, sizeof(PMetadata));\n            new (regionAddr) PMetadata();\n            gThreadRegistry.init((pthread_mutex_t*)&pmd->usedTID, &pmd->maxTid, true);\n            esloco.init(regionAddr+sizeof(PMetadata), regionSize-sizeof(PMetadata), true);\n            PFENCE();\n            pmd->id = PMetadata::MAGIC_ID;\n            PWB(&pmd->id);\n            PFENCE();\n        }\n    }\n\n    // Progress Condition: lock-free\n    // The while-loop retarts only if there was at least one other thread completing a transaction\n    void beginTx(OpData& myopd, const int tid) {\n        tl_is_read_only = true;\n        while (true) {\n            myopd.curTx = curTx->load(std::memory_order_acquire);\n            helpApply(myopd.curTx, tid);\n            // Reset the write-set after (possibly) helping another transaction complete\n            writeSets[tid].numStores = 0;\n            // Start over if there is already a new transaction\n            if (myopd.curTx == curTx->load(std::memory_order_acquire)) return;\n        }\n    }\n\n    // Progress condition: wait-free population-oblivious\n    // Attempts to publish our write-set (commit the transaction) and then applies the write-set.\n    // Returns true if my transaction was committed.\n    inline bool commitTx(OpData& myopd, const int tid) {\n        // If it's a read-only transaction, then commit immediately\n        if (writeSets[tid].numStores == 0) return true;\n        // Give up if the curTx has changed sinced our transaction started\n        if (myopd.curTx != curTx->load(std::memory_order_acquire)) return false;\n        // Move our request to OPEN, using the sequence of the previous transaction +1\n        const uint64_t seq = trans2seq(myopd.curTx);\n        const uint64_t newTx = seqidx2trans(seq+1,tid);\n        myopd.pWriteSet->request.store(newTx, std::memory_order_release);\n        // Copy the write-set to persistent memory and flush it\n        writeSets[tid].persistAndFlushLog(myopd.pWriteSet);\n        // Attempt to CAS curTx to our OpDesc instance (tid) incrementing the seq in it\n        uint64_t lcurTx = myopd.curTx;\n        if (debug) printf(\"tid=%i  attempting CAS on curTx from (%ld,%ld) to (%ld,%ld)\\n\", tid, trans2seq(lcurTx), trans2idx(lcurTx), seq+1, (uint64_t)tid);\n        if (!curTx->compare_exchange_strong(lcurTx, newTx)) return false;\n        PWB(curTx);\n        // Execute each store in the write-set using DCAS() and close the request\n        helpApply(newTx, tid);\n        // We should need a PSYNC() here to provide durable linearizabilty, but the CAS of the state in helpApply() acts as a PSYNC() (on x86).\n        if (debug) printf(\"Committed transaction (%ld,%ld) with %ld stores\\n\", seq+1, (uint64_t)tid, writeSets[tid].numStores);\n        return true;\n    }\n\n    // Same as beginTx/endTx transaction, but with lambdas, and it handles AbortedTx exceptions\n    template<typename R, typename F> R transaction(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = opData[tid];\n        if (myopd.nestedTrans > 0) return func();\n        ++myopd.nestedTrans;\n        tl_opdata = &myopd;\n        R retval {};\n        while (true) {\n            beginTx(myopd, tid);\n            try {\n                retval = func();\n            } catch (AbortedTx&) {\n                continue;\n            }\n            if (commitTx(myopd, tid)) break;\n        }\n        tl_opdata = nullptr;\n        --myopd.nestedTrans;\n        return retval;\n    }\n\n    // Same as above, but returns void\n    template<typename F> void transaction(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = opData[tid];\n        if (myopd.nestedTrans > 0) {\n            func();\n            return;\n        }\n        ++myopd.nestedTrans;\n        tl_opdata = &myopd;\n        while (true) {\n            beginTx(myopd, tid);\n            try {\n                func();\n            } catch (AbortedTx&) {\n                continue;\n            }\n            if (commitTx(myopd, tid)) break;\n        }\n        tl_opdata = nullptr;\n        --myopd.nestedTrans;\n    }\n\n    // It's silly that these have to be static, but we need them for the (SPS) benchmarks due to templatization\n    template<typename R, typename F> static R updateTx(F&& func) { return gOFLF.transaction<R>(func); }\n    template<typename R, typename F> static R readTx(F&& func) { return gOFLF.transaction<R>(func); }\n    template<typename F> static void updateTx(F&& func) { gOFLF.transaction(func); }\n    template<typename F> static void readTx(F&& func) { gOFLF.transaction(func); }\n\n    template <typename T, typename... Args> static T* tmNew(Args&&... args) {\n    //template <typename T> static T* tmNew() {\n        T* ptr = (T*)gOFLF.esloco.malloc(sizeof(T));\n        //new (ptr) T;  // new placement\n        new (ptr) T(std::forward<Args>(args)...);\n        return ptr;\n    }\n\n    template<typename T> static void tmDelete(T* obj) {\n        if (obj == nullptr) return;\n        obj->~T(); // Execute destructor as part of the current transaction\n        tmFree(obj);\n    }\n\n    static void* tmMalloc(size_t size) {\n        if (tl_opdata == nullptr) {\n            printf(\"ERROR: Can not allocate outside a transaction\\n\");\n            return nullptr;\n        }\n        void* obj = gOFLF.esloco.malloc(size);\n        return obj;\n    }\n\n    static void tmFree(void* obj) {\n        if (obj == nullptr) return;\n        if (tl_opdata == nullptr) {\n            printf(\"ERROR: Can not de-allocate outside a transaction\\n\");\n            return;\n        }\n        gOFLF.esloco.free(obj);\n    }\n\n    static void* pmalloc(size_t size) {\n        return gOFLF.esloco.malloc(size);\n    }\n\n    static void pfree(void* obj) {\n        if (obj == nullptr) return;\n        gOFLF.esloco.free(obj);\n    }\n\n    template <typename T> static inline T* get_object(int idx) {\n        tmtype<T*>* ptr = (tmtype<T*>*)&(gOFLF.pmd->rootPtrs[idx]);\n        return ptr->pload();\n    }\n\n    template <typename T> static inline void put_object(int idx, T* obj) {\n        tmtype<T*>* ptr = (tmtype<T*>*)&(gOFLF.pmd->rootPtrs[idx]);\n        ptr->pstore(obj);\n    }\n\nprivate:\n    // Progress condition: wait-free population oblivious\n    inline void helpApply(uint64_t lcurTx, const int tid) {\n        const uint64_t idx = trans2idx(lcurTx);\n        const uint64_t seq = trans2seq(lcurTx);\n        OpData& opd = opData[idx];\n        // Nothing to apply unless the request matches the curTx\n        if (lcurTx != opd.pWriteSet->request.load(std::memory_order_acquire)) return;\n        if (idx != tid) {\n            // Make a copy of the write-set and check if it is consistent\n            writeSets[tid] = writeSets[idx];\n            std::atomic_thread_fence(std::memory_order_acquire);\n            if (lcurTx != curTx->load()) return;\n            if (lcurTx != opd.pWriteSet->request.load(std::memory_order_acquire)) return;\n        }\n        if (debug) printf(\"Applying %ld stores in write-set\\n\", writeSets[tid].numStores);\n        writeSets[tid].apply(seq, tid);\n        writeSets[tid].flushModifications();\n        const uint64_t newReq = seqidx2trans(seq+1,idx);\n        if (opd.pWriteSet->request.load(std::memory_order_acquire) == lcurTx) {\n            opd.pWriteSet->request.compare_exchange_strong(lcurTx, newReq);\n        }\n    }\n\n    // Upon restart, re-applies the last transaction, so as to guarantee that\n    // we have a consistent state in persistent memory.\n    // This is not needed on x86, where the DCAS has atomicity writting to persistent memory.\n    void recover() {\n        uint64_t lcurTx = curTx->load(std::memory_order_acquire);\n        opData[trans2idx(lcurTx)].pWriteSet->applyFromRecover();\n        PSYNC();\n    }\n};\n\n\n\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\ntemplate<typename T> struct tmtype : tmtypebase<T> {\n    tmtype() { }\n\n    tmtype(T initVal) { pstore(initVal); }\n\n    // Casting operator\n    operator T() { return pload(); }\n\n    // Prefix increment operator: ++x\n    void operator++ () { pstore(pload()+1); }\n    // Prefix decrement operator: --x\n    void operator-- () { pstore(pload()-1); }\n    void operator++ (int) { pstore(pload()+1); }\n    void operator-- (int) { pstore(pload()-1); }\n\n    // Equals operator: first downcast to T and then compare\n    bool operator == (const T& otherval) const { return pload() == otherval; }\n\n    // Difference operator: first downcast to T and then compare\n    bool operator != (const T& otherval) const { return pload() != otherval; }\n\n    // Relational operators\n    bool operator < (const T& rhs) { return pload() < rhs; }\n    bool operator > (const T& rhs) { return pload() > rhs; }\n    bool operator <= (const T& rhs) { return pload() <= rhs; }\n    bool operator >= (const T& rhs) { return pload() >= rhs; }\n\n    // Operator arrow ->\n    T operator->() { return pload(); }\n\n    // Copy constructor\n    tmtype<T>(const tmtype<T>& other) { pstore(other.pload()); }\n\n    // Assignment operator from an tmtype\n    tmtype<T>& operator=(const tmtype<T>& other) {\n        pstore(other.pload());\n        return *this;\n    }\n\n    // Assignment operator from a value\n    tmtype<T>& operator=(T value) {\n        pstore(value);\n        return *this;\n    }\n\n    // Operator &\n    T* operator&() {\n        return (T*)this;\n    }\n\n    // Meant to be called when know we're the only ones touching\n    // these contents, for example, in the constructor of an object, before\n    // making the object visible to other threads.\n    inline void isolated_store(T newVal) {\n        tmtypebase<T>::val.store((uint64_t)newVal, std::memory_order_relaxed);\n    }\n\n    // We don't need to check curTx here because we're not de-referencing\n    // the val. It's only after a load() that the val may be de-referenced\n    // (in user code), therefore we do the check on load() only.\n    inline void pstore(T newVal) {\n        OpData* const myopd = tl_opdata;\n        if (myopd == nullptr) { // Looks like we're outside a transaction\n            tmtypebase<T>::val.store((uint64_t)newVal, std::memory_order_relaxed);\n        } else {\n            gOFLF.writeSets[tl_tcico.tid].addOrReplace(this, (uint64_t)newVal);\n        }\n    }\n\n    // We have to check if there is a new ongoing transaction and if so, abort\n    // this execution immediately for two reasons:\n    // 1. Memory Reclamation: the val we're returning may be a pointer to an\n    // object that has since been retired and deleted, therefore we can't allow\n    // user code to de-reference it;\n    // 2. Invariant Conservation: The val we're reading may be from a newer\n    // transaction, which implies that it may break an invariant in the user code.\n    // See examples of invariant breaking in this post:\n    // http://concurrencyfreaks.com/2013/11/stampedlocktryoptimisticread-and.html\n    inline T pload() const {\n        T lval = (T)tmtypebase<T>::val.load(std::memory_order_acquire);\n        OpData* const myopd = tl_opdata;\n        if (myopd == nullptr) return lval;\n        if ((uint8_t*)this < PREGION_ADDR || (uint8_t*)this > PREGION_END) return lval;\n        uint64_t lseq = tmtypebase<T>::seq.load(std::memory_order_acquire);\n        if (lseq > trans2seq(myopd->curTx)) throw AbortedTxException;\n        if (tl_is_read_only) return lval;\n        return (T)gOFLF.writeSets[tl_tcico.tid].lookupAddr(this, (uint64_t)lval);\n    }\n};\n\n\n//\n// Wrapper methods to the global TM instance. The user should use these:\n//\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gOFLF.transaction<R>(func); }\ntemplate<typename R, typename F> static R readTx(F&& func) { return gOFLF.transaction<R>(func); }\ntemplate<typename F> static void updateTx(F&& func) { gOFLF.transaction(func); }\ntemplate<typename F> static void readTx(F&& func) { gOFLF.transaction(func); }\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return OneFileLF::tmNew<T>(std::forward<Args>(args)...); }\ntemplate<typename T> void tmDelete(T* obj) { OneFileLF::tmDelete<T>(obj); }\ntemplate<typename T> static T* get_object(int idx) { return OneFileLF::get_object<T>(idx); }\ntemplate<typename T> static void put_object(int idx, T* obj) { OneFileLF::put_object<T>(idx, obj); }\ninline static void* tmMalloc(size_t size) { return OneFileLF::tmMalloc(size); }\ninline static void tmFree(void* obj) { OneFileLF::tmFree(obj); }\n\n\n//\n// Place these in a .cpp if you include this header from multiple files (compilation units)\n//\nOneFileLF gOFLF {};\nthread_local OpData* tl_opdata {nullptr};\n// Global/singleton to hold all the thread registry functionality\nThreadRegistry gThreadRegistry {};\n// During a transaction, this is true up until the first store()\nthread_local bool tl_is_read_only {false};\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\nthread_local ThreadCheckInCheckOut tl_tcico {};\n// Helper function for thread de-registration\nvoid thread_registry_deregister_thread(const int tid) {\n    gThreadRegistry.deregister_thread(tid);\n}\n\n}\n#endif /* _PERSISTENT_ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_H_ */\n"
  },
  {
    "path": "ptms/OneFilePTMWF.hpp",
    "content": "/*\n * Copyright 2017-2019\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Nachshon Cohen <nachshonc@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.txt\n */\n#ifndef _PERSISTENT_ONE_FILE_WAIT_FREE_TRANSACTIONAL_MEMORY_H_\n#define _PERSISTENT_ONE_FILE_WAIT_FREE_TRANSACTIONAL_MEMORY_H_\n\n#include <atomic>\n#include <cassert>\n#include <iostream>\n#include <vector>\n#include <functional>\n#include <cstring>\n#include <sys/mman.h>   // Needed if we use mmap()\n#include <sys/types.h>  // Needed by open() and close()\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>     // Needed by close()\n\n// Please keep this file in sync (as much as possible) with stms/OneFileWF.hpp\n\n// Macros needed for persistence\n#ifdef PWB_IS_CLFLUSH\n  /*\n   * More info at http://elixir.free-electrons.com/linux/latest/source/arch/x86/include/asm/special_insns.h#L213\n   * Intel programming manual at https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf\n   * Use these for Broadwell CPUs (cervino server)\n   */\n  #define PWB(addr)              __asm__ volatile(\"clflush (%0)\" :: \"r\" (addr) : \"memory\")                      // Broadwell only works with this.\n  #define PFENCE()               {}                                                                             // No ordering fences needed for CLFLUSH (section 7.4.6 of Intel manual)\n  #define PSYNC()                {}                                                                             // For durability it's not obvious, but CLFLUSH seems to be enough, and PMDK uses the same approach\n#elif PWB_IS_CLWB\n  /* Use this for CPUs that support clwb, such as the SkyLake SP series (c5 compute intensive instances in AWS are an example of it) */\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; xsaveopt %0\" : \"+m\" (*(volatile char *)(addr)))  // clwb() only for Ice Lake onwards\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#elif PWB_IS_NOP\n  /* pwbs are not needed for shared memory persistency (i.e. persistency across process failure) */\n  #define PWB(addr)              {}\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#elif PWB_IS_CLFLUSHOPT\n  /* Use this for CPUs that support clflushopt, which is most recent x86 */\n  #define PWB(addr)              __asm__ volatile(\".byte 0x66; clflush %0\" : \"+m\" (*(volatile char *)(addr)))    // clflushopt (Kaby Lake)\n  #define PFENCE()               __asm__ volatile(\"sfence\" : : : \"memory\")\n  #define PSYNC()                __asm__ volatile(\"sfence\" : : : \"memory\")\n#else\n#error \"You must define what PWB is. Choose PWB_IS_CLFLUSHOPT if you don't know what your CPU is capable of\"\n#endif\n\n\n\n/*\n * Differences between POneFileWF and the non-persistent OneFileWF:\n * - A secondary redo log (PWriteSet) is placed in persistent memory before attempting a 'commit'.\n * - The set of the request in helpApply() is always done with a CAS to enforce ordering on the PWBs of the DCAS;\n * - The persistent logs are allocated in PM, same as all user allocations from tmNew(), 'curTx', and 'request'\n */\nnamespace pofwf {\n\n//\n// User configurable variables.\n// Feel free to change these if you need larger transactions, more allocations per transacation, or more threads.\n//\n\n// Maximum number of registered threads that can execute transactions\nstatic const int REGISTRY_MAX_THREADS = 128;\n// Maximum number of stores in the WriteSet per transaction\nstatic const uint64_t TX_MAX_STORES = 40*1024;\n// Number of buckets in the hashmap of the WriteSet.\nstatic const uint64_t HASH_BUCKETS = 2048;\n\n// Persistent-specific configuration\n// Name of persistent file mapping\nstatic const char * PFILE_NAME = \"/dev/shm/ponefilewf_shared\";\n// Start address of mapped persistent memory\nstatic uint8_t* PREGION_ADDR = (uint8_t*)0x7ff000000000;\n// Size of persistent memory. Part of it will be used by the redo logs\nstatic const uint64_t PREGION_SIZE = 1024*1024*1024ULL;    // 1 GB by default\n// End address of mapped persistent memory\nstatic uint8_t* PREGION_END = (PREGION_ADDR+PREGION_SIZE);\n// Maximum number of root pointers available for the user\nstatic const uint64_t MAX_ROOT_POINTERS = 100;\n\n\n// DCAS / CAS2 macro\n#define DCAS(ptr, o1, o2, n1, n2)                               \\\n({                                                              \\\n    char __ret;                                                 \\\n    __typeof__(o2) __junk;                                      \\\n    __typeof__(*(ptr)) __old1 = (o1);                           \\\n    __typeof__(o2) __old2 = (o2);                               \\\n    __typeof__(*(ptr)) __new1 = (n1);                           \\\n    __typeof__(o2) __new2 = (n2);                               \\\n    asm volatile(\"lock cmpxchg16b %2;setz %1\"                   \\\n                   : \"=d\"(__junk), \"=a\"(__ret), \"+m\" (*ptr)     \\\n                   : \"b\"(__new1), \"c\"(__new2),                  \\\n                     \"a\"(__old1), \"d\"(__old2));                 \\\n    __ret; })\n\n\n// Functions to convert between a transaction identifier (uint64_t) and a pair of {sequence,index}\nstatic inline uint64_t seqidx2trans(uint64_t seq, uint64_t idx) {\n    return (seq << 10) | idx;\n}\nstatic inline uint64_t trans2seq(uint64_t trans) {\n    return trans >> 10;\n}\nstatic inline uint64_t trans2idx(uint64_t trans) {\n    return trans & 0x3FF; // 10 bits\n}\n\n// Flush each cache line in a range\nstatic inline void flushFromTo(void* from, void* to) noexcept {\n    const uint64_t cache_line_size = 64;\n    uint8_t* ptr = (uint8_t*)(((uint64_t)from) & (~(cache_line_size-1)));\n    for (; ptr < (uint8_t*)to; ptr += cache_line_size) PWB(ptr);\n}\n\n\n//\n// Thread Registry stuff\n//\nextern void thread_registry_deregister_thread(const int tid);\n\n// An helper class to do the checkin and checkout of the thread registry\nstruct ThreadCheckInCheckOut {\n    static const int NOT_ASSIGNED = -1;\n    int tid { NOT_ASSIGNED };\n    ~ThreadCheckInCheckOut() {\n        if (tid == NOT_ASSIGNED) return;\n        thread_registry_deregister_thread(tid);\n    }\n};\n\nextern thread_local ThreadCheckInCheckOut tl_tcico;\n\n// Forward declaration of global/singleton instance\nclass ThreadRegistry;\nextern ThreadRegistry gThreadRegistry;\n\n/*\n * <h1> Registry for threads </h1>\n *\n * This is singleton type class that allows assignement of a unique id to each thread.\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\n * corresponding slot to be used by a later thread.\n */\nclass ThreadRegistry {\nprivate:\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\n\npublic:\n    ThreadRegistry() {\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\n            usedTID[it].store(false, std::memory_order_relaxed);\n        }\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    int register_thread_new(void) {\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\n            bool unused = false;\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\n            // Increase the current maximum to cover our thread id\n            int curMax = maxTid.load();\n            while (curMax <= tid) {\n                maxTid.compare_exchange_strong(curMax, tid+1);\n                curMax = maxTid.load();\n            }\n            tl_tcico.tid = tid;\n            return tid;\n        }\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\n        assert(false);\n    }\n\n    // Progress condition: wait-free population oblivious\n    inline void deregister_thread(const int tid) {\n        usedTID[tid].store(false, std::memory_order_release);\n    }\n\n    // Progress condition: wait-free population oblivious\n    static inline uint64_t getMaxThreads(void) {\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    static inline int getTID(void) {\n        int tid = tl_tcico.tid;\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\n        return gThreadRegistry.register_thread_new();\n    }\n};\n\n\n// Each object tracked by Hazard Eras needs to have tmbase as one of its base classes.\nstruct tmbase {\n    uint64_t newEra_ {0};        // Filled by tmNew() or tmMalloc()\n    uint64_t delEra_ {0};        // Filled by tmDelete() or tmFree()\n};\n\n\n// A wrapper to std::function so that we can track it with Hazard Eras\nstruct TransFunc : public tmbase {\n    std::function<uint64_t()> func;\n    template<typename F> TransFunc(F&& f) : func{f} { }\n};\n\n\n// This is a specialized implementation of Hazard Eras meant to be used in the OneFile STM.\n// Hazard Eras is a lock-free memory reclamation technique described here:\n// https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf\n// https://dl.acm.org/citation.cfm?id=3087588\n//\n// We're using OF::curTx.seq as the global era.\n//\n// This implementation is different from the lock-free OneFile STM because we need\n// to track the lifetime of the std::function objects where the lambdas are put.\nclass HazardErasOF {\nprivate:\n    static const uint64_t                    NOERA = 0;\n    static const int                         CLPAD = 128/sizeof(std::atomic<uint64_t>);\n    static const int                         THRESHOLD_R = 0; // This is named 'R' in the HP paper\n    const unsigned int                       maxThreads;\n    alignas(128) std::atomic<uint64_t>*      he;\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\n    alignas(128) std::vector<TransFunc*>     retiredListTx[REGISTRY_MAX_THREADS*CLPAD];\n\npublic:\n    HazardErasOF(unsigned int maxThreads=REGISTRY_MAX_THREADS) : maxThreads{maxThreads} {\n        he = new std::atomic<uint64_t>[REGISTRY_MAX_THREADS*CLPAD];\n        for (unsigned it = 0; it < REGISTRY_MAX_THREADS; it++) {\n            he[it*CLPAD].store(NOERA, std::memory_order_relaxed);\n            retiredListTx[it*CLPAD].reserve(REGISTRY_MAX_THREADS);\n        }\n    }\n\n    ~HazardErasOF() {\n        // Clear the objects in the retired lists\n        for (unsigned it = 0; it < maxThreads; it++) {\n            for (unsigned iret = 0; iret < retiredListTx[it*CLPAD].size(); iret++) {\n                TransFunc* tx = retiredListTx[it*CLPAD][iret];\n                delete tx;\n            }\n        }\n        delete[] he;\n    }\n\n    // Progress condition: wait-free population oblivious\n    inline void clear(const int tid) {\n        he[tid*CLPAD].store(NOERA, std::memory_order_release);\n    }\n\n    // Progress condition: wait-free population oblivious\n    inline void set(uint64_t trans, const int tid) {\n        he[tid*CLPAD].store(trans2seq(trans));\n    }\n\n    // Progress condition: wait-free population oblivious\n    inline void addToRetiredListTx(TransFunc* tx, const int tid) {\n        retiredListTx[tid*CLPAD].push_back(tx);\n    }\n\n    /**\n     * Progress condition: bounded wait-free\n     *\n     * Attemps to delete the no-longer-in-use objects in the retired list.\n     * We need to pass the currEra coming from the seq of the currTx so that\n     * the objects from the current transaction don't get deleted.\n     *\n     * TODO: consider using erase() with std::remove_if()\n     */\n    void clean(uint64_t curEra, const int tid) {\n        for (unsigned iret = 0; iret < retiredListTx[tid*CLPAD].size();) {\n            TransFunc* tx = retiredListTx[tid*CLPAD][iret];\n            if (canDelete(curEra, tx)) {\n                retiredListTx[tid*CLPAD].erase(retiredListTx[tid*CLPAD].begin() + iret);\n                delete tx;\n                continue;\n            }\n            iret++;\n        }\n    }\n\n    // Progress condition: wait-free bounded (by the number of threads)\n    inline bool canDelete(uint64_t curEra, tmbase* del) {\n        // We can't delete objects from the current transaction\n        if (del->delEra_ == curEra) return false;\n        for (unsigned it = 0; it < ThreadRegistry::getMaxThreads(); it++) {\n            const auto era = he[it*CLPAD].load(std::memory_order_acquire);\n            if (era == NOERA || era < del->newEra_ || era > del->delEra_) continue;\n            return false;\n        }\n        return true;\n    }\n};\n\n\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\ntemplate<typename T> struct tmtype {\n    // Stores the actual value as an atomic\n    std::atomic<uint64_t>  val;\n    // Lets hope this comes immediately after 'val' in memory mapping, otherwise the DCAS() will fail\n    std::atomic<uint64_t>  seq;\n\n    tmtype() { }\n\n    tmtype(T initVal) { pstore(initVal); }\n\n    // Casting operator\n    operator T() { return pload(); }\n\n    // Prefix increment operator: ++x\n    void operator++ () { pstore(pload()+1); }\n    // Prefix decrement operator: --x\n    void operator-- () { pstore(pload()-1); }\n    void operator++ (int) { pstore(pload()+1); }\n    void operator-- (int) { pstore(pload()-1); }\n\n    // Equals operator: first downcast to T and then compare\n    bool operator == (const T& otherval) const { return pload() == otherval; }\n\n    // Difference operator: first downcast to T and then compare\n    bool operator != (const T& otherval) const { return pload() != otherval; }\n\n    // Relational operators\n    bool operator < (const T& rhs) { return pload() < rhs; }\n    bool operator > (const T& rhs) { return pload() > rhs; }\n    bool operator <= (const T& rhs) { return pload() <= rhs; }\n    bool operator >= (const T& rhs) { return pload() >= rhs; }\n\n    // Operator arrow ->\n    T operator->() { return pload(); }\n\n    // Copy constructor\n    tmtype<T>(const tmtype<T>& other) { pstore(other.pload()); }\n\n    // Assignment operator from an tmtype\n    tmtype<T>& operator=(const tmtype<T>& other) {\n        pstore(other.pload());\n        return *this;\n    }\n\n    // Assignment operator from a value\n    tmtype<T>& operator=(T value) {\n        pstore(value);\n        return *this;\n    }\n\n    // Operator &\n    T* operator&() {\n        return (T*)this;\n    }\n\n    // Meant to be called when know we're the only ones touching\n    // these contents, for example, in the constructor of an object, before\n    // making the object visible to other threads.\n    inline void isolated_store(T newVal) {\n        val.store((uint64_t)newVal, std::memory_order_relaxed);\n    }\n\n    // Used only internally to initialize the operations[] array\n    inline void operationsInit() {\n        val.store((uint64_t)nullptr, std::memory_order_relaxed);\n        seq.store(0, std::memory_order_relaxed);\n    }\n\n    // Used only internally to initialize the results[] array\n    inline void resultsInit() {\n        val.store(0, std::memory_order_relaxed);\n        seq.store(1, std::memory_order_relaxed);\n    }\n\n    // Used only internally by updateTx() to determine if the request is opened or not\n    inline uint64_t getSeq() const {\n        return seq.load(std::memory_order_acquire);\n    }\n\n    // Used only internally by updateTx()\n    inline void rawStore(T& newVal, uint64_t lseq) {\n        val.store((uint64_t)newVal, std::memory_order_relaxed);\n        seq.store(lseq, std::memory_order_release);\n    }\n\n    // Methods that are defined later because they have compilation dependencies on gOFWF\n    inline T pload() const;\n    inline bool rawLoad(T& keepVal, uint64_t& keepSeq);\n    inline void pstore(T newVal);\n};\n\n\n/*\n * EsLoco is an Extremely Simple memory aLOCatOr\n *\n * It is based on intrusive singly-linked lists (a free-list), one for each power of two size.\n * All blocks are powers of two, the smallest size enough to contain the desired user data plus the block header.\n * There is an array named 'freelists' where each entry is a pointer to the head of a stack for that respective block size.\n * Blocks are allocated in powers of 2 of words (64bit words).\n * Each block has an header with two words: the size of the node (in words), the pointer to the next node.\n * The minimum block size is 4 words, with 2 for the header and 2 for the user.\n * When there is no suitable block in the freelist, it will create a new block from the remaining pool.\n *\n * EsLoco was designed for usage in PTMs but it doesn't have to be used only for that.\n * Average number of stores for an allocation is 1.\n * Average number of stores for a de-allocation is 2.\n *\n * Memory layout:\n * ------------------------------------------------------------------------\n * | poolTop | freelists[0] ... freelists[61] | ... allocated objects ... |\n * ------------------------------------------------------------------------\n */\ntemplate <template <typename> class P>\nclass EsLoco {\nprivate:\n    struct block {\n        P<block*>   next;   // Pointer to next block in free-list (when block is in free-list)\n        P<uint64_t> size;   // Exponent of power of two of the size of this block in bytes.\n    };\n\n    const bool debugOn = false;\n\n    // Volatile data\n    uint8_t* poolAddr {nullptr};\n    uint64_t poolSize {0};\n\n    // Pointer to array of persistent heads of free-list\n    block* freelists {nullptr};\n    // Volatile pointer to persistent pointer to last unused address (the top of the pool)\n    P<uint8_t*>* poolTop {nullptr};\n\n    // Number of blocks in the freelists array.\n    // Each entry corresponds to an exponent of the block size: 2^4, 2^5, 2^6... 2^40\n    static const int kMaxBlockSize = 50; // 1024 TB of memory should be enough\n\n    // For powers of 2, returns the highest bit, otherwise, returns the next highest bit\n    uint64_t highestBit(uint64_t val) {\n        uint64_t b = 0;\n        while ((val >> (b+1)) != 0) b++;\n        if (val > (1ULL << b)) return b+1;\n        return b;\n    }\n\n    uint8_t* aligned(uint8_t* addr) {\n        return (uint8_t*)((size_t)addr & (~0x3FULL)) + 128;\n    }\n\npublic:\n    void init(void* addressOfMemoryPool, size_t sizeOfMemoryPool, bool clearPool=true) {\n        // Align the base address of the memory pool\n        poolAddr = aligned((uint8_t*)addressOfMemoryPool);\n        poolSize = sizeOfMemoryPool + (uint8_t*)addressOfMemoryPool - poolAddr;\n        // The first thing in the pool is a pointer to the top of the pool\n        poolTop = (P<uint8_t*>*)poolAddr;\n        // The second thing in the pool is the array of freelists\n        freelists = (block*)(poolAddr + sizeof(*poolTop));\n        if (clearPool) {\n            std::memset(poolAddr, 0, poolSize);\n            for (int i = 0; i < kMaxBlockSize; i++) freelists[i].next.pstore(nullptr);\n            // The size of the freelists array in bytes is sizeof(block)*kMaxBlockSize\n            // Align to cache line boundary (DCAS needs 16 byte alignment)\n            poolTop->pstore(aligned(poolAddr + sizeof(*poolTop) + sizeof(block)*kMaxBlockSize));\n        }\n        if (debugOn) printf(\"Starting EsLoco with poolAddr=%p and poolSize=%ld, up to %p\\n\", poolAddr, poolSize, poolAddr+poolSize);\n    }\n\n    // Resets the metadata of the allocator back to its defaults\n    void reset() {\n        std::memset(poolAddr, 0, sizeof(block)*kMaxBlockSize);\n        poolTop->pstore(nullptr);\n    }\n\n    // Returns the number of bytes that may (or may not) have allocated objects, from the base address to the top address\n    uint64_t getUsedSize() {\n        return poolTop->pload() - poolAddr;\n    }\n\n    // Takes the desired size of the object in bytes.\n    // Returns pointer to memory in pool, or nullptr.\n    // Does on average 1 store to persistent memory when re-utilizing blocks.\n    void* malloc(size_t size) {\n        P<uint8_t*>* top = (P<uint8_t*>*)(((uint8_t*)poolTop));\n        block* flists = (block*)(((uint8_t*)freelists));\n        // Adjust size to nearest (highest) power of 2\n        uint64_t bsize = highestBit(size + sizeof(block));\n        if (debugOn) printf(\"malloc(%ld) requested,  block size exponent = %ld\\n\", size, bsize);\n        block* myblock = nullptr;\n        // Check if there is a block of that size in the corresponding freelist\n        if (flists[bsize].next.pload() != nullptr) {\n            if (debugOn) printf(\"Found available block in freelist\\n\");\n            // Unlink block\n            myblock = flists[bsize].next;\n            flists[bsize].next = myblock->next;          // pstore()\n        } else {\n            if (debugOn) printf(\"Creating new block from top, currently at %p\\n\", top->pload());\n            // Couldn't find a suitable block, get one from the top of the pool if there is one available\n            if (top->pload() + (1<<bsize) > poolSize + poolAddr) {\n                printf(\"EsLoco: Out of memory for %ld bytes allocation\\n\", size);\n                return nullptr;\n            }\n            myblock = (block*)top->pload();\n            top->pstore(top->pload() + (1<<bsize));      // pstore()\n            myblock->size = bsize;                       // pstore()\n        }\n        if (debugOn) printf(\"returning ptr = %p\\n\", (void*)((uint8_t*)myblock + sizeof(block)));\n        // Return the block, minus the header\n        return (void*)((uint8_t*)myblock + sizeof(block));\n    }\n\n    // Takes a pointer to an object and puts the block on the free-list.\n    // Does on average 2 stores to persistent memory.\n    void free(void* ptr) {\n        if (ptr == nullptr) return;\n        block* flists = (block*)(((uint8_t*)freelists));\n        block* myblock = (block*)((uint8_t*)ptr - sizeof(block));\n        if (debugOn) printf(\"free(%p)  block size exponent = %ld\\n\", ptr, myblock->size.pload());\n        // Insert the block in the corresponding freelist\n        myblock->next = flists[myblock->size].next;      // pstore()\n        flists[myblock->size].next = myblock;            // pstore()\n    }\n};\n\n\n// An entry in the persistent write-set (compacted for performance reasons)\nstruct PWriteSetEntry {\n    void*    addr;  // Address of value+sequence to change\n    uint64_t val;   // Desired value to change to\n};\n\n\n// The persistent write-set\nstruct PWriteSet {\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\n    std::atomic<uint64_t> request {0};            // Can be moved to CLOSED by other threads, using a CAS\n    PWriteSetEntry        plog[TX_MAX_STORES];    // Redo log of stores\n\n    // Applies all entries in the log. Called only by recover() which is non-concurrent.\n    void applyFromRecover() {\n        // We're assuming that 'val' is the size of a uint64_t\n        for (uint64_t i = 0; i < numStores; i++) {\n            *((uint64_t*)plog[i].addr) = plog[i].val;\n            PWB(plog[i].addr);\n        }\n    }\n};\n\n\n// The persistent metadata is a 'header' that contains all the logs and the persistent curTx variable.\n// It is located at the start of the persistent region, and the remaining region contains the data available for the allocator to use.\nstruct PMetadata {\n    static const uint64_t   MAGIC_ID = 0x1337babe;\n    std::atomic<uint64_t>   curTx {seqidx2trans(1,0)};\n    std::atomic<uint64_t>   pad1[15];\n    tmtype<void*>           rootPtrs[MAX_ROOT_POINTERS];\n    PWriteSet               plog[REGISTRY_MAX_THREADS];\n    uint64_t                id {0};\n    uint64_t                pad2 {0};\n};\n\n\n// A single entry in the write-set\nstruct WriteSetEntry {\n    void*          addr {nullptr};  // Address of value+sequence to change\n    uint64_t       val;             // Desired value to change to\n    WriteSetEntry* next {nullptr};  // Pointer to next node in the (intrusive) hash map\n};\n\nextern thread_local bool tl_is_read_only;\n\n\n// The write-set is a log of the words modified during the transaction.\n// This log is an array with an intrusive hashmap of size HASH_BUCKETS.\nstruct WriteSet {\n    static const uint64_t MAX_ARRAY_LOOKUP = 30;  // Beyond this, it seems to be faster to use the hashmap\n    WriteSetEntry         log[TX_MAX_STORES];     // Redo log of stores\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\n    WriteSetEntry*        buckets[HASH_BUCKETS];  // Intrusive HashMap for fast lookup in large(r) transactions\n\n    WriteSet() {\n        numStores = 0;\n        for (int i = 0; i < HASH_BUCKETS; i++) buckets[i] = &log[TX_MAX_STORES-1];\n    }\n\n    // Copies the current write set to persistent memory\n    inline void persistAndFlushLog(PWriteSet* const pwset) {\n        for (uint64_t i = 0; i < numStores; i++) {\n            pwset->plog[i].addr = log[i].addr;\n            pwset->plog[i].val = log[i].val;\n        }\n        pwset->numStores = numStores;\n        // Flush the log and the numStores variable\n        flushFromTo(&pwset->numStores, &pwset->plog[numStores+1]);\n    }\n\n    // Uses the log to flush the modifications to NVM.\n    // We assume tmtype does not cross cache line boundaries.\n    inline void flushModifications() {\n        for (uint64_t i = 0; i < numStores; i++) PWB(log[i].addr);\n    }\n\n    // Each address on a different bucket\n    inline uint64_t hash(const void* addr) const {\n        return (((uint64_t)addr) >> 3) % HASH_BUCKETS;\n    }\n\n    // Adds a modification to the redo log\n    inline void addOrReplace(void* addr, uint64_t val) {\n        if (tl_is_read_only) tl_is_read_only = false;\n        const uint64_t hashAddr = hash(addr);\n        if ((((size_t)addr & (~0xFULL)) != (size_t)addr)) {\n            printf(\"Alignment ERROR in addOrReplace() at address %p\\n\", addr);\n            assert(false);\n        }\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < numStores; idx++) {\n                if (log[idx].addr == addr) {\n                    log[idx].val = val;\n                    return;\n                }\n            }\n        } else {\n            // Lookup in hashmap\n            WriteSetEntry* be = buckets[hashAddr];\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\n                while (be != nullptr) {\n                    if (be->addr == addr) {\n                        be->val = val;\n                        return;\n                    }\n                    be = be->next;\n                }\n            }\n        }\n        // Add to array\n        WriteSetEntry* e = &log[numStores++];\n        assert(numStores < TX_MAX_STORES);\n        e->addr = addr;\n        e->val = val;\n        // Add to hashmap\n        WriteSetEntry* be = buckets[hashAddr];\n        // Clear if entry is from previous tx\n        e->next = (be < e && hash(be->addr) == hashAddr) ? be : nullptr;\n        buckets[hashAddr] = e;\n    }\n\n    // Does a lookup on the WriteSet for an addr.\n    // If the numStores is lower than MAX_ARRAY_LOOKUP, the lookup is done on the log, otherwise, the lookup is done on the hashmap.\n    // If it's not in the write-set, return lval.\n    inline uint64_t lookupAddr(const void* addr, uint64_t lval) {\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < numStores; idx++) {\n                if (log[idx].addr == addr) return log[idx].val;\n            }\n        } else {\n            // Lookup in hashmap\n            const uint64_t hashAddr = hash(addr);\n            WriteSetEntry* be = buckets[hashAddr];\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\n                while (be != nullptr) {\n                    if (be->addr == addr) return be->val;\n                    be = be->next;\n                }\n            }\n        }\n        return lval;\n    }\n\n    // Returns true if there is a predecent log entry for the same cache line\n    inline bool lookupCacheLine(void* addr, int myidx) {\n        size_t cl = (size_t)addr & (~0x3F);\n        if (numStores < MAX_ARRAY_LOOKUP) {\n            // Lookup in array\n            for (unsigned int idx = 0; idx < myidx; idx++) {\n                if ((size_t)log[idx].addr & (~0x3F) == cl) return true;\n            }\n        } else {\n            // Lookup in hashmap. If it has the same cache line, it must be in this bucket\n            WriteSetEntry* be = buckets[hash(addr)];\n            if (be < &log[numStores]) {\n                while (be != nullptr) {\n                    if ((size_t)be->addr & (~0x3F) == cl) return true;\n                    be = be->next;\n                }\n            }\n        }\n        return false;\n    }\n\n    // Assignment operator, used when making a copy of a WriteSet to help another thread\n    WriteSet& operator = (const WriteSet &other) {\n        numStores = other.numStores;\n        for (uint64_t i = 0; i < numStores; i++) log[i] = other.log[i];\n        return *this;\n    }\n\n    // Applies all entries in the log as DCASes.\n    // Seq must match for DCAS to succeed. This method is on the \"hot-path\".\n    inline void apply(uint64_t seq, const int tid) {\n        for (uint64_t i = 0; i < numStores; i++) {\n            // Use an heuristic to give each thread 8 consecutive DCAS to apply\n            WriteSetEntry& e = log[(tid*8 + i) % numStores];\n            tmtype<uint64_t>* tmte = (tmtype<uint64_t>*)e.addr;\n            uint64_t lval = tmte->val.load(std::memory_order_acquire);\n            uint64_t lseq = tmte->seq.load(std::memory_order_acquire);\n            if (lseq < seq) DCAS((uint64_t*)e.addr, lval, lseq, e.val, seq);\n        }\n    }\n};\n\n\n// Forward declaration\nstruct OpData;\n// This is used by addOrReplace() to know which OpData instance to use for the current transaction\nextern thread_local OpData* tl_opdata;\n\n\n// Its purpose is to hold thread-local data\nstruct OpData {\n    uint64_t      curTx {0};              // Used during a transaction to keep the value of curTx read in beginTx() (owner thread only)\n    uint64_t      nestedTrans {0};        // Thread-local: Number of nested transactions\n    PWriteSet*    pWriteSet {nullptr};    // Pointer to the redo log in persistent memory\n    uint64_t      padding[16-3];          // Padding to avoid false-sharing in nestedTrans and curTx\n};\n\n\n// Used to identify aborted transactions\nstruct AbortedTx {};\nstatic constexpr AbortedTx AbortedTxException {};\n\nclass OneFileWF;\nextern OneFileWF gOFWF;\n\n\n/**\n * <h1> OneFile STM (Wait-Free) </h1>\n *\n * OneFile is a Software Transacional Memory with wait-free progress, meant to\n * implement wait-free data structures.\n * OneFile is a word-based STM and it uses double-compare-and-swap (DCAS).\n *\n * Right now it has several limitations, some will be fixed in the future, some may be hard limitations of this approach:\n * - We can't have stack allocated tmtype<> variables. For example, we can't created inside a transaction \"tmtpye<uint64_t> tmp = a;\",\n *   it will give weird errors because of stack allocation.\n * - We need DCAS but it can be emulated with LL/SC or even with single-word CAS\n *   if we do redirection to a (lock-free) pool with SeqPtrs;\n */\nclass OneFileWF {\nprivate:\n    static const bool                    debug = false;\n    OpData                              *opData;\n    int                                  fd {-1};\n    HazardErasOF                         he {REGISTRY_MAX_THREADS};\n    // Maximum number of times a reader will fail a transaction before turning into an updateTx()\n    static const int                     MAX_READ_TRIES = 4;\n    // Member variables for wait-free consensus\n    tmtype<TransFunc*>*                  operations;  // We've tried adding padding here but it didn't make a difference\n    tmtype<uint64_t>*                    results;\n    uint64_t                             padding[16];\npublic:\n    EsLoco<tmtype>                       esloco {};\n    PMetadata*                           pmd {nullptr};\n    std::atomic<uint64_t>*               curTx {nullptr};              // Pointer to persistent memory location of curTx (it's in PMetadata)\n    WriteSet*                            writeSets;                    // Two write-sets for each thread\n\n    OneFileWF() {\n        opData = new OpData[REGISTRY_MAX_THREADS];\n        writeSets = new WriteSet[REGISTRY_MAX_THREADS];\n        operations = new tmtype<TransFunc*>[REGISTRY_MAX_THREADS];\n        for (unsigned i = 0; i < REGISTRY_MAX_THREADS; i++) operations[i].operationsInit();\n        results = new tmtype<uint64_t>[REGISTRY_MAX_THREADS];\n        for (unsigned i = 0; i < REGISTRY_MAX_THREADS; i++) results[i].resultsInit();\n        mapPersistentRegion(PFILE_NAME, PREGION_ADDR, PREGION_SIZE);\n    }\n\n    ~OneFileWF() {\n        delete[] opData;\n        delete[] writeSets;\n        delete[] operations;\n        delete[] results;\n    }\n\n    static std::string className() { return \"OneFilePTM-WF\"; }\n\n    void mapPersistentRegion(const char* filename, uint8_t* regionAddr, const uint64_t regionSize) {\n        // Check that the header with the logs leaves at least half the memory available to the user\n        if (sizeof(PMetadata) > regionSize/2) {\n            printf(\"ERROR: the size of the logs in persistent memory is so large that it takes more than half the whole persistent memory\\n\");\n            printf(\"Please reduce some of the settings in OneFilePTM.hpp and try again\\n\");\n            assert(false);\n        }\n        bool reuseRegion = false;\n        // Check if the file already exists or not\n        struct stat buf;\n        if (stat(filename, &buf) == 0) {\n            // File exists\n            fd = open(filename, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            reuseRegion = true;\n        } else {\n            // File doesn't exist\n            fd = open(filename, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            if (lseek(fd, regionSize-1, SEEK_SET) == -1) {\n                perror(\"lseek() error\");\n            }\n            if (write(fd, \"\", 1) == -1) {\n                perror(\"write() error\");\n            }\n        }\n        // mmap() memory range\n        void* got_addr = (uint8_t *)mmap(regionAddr, regionSize, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);\n        if (got_addr == MAP_FAILED || got_addr != regionAddr) {\n            printf(\"got_addr = %p  instead of %p\\n\", got_addr, regionAddr);\n            perror(\"ERROR: mmap() is not working !!! \");\n            assert(false);\n        }\n        // Check if the header is consistent and only then can we attempt to re-use, otherwise we clear everything that's there\n        pmd = reinterpret_cast<PMetadata*>(regionAddr);\n        if (reuseRegion) reuseRegion = (pmd->id == PMetadata::MAGIC_ID);\n        // Map pieces of persistent Metadata to pointers in volatile memory\n        for (uint64_t i = 0; i < REGISTRY_MAX_THREADS; i++) opData[i].pWriteSet = &(pmd->plog[i]);\n        curTx = &(pmd->curTx);\n        // If the file has just been created or if the header is not consistent, clear everything.\n        // Otherwise, re-use and recover to a consistent state.\n        if (reuseRegion) {\n            esloco.init(regionAddr+sizeof(PMetadata), regionSize-sizeof(PMetadata), false);\n            //recover(); // Not needed on x86\n        } else {\n            // Start by resetting all tmtypes::seq in the metadata region\n            std::memset(regionAddr, 0, sizeof(PMetadata));\n            new (regionAddr) PMetadata();\n            esloco.init(regionAddr+sizeof(PMetadata), regionSize-sizeof(PMetadata), true);\n            PFENCE();\n            pmd->id = PMetadata::MAGIC_ID;\n            PWB(&pmd->id);\n            PFENCE();\n        }\n    }\n\n    // My transaction was successful, it's my duty to cleanup any retired objects.\n    // This is called by the owner thread when the transaction succeeds, to pass\n    // the retired objects to Hazard Eras. We can't delete the objects\n    // immediately because there might be other threads trying to apply our log\n    // which may (or may not) contain addresses inside the objects in this list.\n    void retireRetiresFromLog(OpData& myopd, const int tid) {\n        uint64_t lseq = trans2seq(curTx->load(std::memory_order_acquire));\n        // Start a cleaning phase, scanning to see which ones can be removed\n        he.clean(lseq, tid);\n    }\n\n    // Progress condition: wait-free population-oblivious\n    // Attempts to publish our write-set (commit the transaction) and then applies the write-set.\n    // Returns true if my transaction was committed.\n    inline bool commitTx(OpData& myopd, const int tid) {\n        // If it's a read-only transaction, then commit immediately\n        if (writeSets[tid].numStores == 0) return true;\n        // Give up if the curTx has changed sinced our transaction started\n        if (myopd.curTx != curTx->load(std::memory_order_acquire)) return false;\n        // Move our request to OPEN, using the sequence of the previous transaction +1\n        const uint64_t seq = trans2seq(myopd.curTx);\n        const uint64_t newTx = seqidx2trans(seq+1,tid);\n        myopd.pWriteSet->request.store(newTx, std::memory_order_release);\n        // Copy the write-set to persistent memory and flush it\n        writeSets[tid].persistAndFlushLog(myopd.pWriteSet);\n        // Attempt to CAS curTx to our OpDesc instance (tid) incrementing the seq in it\n        uint64_t lcurTx = myopd.curTx;\n        if (debug) printf(\"tid=%i  attempting CAS on curTx from (%ld,%ld) to (%ld,%ld)\\n\", tid, trans2seq(lcurTx), trans2idx(lcurTx), seq+1, (uint64_t)tid);\n        if (!curTx->compare_exchange_strong(lcurTx, newTx)) return false;\n        PWB(curTx);\n        // Execute each store in the write-set using DCAS() and close the request\n        helpApply(newTx, tid);\n        retireRetiresFromLog(myopd, tid);\n        // We should need a PSYNC() here to provide durable linearizabilty, but the CAS of the state in helpApply() acts as a PSYNC() (on x86).\n        if (debug) printf(\"Committed transaction (%ld,%ld) with %ld stores\\n\", seq+1, (uint64_t)tid, writeSets[tid].numStores);\n        return true;\n    }\n\n    // Progress condition: wait-free (bounded by the number of threads)\n    // Applies a mutative transaction or gets another thread with an ongoing\n    // transaction to apply it.\n    // If three 'seq' have passed since the transaction when we published our\n    // function, then the worst-case scenario is: the first transaction does not\n    // see our function; the second transaction transforms our function\n    // but doesn't apply the corresponding write-set; the third transaction\n    // guarantees that the log of the second transaction is applied.\n    inline void innerUpdateTx(OpData& myopd, TransFunc* funcptr, const int tid) {\n        ++myopd.nestedTrans;\n        if (debug) printf(\"updateTx(tid=%d)\\n\", tid);\n        // We need an era from before the 'funcptr' is announced, so as to protect it\n        uint64_t firstEra = trans2seq(curTx->load(std::memory_order_acquire));\n        operations[tid].rawStore(funcptr, results[tid].getSeq());\n        tl_opdata = &myopd;\n        // Check 3x for the completion of our function because we don't have a fence\n        // on operations[tid].rawStore(), otherwise it would be just 2x.\n        for (int iter = 0; iter < 4; iter++) {\n            // An update transaction is read-only until it does the first store()\n            tl_is_read_only = true;\n            // Clear the logs of the previous transaction\n            writeSets[tid].numStores = 0;\n            myopd.curTx = curTx->load(std::memory_order_acquire);\n            // Optimization: if my request is answered, then my tx is committed\n            if (results[tid].getSeq() > operations[tid].getSeq()) break;\n            helpApply(myopd.curTx, tid);\n            // Reset the write-set after (possibly) helping another transaction complete\n            writeSets[tid].numStores = 0;\n            // Use HE to protect the TransFunc we're going to access\n            he.set(myopd.curTx, tid);\n            if (myopd.curTx != curTx->load()) continue;\n            try {\n                if (!transformAll(myopd.curTx, tid)) continue;\n            } catch (AbortedTx&) {\n                continue;\n            }\n            if (commitTx(myopd, tid)) break;\n        }\n        tl_opdata = nullptr;\n        --myopd.nestedTrans;\n        he.clear(tid);\n        retireMyFunc(tid, funcptr, firstEra);\n    }\n\n    // Update transaction with non-void return value\n    template<typename R, class F> static R updateTx(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = gOFWF.opData[tid];\n        if (myopd.nestedTrans > 0) return func();\n        // Copy the lambda to a std::function<> and announce a request with the pointer to it\n        gOFWF.innerUpdateTx(myopd, new TransFunc([func] () { return (uint64_t)func(); }), tid);\n        return (R)gOFWF.results[tid].pload();\n    }\n\n    // Update transaction with void return value\n    template<class F> static void updateTx(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = gOFWF.opData[tid];\n        if (myopd.nestedTrans > 0) {\n            func();\n            return;\n        }\n        // Copy the lambda to a std::function<> and announce a request with the pointer to it\n        gOFWF.innerUpdateTx(myopd, new TransFunc([func] () { func(); return 0; }), tid);\n    }\n\n    // Progress condition: wait-free (bounded by the number of threads + MAX_READ_TRIES)\n    template<typename R, class F> R readTransaction(F&& func) {\n        const int tid = ThreadRegistry::getTID();\n        OpData& myopd = opData[tid];\n        if (myopd.nestedTrans > 0) return func();\n        ++myopd.nestedTrans;\n        tl_opdata = &myopd;\n        tl_is_read_only = true;\n        if (debug) printf(\"readTx(tid=%d)\\n\", tid);\n        R retval {};\n        writeSets[tid].numStores = 0;\n        for (int iter = 0; iter < MAX_READ_TRIES; iter++) {\n            myopd.curTx = curTx->load(std::memory_order_acquire);\n            helpApply(myopd.curTx, tid);\n            // Reset the write-set after (possibly) helping another transaction complete\n            writeSets[tid].numStores = 0;\n            // Use HE to protect the objects we're going to access during the simulation\n            he.set(myopd.curTx, tid);\n            if (myopd.curTx != curTx->load()) continue;\n            try {\n                retval = func();\n            } catch (AbortedTx&) {\n                continue;\n            }\n            --myopd.nestedTrans;\n            tl_opdata = nullptr;\n            he.clear(tid);\n            return retval;\n        }\n        if (debug) printf(\"readTx() executed MAX_READ_TRIES, posing as updateTx()\\n\");\n        --myopd.nestedTrans;\n        // Tried too many times unsucessfully, pose as an updateTx()\n        return updateTx<R>(func);\n    }\n\n    template<typename R, typename F> static R readTx(F&& func) { return gOFWF.readTransaction<R>(func); }\n    template<typename F> static void readTx(F&& func) { gOFWF.readTransaction(func); }\n\n    template <typename T, typename... Args> static T* tmNew(Args&&... args) {\n    //template <typename T> static T* tmNew() {\n        T* ptr = (T*)gOFWF.esloco.malloc(sizeof(T));\n        //new (ptr) T;  // new placement\n        new (ptr) T(std::forward<Args>(args)...);\n        return ptr;\n    }\n\n    template<typename T> static void tmDelete(T* obj) {\n        if (obj == nullptr) return;\n        obj->~T(); // Execute destructor as part of the current transaction\n        tmFree(obj);\n    }\n\n    static void* tmMalloc(size_t size) {\n        if (tl_opdata == nullptr) {\n            printf(\"ERROR: Can not allocate outside a transaction\\n\");\n            return nullptr;\n        }\n        void* obj = gOFWF.esloco.malloc(size);\n        return obj;\n    }\n\n    // We assume there is a tmbase allocated in the beginning of the allocation\n    static void tmFree(void* obj) {\n        if (obj == nullptr) return;\n        if (tl_opdata == nullptr) {\n            printf(\"ERROR: Can not de-allocate outside a transaction\\n\");\n            return;\n        }\n        gOFWF.esloco.free(obj);\n    }\n    static void* pmalloc(size_t size) {\n        return gOFWF.esloco.malloc(size);\n    }\n\n    static void pfree(void* obj) {\n        if (obj == nullptr) return;\n        gOFWF.esloco.free(obj);\n    }\n\n    template <typename T> static inline T* get_object(int idx) {\n        tmtype<T*>* ptr = (tmtype<T*>*)&(gOFWF.pmd->rootPtrs[idx]);\n        return ptr->pload();\n    }\n\n    template <typename T> static inline void put_object(int idx, T* obj) {\n        tmtype<T*>* ptr = (tmtype<T*>*)&(gOFWF.pmd->rootPtrs[idx]);\n        ptr->pstore(obj);\n    }\n\nprivate:\n    // Progress condition: wait-free population oblivious\n    inline void helpApply(uint64_t lcurTx, const int tid) {\n        const uint64_t idx = trans2idx(lcurTx);\n        const uint64_t seq = trans2seq(lcurTx);\n        OpData& opd = opData[idx];\n        // Nothing to apply unless the request matches the curTx\n        if (lcurTx != opd.pWriteSet->request.load(std::memory_order_acquire)) return;\n        if (idx != tid) {\n            // Make a copy of the write-set and check if it is consistent\n            writeSets[tid] = writeSets[idx];\n            std::atomic_thread_fence(std::memory_order_acquire);\n            if (lcurTx != curTx->load()) return;\n            if (lcurTx != opd.pWriteSet->request.load(std::memory_order_acquire)) return;\n        }\n        if (debug) printf(\"Applying %ld stores in write-set\\n\", writeSets[tid].numStores);\n        writeSets[tid].apply(seq, tid);\n        writeSets[tid].flushModifications();\n        if (opd.pWriteSet->request.load() == lcurTx) {\n            const uint64_t newReq = seqidx2trans(seq+1,idx);\n            opd.pWriteSet->request.compare_exchange_strong(lcurTx, newReq);\n        }\n    }\n\n    inline void retireMyFunc(const int tid, TransFunc* myfunc, uint64_t firstEra) {\n        myfunc->newEra_ = firstEra;\n        myfunc->delEra_ = trans2seq(curTx->load(std::memory_order_acquire))+1; // Do we really need the +1 ?\n        he.addToRetiredListTx(myfunc, tid);\n    }\n\n    // Aggregate all the functions of the different thread's writeTransaction()\n    // and transform them into to a single log (the current thread's log).\n    // Returns true if all active TransFunc were transformed\n    inline bool transformAll(const uint64_t lcurrTx, const int tid) {\n        for (unsigned i = 0; i < ThreadRegistry::getMaxThreads(); i++) {\n            // Check if the operation of thread i has been applied (has a matching result)\n            TransFunc* txfunc;\n            uint64_t res, operationsSeq, resultSeq;\n            if (!operations[i].rawLoad(txfunc, operationsSeq)) continue;\n            if (!results[i].rawLoad(res, resultSeq)) continue;\n            if (resultSeq > operationsSeq) continue;\n            // Operation has not yet been applied, check that transaction identifier has not changed\n            if (lcurrTx != curTx->load(std::memory_order_acquire)) return false;\n            // Apply the operation of thread i and save result in results[i],\n            // with this store being part of the transaction itself.\n            results[i] = txfunc->func();\n        }\n        return true;\n    }\n\n    // Upon restart, re-applies the last transaction, so as to guarantee that\n    // we have a consistent state in persistent memory.\n    // This is not used on x86 because the DCAS has atomicity writting to persistent memory.\n    void recover() {\n        uint64_t lcurTx = curTx->load(std::memory_order_acquire);\n        opData[trans2idx(lcurTx)].pWriteSet->applyFromRecover();\n        PSYNC();\n    }\n};\n\n\n//\n// Wrapper methods to the global TM instance. The user should use these:\n//\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gOFWF.updateTx<R>(func); }\ntemplate<typename R, typename F> static R readTx(F&& func) { return gOFWF.readTx<R>(func); }\ntemplate<typename F> static void updateTx(F&& func) { gOFWF.updateTx(func); }\ntemplate<typename F> static void readTx(F&& func) { gOFWF.readTx(func); }\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return OneFileWF::tmNew<T>(args...); }\ntemplate<typename T> void tmDelete(T* obj) { OneFileWF::tmDelete<T>(obj); }\ntemplate<typename T> static T* get_object(int idx) { return OneFileWF::get_object<T>(idx); }\ntemplate<typename T> static void put_object(int idx, T* obj) { OneFileWF::put_object<T>(idx, obj); }\ninline void* tmMalloc(size_t size) { return OneFileWF::tmMalloc(size); }\ninline void tmFree(void* obj) { OneFileWF::tmFree(obj); }\n\n\n// We have to check if there is a new ongoing transaction and if so, abort\n// this execution immediately for two reasons:\n// 1. Memory Reclamation: the val we're returning may be a pointer to an\n// object that has since been retired and deleted, therefore we can't allow\n// user code to de-reference it;\n// 2. Invariant Conservation: The val we're reading may be from a newer\n// transaction, which implies that it may break an invariant in the user code.\n// See examples of invariant breaking in this post:\n// http://concurrencyfreaks.com/2013/11/stampedlocktryoptimisticread-and.html\ntemplate<typename T> inline T tmtype<T>::pload() const {\n    T lval = (T)val.load(std::memory_order_acquire);\n    OpData* const myopd = tl_opdata;\n    if (myopd == nullptr) return lval;\n    if ((uint8_t*)this < PREGION_ADDR || (uint8_t*)this > PREGION_END) return lval;\n    uint64_t lseq = seq.load(std::memory_order_acquire);\n    if (lseq > trans2seq(myopd->curTx)) throw AbortedTxException;\n    if (tl_is_read_only) return lval;\n    return (T)gOFWF.writeSets[tl_tcico.tid].lookupAddr(this, (uint64_t)lval);\n}\n\n// This method is meant to be used by the internal consensus mechanism, not by the user.\n// Returns true if the 'val' and 'seq' placed in 'keepVal' and 'keepSeq'\n// are consistent, i.e. linearizabile. We need to use acquire-loads to keep\n// order and re-check the 'seq' to make sure it corresponds to the 'val' we're returning.\ntemplate<typename T> inline bool tmtype<T>::rawLoad(T& keepVal, uint64_t& keepSeq) {\n    keepSeq = seq.load(std::memory_order_acquire);\n    keepVal = (T)val.load(std::memory_order_acquire);\n    return (keepSeq == seq.load(std::memory_order_acquire));\n}\n\n// We don't need to check currTx here because we're not de-referencing\n// the val. It's only after a load() that the val may be de-referenced\n// (in user code), therefore we do the check on load() only.\ntemplate<typename T> inline void tmtype<T>::pstore(T newVal) {\n    if (tl_opdata == nullptr) { // Looks like we're outside a transaction\n        val.store((uint64_t)newVal, std::memory_order_relaxed);\n    } else {\n        gOFWF.writeSets[tl_tcico.tid].addOrReplace(this, (uint64_t)newVal);\n    }\n}\n\n\n//\n// Place these in a .cpp if you include this header from multiple files (compilation units)\n//\nOneFileWF gOFWF {};\nthread_local OpData* tl_opdata {nullptr};\n// Global/singleton to hold all the thread registry functionality\nThreadRegistry gThreadRegistry {};\n// During a transaction, this is true up until the first store()\nthread_local bool tl_is_read_only {false};\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\nthread_local ThreadCheckInCheckOut tl_tcico {};\n// Helper function for thread de-registration\nvoid thread_registry_deregister_thread(const int tid) {\n    gThreadRegistry.deregister_thread(tid);\n}\n\n}\n#endif /* _PERSISTENT_ONE_FILE_WAIT_FREE_TRANSACTIONAL_MEMORY_WITH_H_ */\n"
  },
  {
    "path": "ptms/PMDKTM.hpp",
    "content": "#ifndef _PMDK_TM_PERSISTENCY_\n#define _PMDK_TM_PERSISTENCY_\n\n#define PMDK_STM\n\n#ifdef PMDK_STM\n#include <shared_mutex>         // You can comment this out if you use instead our C-RW-WP reader-writer lock\n#include <libpmemobj++/p.hpp>\n#include <libpmemobj++/transaction.hpp>\n#include <libpmemobj++/pool.hpp>\n#include <libpmemobj++/allocator.hpp>\n#endif\n\nnamespace pmdk {\n\n#ifdef PMDK_STM\n\nusing namespace pmem::obj;\n\nauto gpop = pool_base::create(\"/dev/shm/pmdk_shared\", \"\", (size_t)(400*1024*1024));\n\nstd::shared_timed_mutex grwlock {};\n\nthread_local int tl_nested_write_trans {0};\nthread_local int tl_nested_read_trans {0};\n\n#endif\n\n// Ugly hack just to make PMDK work with our root pointers\nstatic void* g_objects[100];\n\n/*\n * <h1> Wrapper for libpmemobj from pmem.io </h1>\n *\n * http://pmem.io/pmdk/cpp_obj/\n *\n */\nclass PMDKTM {\n\npublic:\n    PMDKTM()  {\n        for (int i = 0; i < 100; i++) g_objects[i] = nullptr;\n\n    }\n\n    ~PMDKTM() { }\n\n\n    static std::string className() { return \"PMDK\"; }\n\n\n    template <typename T>\n    static inline T* get_object(int idx) {\n        return (T*)g_objects[idx];  // TODO: fix me\n    }\n\n    template <typename T>\n    static inline void put_object(int idx, T* obj) {\n        g_objects[idx] = obj;  // TODO: fix me\n        //PWB(&per->objects[idx]);\n    }\n\n\n    inline void begin_transaction() {\n    }\n\n    inline void end_transaction() {\n    }\n\n    inline void recover_if_needed() {\n    }\n\n    inline void abort_transaction(void) {\n    }\n\n\n    template<class F> static void transaction(F&& func) {\n#ifdef PMDK_STM\n        transaction::run(gpop, func);\n#endif\n    }\n\n    template<class F> static void updateTx(F&& func) {\n#ifdef PMDK_STM\n        if (tl_nested_write_trans > 0) {\n            transaction::run(gpop, func);\n            return;\n        }\n        ++tl_nested_write_trans;\n        grwlock.lock();\n        transaction::run(gpop, func);\n        grwlock.unlock();\n        --tl_nested_write_trans;\n#endif\n    }\n\n    template<class F> static void readTx(F&& func) {\n#ifdef PMDK_STM\n        if (tl_nested_read_trans > 0) {\n            transaction::run(gpop, func);\n            return;\n        }\n        ++tl_nested_read_trans;\n        grwlock.lock_shared();\n        transaction::run(gpop, func);\n        grwlock.unlock_shared();\n        --tl_nested_read_trans;\n#endif\n    }\n\n\n    /*\n     * Allocator\n     * Must be called from within a transaction\n     */\n    template <typename T, typename... Args>\n    static T* tmNew(Args&&... args) {\n        void *addr = nullptr;\n#ifdef PMDK_STM\n        auto oid = pmemobj_tx_alloc(sizeof(T), 0);\n        addr = pmemobj_direct(oid);\n#endif\n        return new (addr) T(std::forward<Args>(args)...); // placement new\n    }\n\n\n    /*\n     * De-allocator\n     * Must be called from within a transaction\n     */\n    template<typename T>\n    static void tmDelete(T* obj) {\n#ifdef PMDK_STM\n        if (obj == nullptr) return;\n        obj->~T();\n        pmemobj_tx_free(pmemobj_oid(obj));\n#endif\n    }\n\n    /* Allocator for C methods */\n    static void* pmalloc(size_t size) {\n        void* ptr = nullptr;\n#ifdef PMDK_STM\n        auto oid = pmemobj_tx_alloc(size, 0);\n        ptr = pmemobj_direct(oid);\n#endif\n        return ptr;\n    }\n\n\n    /* De-allocator for C methods (like memcached) */\n    static void pfree(void* ptr) {\n#ifdef PMDK_STM\n        pmemobj_tx_free(pmemobj_oid(ptr));\n#endif\n    }\n\n    // Doesn't actually do any checking. That functionality exists only for RomulusLog and RomulusLR\n    static bool consistency_check(void) {\n        return true;\n    }\n\n\n    // TODO: Remove these two once we make CX have void transactions\n    template<typename R,class F>\n    inline static R readTx(F&& func) {\n        readTx( [&]() {func();} );\n        return R{};\n    }\n    template<typename R,class F>\n    inline static R updateTx(F&& func) {\n        updateTx( [&]() {func();} );\n        return R{};\n    }\n};\n\n\n/*\n * Definition of persist<> type\n */\ntemplate<typename T>\nstruct persist {\n#ifdef PMDK_STM\n    // Stores the actual value\n    pmem::obj::p<T> val {};   // This is where the magic happens in libpmemobj\n#else\n    T val {};\n#endif\n    persist() { }\n\n    persist(T initVal) {\n        pstore(initVal);\n    }\n\n    // Casting operator\n    operator T() {\n        return pload();\n    }\n\n    // Casting to const\n    operator T() const {\n        return pload();\n    }\n\n    // Prefix increment operator: ++x\n    void operator++ () {\n        pstore(pload()+1);\n    }\n\n    // Prefix decrement operator: --x\n    void operator-- () {\n        pstore(pload()-1);\n    }\n\n    void operator++ (int) {\n        pstore(pload()+1);\n    }\n\n    void operator-- (int) {\n        pstore(pload()-1);\n    }\n\n    // Equals operator: first downcast to T and then compare\n    bool operator == (const T& otherval) const {\n        return pload() == otherval;\n    }\n\n    // Difference operator: first downcast to T and then compare\n    bool operator != (const T& otherval) const {\n        return pload() != otherval;\n    }\n\n    // Relational operators\n    bool operator < (const T& rhs) {\n        return pload() < rhs;\n    }\n    bool operator > (const T& rhs) {\n        return pload() > rhs;\n    }\n    bool operator <= (const T& rhs) {\n        return pload() <= rhs;\n    }\n    bool operator >= (const T& rhs) {\n        return pload() >= rhs;\n    }\n\n    T operator % (const T& rhs) {\n        return pload() % rhs;\n    }\n\n    // Operator arrow ->\n    T operator->() {\n        return pload();\n    }\n\n    // Operator &\n    T* operator&() {\n#ifdef PMDK_STM\n        return (T*)&val.get_ro();  // tsc, tsc: bad way to take away constness, but p<> is inflexible\n#else\n        return &val;\n#endif\n    }\n\n    // Copy constructor\n    persist<T>(const persist<T>& other) {\n        pstore(other.pload());\n    }\n\n    // Assignment operator from an atomic_mwc\n    persist<T>& operator=(const persist<T>& other) {\n        pstore(other.pload());\n        return *this;\n    }\n\n    // Assignment operator from a value\n    persist<T>& operator=(T value) {\n        pstore(value);\n        return *this;\n    }\n\n    persist<T>& operator&=(T value) {\n        pstore(pload() & value);\n        return *this;\n    }\n\n    persist<T>& operator|=(T value) {\n        pstore(pload() | value);\n        return *this;\n    }\n    persist<T>& operator+=(T value) {\n        pstore(pload() + value);\n        return *this;\n    }\n    persist<T>& operator-=(T value) {\n        pstore(pload() - value);\n        return *this;\n    }\n\n    inline void pstore(T newVal) {\n        val = newVal;\n    }\n\n    inline T pload() const {\n        return val;\n    }\n};\n\n\n\n\n} // end of pmdk namespace\n\n#undef PMDK_STM\n\n#endif   // _PMDK_TM_PERSISTENCY_\n"
  },
  {
    "path": "ptms/README.md",
    "content": "We have in here the PTMs (Persistent Transactional Memories) and their wrappers.\r\n\r\n### PMDK ###\r\nAlso known as NVML, it is undo-log based.\r\nUses a regular pthread_rwlock_t for concurrency.\r\nBlocking progress.\r\nYou need to install this library from github.\r\n\r\n### RomulusLog ###\r\nFor persistence, uses the Romulus technique with volatile redo log.\r\nUses a C-RW-WP reader-writer lock with integrated flat-combining.\r\nBlocking with starvation-free progress for writers.\r\nUses 0x7fdd40000000 by default as the mapping address.\r\n\r\n### RomulusLR ###\r\nFor persistence, uses the Romulus technique with volatile redo log.\r\nFor concurrency, uses the Left-Right universal construct with integrated flat-combining.\r\nBlocking with starvation-free progress for writers and wait-free population oblivious for readers.\r\nUses 0x7fdd80000000 by default as the mapping address.\r\n\r\n### PTM OneFile Lock-Free ###\r\nImplementation of the OneFile STM (Lock-Free) with persistent memory support. Does 2 fences per transaction.\r\nThis is redo-log based and it uses EsLoco memory allocator.\r\nHas lock-free progress for all transactions.\r\nDoes not use pfences.h\r\nUses 0x7fea00000000 by default as the mapping address.\r\n\r\n### PTM OneFile Wait-Free ###\r\nImplementation of the OneFile STM (Wait-Free) with persistent memory support. Does 2 fences per transaction.\r\nThis is redo-log based and it uses EsLoco memory allocator.\r\nHas wait-free bounded progress for all transactions.\r\nDoes not use pfences.h\r\nUses 0x7feb00000000 by default as the mapping address.\r\n\r\nThe pfences.h file contains the definitions of the PWB(), PFENCE() and PSYNC() macros for Romulus, depending on the target cpu.\r\nPMDK detects these at runtime, using the best possible one.\r\nThe concept of pwb/pfence/psync comes from the paper \"Linearizability of Persistent Memory Objects Under a Full-System-Crash Failure Model\" by Joseph Izraelevitz, Hammurabi Mendes, Michael L. Scott.\r\n"
  },
  {
    "path": "ptms/atlas/README.md",
    "content": "Atlas doesn't provide durable linearizable transactions (ACID) and therefore, it is not directly comparable with the other PTMs.\r\nAlso, it's a bit of a pain to get working because it requires a patch to the compiler. If you really want to see for yourself, here it is."
  },
  {
    "path": "ptms/atlas/atlas.patch",
    "content": "diff --git a/OnefileReadme.md b/OnefileReadme.md\nnew file mode 100644\nindex 0000000..6e6920d\n--- /dev/null\n+++ b/OnefileReadme.md\n@@ -0,0 +1,5 @@\n+# Building Atlas\n+\n+1. Build plugin. cd compiler-plugin; make\n+2. Build Atlas. cd runtime; mkdir build; cd build; cmake ..; make -j\n+\ndiff --git a/compiler-plugin/Makefile b/compiler-plugin/Makefile\nnew file mode 100644\nindex 0000000..ac81d22\n--- /dev/null\n+++ b/compiler-plugin/Makefile\n@@ -0,0 +1,7 @@\n+\n+all: plugin\n+\n+plugin: plugin_build/NvmInstrumenter.so\n+\n+plugin_build/NvmInstrumenter.so: src/Instrumentation/NvmInstrumenter.cpp\n+\t./build_plugin\n\\ No newline at end of file\ndiff --git a/compiler-plugin/build_plugin b/compiler-plugin/build_plugin\nindex 0cde572..dc38e9e 100755\n--- a/compiler-plugin/build_plugin\n+++ b/compiler-plugin/build_plugin\n@@ -15,6 +15,8 @@\n # <http://www.gnu.org/licenses/>.\n #\n \n+#etc_flags=\"-stdlib=libstdc++ -D_GLIBCXX_USE_CXX11_ABI=0 -fno-rtti\"\n+\n logfile=\"build_log.txt\"\n if [ -f \"$logfile\" ]; then\n     rm $logfile\n@@ -28,7 +30,7 @@ if [ ! -f \"$srcfile\" ]; then\n     echo \"Could not find plugin source file NvmInstrumenter.cpp - are you running from within Atlas/compiler-plugin?\"\n     exit 1\n fi\n-clangpppath=$(which clang++; reval=\"$?\")\n+clangpppath=$(which clang; reval=\"$?\")\n if [ \"$?\" -ne 0 ]; then\n     echo \"Could not find a copy of clang++, is it installed or added to PATH?\"\n     exit 1\n@@ -43,19 +45,21 @@ else\n     echo \"Found llvm-config in $llvmconfigpath\"\n fi\n echo \"Compiling object files\" | tee $logfile\n-timeout 300s clang++ -c $srcfile `llvm-config --cxxflags` >> $logfile 2>&1\n+\n+timeout 300s clang -c $srcfile -g `llvm-config --cxxflags` >> $logfile 2>&1\n retval=\"$?\"\n if [ \"$retval\" == \"124\" ]; then\n     echo \"Compilation took longer than 5 minutes - have you got conflicting versions of llvmretval Try building with the linked script.\"\n     exit 1\n elif [ \"$retval\" -ne 0 ]; then\n     echo \"Build shared lib failed on compilation, check $logfile\"\n+    cat $logfile\n     exit 1\n else\n     echo \"Compilation successful\"\n fi\n echo \"Linking\" | tee $logfile\n-timeout 300s clang++ -shared NvmInstrumenter.o -o NvmInstrumenter.so >> $logfile 2>&1\n+timeout 300s clang `llvm-config --cxxflags` -g -shared NvmInstrumenter.o -o NvmInstrumenter.so >> $logfile 2>&1\n retval=\"$?\"\n if [ \"$retval\" == \"124\" ]; then\n     echo \"Linking took longer than 5 minutes - have you got conflicting versions of llvmretval Try building with the linked script.\"\ndiff --git a/runtime/src/consistency/helper_driver.cpp b/runtime/src/consistency/helper_driver.cpp\nindex f34c8f2..e8a5d6a 100644\n--- a/runtime/src/consistency/helper_driver.cpp\n+++ b/runtime/src/consistency/helper_driver.cpp\n@@ -24,6 +24,17 @@\n #include \"log_mgr.hpp\"\n #include \"consistency_mgr.hpp\"\n \n+#include <atomic>\n+std::atomic<bool> waitingHelperFinishFlag;\n+//synchronize with helper thread. \n+void synchronizeWithHelper(){\n+\twaitingHelperFinishFlag.store(true);\n+\twhile(waitingHelperFinishFlag.load()){\n+\t\tAtlas::LogMgr::getInstance().signalLogReady();\n+\t\t;\n+\t}\n+}\n+\n namespace Atlas {\n     \n uint64_t removed_log_count = 0;\n@@ -135,6 +146,10 @@ void Helper::doConsistentUpdate(void *arg_lsp)\n             CSMgr::deleteInstance();\n             break;\n         }\n+        if(waitingHelperFinishFlag.load() && !cs_mgr.get_num_graph_vertices()){\n+        \t//helper finished. Now signal application it can continue.\n+\t\t\twaitingHelperFinishFlag.store(false);\n+        }\n         \n         CSMgr::deleteInstance();\n \ndiff --git a/runtime/tests/data_structures/CMakeLists.txt b/runtime/tests/data_structures/CMakeLists.txt\nindex f02cc09..13367d8 100644\n--- a/runtime/tests/data_structures/CMakeLists.txt\n+++ b/runtime/tests/data_structures/CMakeLists.txt\n@@ -16,7 +16,7 @@\n \n set (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/tests/data_structures)\n \n-set (DS_ATLAS_TGTS alarm_clock_nvm queue_nvm stores_nvm cow_array_list_nvm sll_nvm sll_mt_ll sll_ll)\n+set (DS_ATLAS_TGTS alarm_clock_nvm queue_nvm stores_nvm cow_array_list_nvm sll_nvm sll_mt_ll sll_ll sps_nvm)\n set (DS_NOATLAS_TGTS cow_array_list queue sll sll_mt stores alarm_clock)\n set (DS_ALL_TGTS ${DS_ATLAS_TGTS} ${DS_NOATLAS_TGTS})\n \ndiff --git a/runtime/tests/data_structures/PBenchmarkSPS.hpp b/runtime/tests/data_structures/PBenchmarkSPS.hpp\nnew file mode 100644\nindex 0000000..f6b4873\n--- /dev/null\n+++ b/runtime/tests/data_structures/PBenchmarkSPS.hpp\n@@ -0,0 +1,226 @@\n+#ifndef _PERSISTENT_BENCHMARK_SPS_H_\n+#define _PERSISTENT_BENCHMARK_SPS_H_\n+\n+#include <atomic>\n+#include <chrono>\n+#include <thread>\n+#include <string>\n+#include <vector>\n+#include <algorithm>\n+#include <cassert>\n+#include <iostream>\n+#include <typeinfo>\n+#include \"atlas_api.h\"\n+#include \"atlas_alloc.h\"\n+#include <pthread.h>\n+\n+static const int arraySize=200000;\n+static const int MAX_THREADS=64;\n+static const int MAX_RUNS = 10;\n+\n+using namespace std;\n+using namespace chrono;\n+\n+extern unsigned nvm_region_id;\n+\n+static const int LOCK_BUCKET_SIZE = 1;\n+static pthread_mutex_t locks[arraySize/LOCK_BUCKET_SIZE] = {PTHREAD_MUTEX_INITIALIZER};\n+/**\n+ * This is a micro-benchmark with integer swaps (SPS) for PTMs\n+ */\n+class PBenchmarkSPS {\n+\n+private:\n+\tint numThreads;\n+\n+public:\n+\tstruct UserData  {\n+\t\tlong long seq;\n+\t\tint tid;\n+\t\tUserData(long long lseq, int ltid) {\n+\t\t\tthis->seq = lseq;\n+\t\t\tthis->tid = ltid;\n+\t\t}\n+\t\tUserData() {\n+\t\t\tthis->seq = -2;\n+\t\t\tthis->tid = -2;\n+\t\t}\n+\t\tUserData(const UserData &other) : seq(other.seq), tid(other.tid) { }\n+\n+\t\tbool operator < (const UserData& other) const {\n+\t\t\treturn seq < other.seq;\n+\t\t}\n+\t};\n+\n+\tPBenchmarkSPS(int numThreads) {\n+\t\tthis->numThreads = numThreads;\n+\t}\n+\n+\tstruct sync_struct{\n+\t\tatomic<bool> startFlag = { false };\n+\t\tatomic<bool> quit = { false };\n+\t\tlong numSwapsPerTx;\n+\t\tsync_struct(long numSwapsPerTxParam):startFlag(false),quit(false),numSwapsPerTx(numSwapsPerTxParam){}\n+\t};\n+\tstatic void thread_driver_fine_grained(sync_struct *sync, long long *ops, const int tid){\n+\t\tuint64_t seed = tid+1234567890123456781ULL;\n+\t\tint larraySize = arraySize;\n+\t\tlong numSwapsPerTx = sync->numSwapsPerTx;\n+\t\tvector<uint64_t> pairs(numSwapsPerTx*2);\n+\t\t// Spin until the startFlag is set\n+\t\twhile (!sync->startFlag.load()) {}\n+\t\t// Do transactions until the quit flag is set\n+\t\tlong long tcount = 0;\n+\t\twhile (!sync->quit.load()) {\n+\t\t\tuint64_t *parray = (uint64_t*)NVM_GetRegionRoot(nvm_region_id);\n+\t\t\tfor (int i = 0; i < numSwapsPerTx; i++) {\n+\t\t\t\tseed = randomLong(seed);\n+\t\t\t\tauto ia = seed%larraySize;\n+\t\t\t\tseed = randomLong(seed);\n+\t\t\t\tauto ib = seed%larraySize;\n+\t\t\t\tpairs[i*2]=ia;\n+\t\t\t\tpairs[i*2+1]=ib;\n+\t\t\t}\n+\t\t\tvector<uint64_t> lcks(pairs);\n+\t\t\tstd::sort(lcks.begin(), lcks.end());\n+\t\t\tauto end = std::unique(lcks.begin(),lcks.end());\n+\t\t\tfor(auto it = lcks.begin(); it!=end; ++it)\n+\t\t\t\tpthread_mutex_lock(&locks[*it]);\n+\t\t\tfor (int i = 0; i < numSwapsPerTx; i++) {\n+\t\t\t\tauto ia=pairs[2*i], ib=pairs[2*i+1];\n+\t\t\t\tuint64_t tmp = parray[ia];\n+\t\t\t\tparray[ia] = parray[ib];\n+\t\t\t\tparray[ib] = tmp;\n+\t\t\t}\n+\t\t\tfor(auto it = lcks.begin(); it!=end; ++it)\n+\t\t\t\tpthread_mutex_unlock(&locks[*it]);\n+\n+\t\t\t++tcount;\n+\t\t\t/*\n+\t                PE::read_transaction([this,&seed,&parray,&numWordsPerTransaction] () {\n+\t                    PersistentArrayInt<persist>* read_array = PE::template get_object<PersistentArrayInt<persist>>(PIDX_INT_ARRAY);\n+\t                    // Check that the array is consistent\n+\t                    int sum = 0;\n+\t                    for (int i = 0; i < arraySize; i++) {\n+\t                        sum += read_array->counters[i];\n+\t                    }\n+\t                    assert(sum == 0);\n+\t                } );\n+\t\t\t */\n+\t\t}\n+\t\t*ops = tcount;\n+\t}\n+\tstatic void thread_driver(sync_struct *sync, long long *ops, const int tid){\n+\t\tuint64_t seed = tid+1234567890123456781ULL;\n+\t\tint larraySize = arraySize;\n+\t\tlong numSwapsPerTx = sync->numSwapsPerTx;\n+\t\t// Spin until the startFlag is set\n+\t\twhile (!sync->startFlag.load()) {}\n+\t\t// Do transactions until the quit flag is set\n+\t\tlong long tcount = 0;\n+\t\twhile (!sync->quit.load()) {\n+\t\t\tpthread_mutex_lock(&locks[0]);\n+\t\t\tuint64_t *parray = (uint64_t*)NVM_GetRegionRoot(nvm_region_id);\n+\t\t\tfor (int i = 0; i < numSwapsPerTx; i++) {\n+\t\t\t\tseed = randomLong(seed);\n+\t\t\t\tauto ia = seed%larraySize;\n+\t\t\t\tuint64_t tmp = parray[ia];\n+\t\t\t\tseed = randomLong(seed);\n+\t\t\t\tauto ib = seed%larraySize;\n+\t\t\t\tparray[ia] = parray[ib];\n+\t\t\t\tparray[ib] = tmp;\n+\t\t\t}\n+\t\t\tpthread_mutex_unlock(&locks[0]);\n+\t\t\t++tcount;\n+\t\t\t/*\n+                PE::read_transaction([this,&seed,&parray,&numWordsPerTransaction] () {\n+                    PersistentArrayInt<persist>* read_array = PE::template get_object<PersistentArrayInt<persist>>(PIDX_INT_ARRAY);\n+                    // Check that the array is consistent\n+                    int sum = 0;\n+                    for (int i = 0; i < arraySize; i++) {\n+                        sum += read_array->counters[i];\n+                    }\n+                    assert(sum == 0);\n+                } );\n+\t\t\t */\n+\t\t}\n+\t\t*ops = tcount;\n+\t}\n+\n+\t/*\n+\t * An array of integers that gets randomly permutated.\n+\t */\n+\t//template<typename PTM, template<typename> class PERSIST>\n+\tuint64_t benchmarkSPSInteger(std::string& className, const seconds testLengthSeconds, const long numSwapsPerTx, const int numRuns) {\n+\t\tlong long ops[MAX_THREADS][MAX_RUNS];\n+\t\tlong long lengthSec[MAX_RUNS];\n+\t\tassert(numThreads <= MAX_THREADS);\n+\t\tassert(numRuns <= MAX_RUNS);\n+\t\t//atomic<bool> startFlag = { false };\n+\t\t//atomic<bool> quit = { false };\n+\t\tsync_struct sync{numSwapsPerTx};\n+\n+\t\t// Create the array of integers and initialize it, saving it in root pointer 0\n+\t\tint larraySize = arraySize;\n+\t\tNVM_BEGIN_DURABLE();\n+\t\tvoid *arr = nvm_alloc((unsigned long)(larraySize*sizeof(uint64_t)), nvm_region_id);\n+\t\tNVM_SetRegionRoot(nvm_region_id, arr);\n+\t\tNVM_END_DURABLE();\n+\n+\t\tfor (int irun = 0; irun < numRuns; irun++) {\n+\t\t\tif (irun == 0) {\n+\t\t\t\t//className = PTM::className();\n+\t\t\t\tcout << \"##### \" << className << \" #####  \\n\";\n+\t\t\t}\n+\t\t\tthread enqdeqThreads[MAX_THREADS];\n+\t\t\tfor (int tid = 0; tid < numThreads; tid++)\n+\t\t\t\t//enqdeqThreads[tid] = thread(thread_driver_fine_grained, &sync, &ops[tid][irun], tid);\n+\t\t\t\tenqdeqThreads[tid] = thread(thread_driver, &sync, &ops[tid][irun], tid);\n+\t\t\tauto startBeats = steady_clock::now();\n+\t\t\tsync.startFlag.store(true);\n+\t\t\t// Sleep for 20 seconds\n+\t\t\tthis_thread::sleep_for(testLengthSeconds);\n+\t\t\tsync.quit.store(true);\n+\t\t\tauto stopBeats = steady_clock::now();\n+\t\t\tfor (int tid = 0; tid < numThreads; tid++) enqdeqThreads[tid].join();\n+\t\t\tlengthSec[irun] = (stopBeats-startBeats).count();\n+\t\t\tsync.startFlag.store(false);\n+\t\t\tsync.quit.store(false);\n+\t\t}\n+\n+\t\tNVM_BEGIN_DURABLE();\n+\t\tnvm_free(NVM_GetRegionRoot(nvm_region_id));\n+\t\tNVM_SetRegionRoot(nvm_region_id, nullptr);\n+\t\tNVM_END_DURABLE();\n+\n+\t\t// Accounting\n+\t\tvector<long long> agg(numRuns);\n+\t\tfor (int irun = 0; irun < numRuns; irun++) {\n+\t\t\tfor(int i=0;i<numThreads;i++){\n+\t\t\t\tagg[irun] += ops[i][irun]*1000000000LL/lengthSec[irun];\n+\t\t\t}\n+\t\t}\n+\t\t// Compute the median. numRuns should be an odd number\n+\t\tsort(agg.begin(),agg.end());\n+\t\tauto maxops = agg[numRuns-1];\n+\t\tauto minops = agg[0];\n+\t\tauto medianops = agg[numRuns/2];\n+\t\tauto delta = (long)(100.*(maxops-minops) / ((double)medianops));\n+\t\t// Printed value is the median of the number of ops per second that all threads were able to accomplish (on average)\n+\t\tstd::cout << \"Swaps/sec = \" << medianops*numSwapsPerTx << \"     delta = \" << delta*numSwapsPerTx << \"%   min = \" << minops*numSwapsPerTx << \"   max = \" << maxops*numSwapsPerTx << \"\\n\";\n+\t\treturn medianops*numSwapsPerTx;\n+\t}\n+\n+\n+\t/**\n+\t * An imprecise but fast random number generator\n+\t */\n+\tstatic uint64_t randomLong(uint64_t x) {\n+\t\tx ^= x >> 12; // a\n+\t\tx ^= x << 25; // b\n+\t\tx ^= x >> 27; // c\n+\t\treturn x * 2685821657736338717LL;\n+\t}\n+};\n+\n+#endif\ndiff --git a/runtime/tests/data_structures/sps_nvm.cpp b/runtime/tests/data_structures/sps_nvm.cpp\nnew file mode 100644\nindex 0000000..2e247c1\n--- /dev/null\n+++ b/runtime/tests/data_structures/sps_nvm.cpp\n@@ -0,0 +1,113 @@\n+/*\n+ * This benchmark executes SPS for the following PTMs:\n+ * - RomulusLog\n+ * - RomulusLR\n+ * - PMDK\n+ * - OneFilePTM-LF (lock-free)\n+ * - OneFilePTM-WF (wait-free bounded)\n+ */\n+#include <iostream>\n+#include <fstream>\n+#include <cstring>\n+#include <vector>\n+#include <chrono>\n+#include <atomic>\n+#include <chrono>\n+#include <thread>\n+#include <string>\n+#include <vector>\n+#include <algorithm>\n+#include <cassert>\n+#include <iostream>\n+#include <typeinfo>\n+#include \"PBenchmarkSPS.hpp\"\n+\n+using namespace std;\n+using namespace chrono;\n+//#include \"benchmarks/PBenchmarkSPS.hpp\"\n+//#include \"ptms/atlas/AtlasPTM.hpp\"\n+\n+unsigned nvm_region_id;\n+\n+void AtlasInit(){\n+    NVM_Initialize();\n+    nvm_region_id = NVM_FindOrCreateRegion(\"SPS_onefile\", O_RDWR, NULL);\n+}\n+void AtlasFinish(){\n+    NVM_CloseRegion(nvm_region_id);\n+    // Optionally print Atlas stats\n+#ifdef NVM_STATS\n+    NVM_PrintStats();\n+#endif\n+    // Atlas bookkeeping\n+    NVM_Finalize();\n+}\n+void synchronizeWithHelper();\n+int main(void) {\n+    AtlasInit();\n+\n+    const std::string dataFilename {\"data/psps-integer-atlas.txt\"};\n+    vector<int> threadList = { 1, 2, 4, 8, 16, 32 };         // For the laptop\n+    //vector<int> threadList = { 1, 2, 4, 8, 16, 24, 32 };   // For Cervino or AWS\n+    vector<long> swapsPerTxList = { 1, 4, 8, 16, 32, 64, 128, 256 };\n+    const int numRuns = 1;                                   // 5 runs for the paper\n+    const seconds testLength(2);                          // 20s for the paper\n+    const int EMAX_CLASS = 10;\n+    unsigned maxClass = 0;\n+    vector<vector<vector<uint64_t>>> results(EMAX_CLASS,\n+    \t\tvector<vector<uint64_t>>(threadList.size(),\n+    \t\t\t\tvector<uint64_t>(swapsPerTxList.size(),0)));\n+\n+    //uint64_t results[EMAX_CLASS][threadList.size()][swapsPerTxList.size()];\n+    std::string cNames[EMAX_CLASS]={\"ATLAS\"};\n+    // Reset results\n+    //std::memset(results, 0, sizeof(uint64_t)*EMAX_CLASS*threadList.size()*swapsPerTxList.size());\n+\n+\n+    // SPS Benchmarks multi-threaded\n+    std::cout << \"\\n----- Persistent SPS Benchmark (multi-threaded integer array swap) -----\\n\";\n+    for (unsigned it = 0; it < threadList.size(); it++) {\n+        int nThreads = threadList[it];\n+        for (unsigned is = 0; is < swapsPerTxList.size(); is++) {\n+            int nWords = swapsPerTxList[is];\n+            int ic = 0;\n+            PBenchmarkSPS bench(nThreads);\n+            std::cout << \"\\n----- threads=\" << nThreads << \"   runs=\" << numRuns << \"   length=\" << testLength.count() << \"s   arraySize=\" << arraySize << \"   swaps/tx=\" << nWords << \" -----\\n\";\n+            results[ic][it][is] = bench.benchmarkSPSInteger   (cNames[ic], testLength, nWords, numRuns);\n+            ic++;\n+            maxClass = ic;\n+            synchronizeWithHelper();\n+        }\n+        std::cout << \"\\n\";\n+    }\n+\n+    AtlasFinish();\n+\n+    // Export tab-separated values to a file to be imported in gnuplot or excel\n+    ofstream dataFile;\n+    dataFile.open(dataFilename);\n+    dataFile << \"Swaps\\t\";\n+    // Printf class names for each column plus the corresponding thread\n+    for (unsigned iclass = 0; iclass < maxClass; iclass++) {\n+        for (unsigned ithread = 0; ithread < threadList.size(); ithread++) {\n+            int nThreads = threadList[ithread];\n+            dataFile << cNames[iclass] << \"-\" << nThreads <<\"T\\t\";\n+        }\n+    }\n+    dataFile << \"\\n\";\n+    for (unsigned iswaps = 0; iswaps < swapsPerTxList.size(); iswaps++) {\n+        dataFile << swapsPerTxList[iswaps] << \"\\t\";\n+        for (unsigned iclass = 0; iclass < maxClass; iclass++) {\n+            for (unsigned ithread = 0; ithread < threadList.size(); ithread++) {\n+                dataFile << results[iclass][ithread][iswaps] << \"\\t\";\n+            }\n+        }\n+        dataFile << \"\\n\";\n+    }\n+    dataFile.close();\n+    std::cout << \"\\nSuccessfuly saved results in \" << dataFilename << \"\\n\";\n+\n+\n+\n+    return 0;\n+}\n"
  },
  {
    "path": "ptms/romuluslog/RomulusLog.cpp",
    "content": "\n#include \"RomulusLog.hpp\"\n\nnamespace romuluslog {\n\n// Global with the 'main' size. Used by pload()\nuint64_t g_main_size = 0;\n// Global with the 'main' addr. Used by pload()\nuint8_t* g_main_addr = 0;\n\n// Counter of nested write transactions\nthread_local int64_t tl_nested_write_trans = 0;\n// Counter of nested read-only transactions\nthread_local int64_t tl_nested_read_trans = 0;\nbool histoOn = false;\nbool histoflag = false;\nRomulusLog gRomLog {};\n\n/*\n * <h1> Romulus Log </h1>\n* TODO: explain this...\n*\n*\n*\n*/\n#ifdef USE_ESLOCO\n#else\nmspace create_mspace_with_base(void* base, size_t capacity, int locked);\n#endif\n//\n// Private methods\n//\n\n// Copy the data from 'main' to 'back'\nvoid RomulusLog::copyMainToBack() {\n    uint64_t size = std::min(per->used_size,g_main_size);\n    std::memcpy(back_addr, main_addr, size);\n    flush_range(back_addr, size);\n}\n\n// Copy the data from 'back' to 'main'\nvoid RomulusLog::copyBackToMain() {\n    uint64_t size = std::min(per->used_size,g_main_size);\n    std::memcpy(main_addr, back_addr, size);\n    flush_range(main_addr, size);\n}\n\nRomulusLog::RomulusLog() : dommap{true},maxThreads{128} {\n    fc = new std::atomic< std::function<void()>* >[maxThreads*CLPAD];\n    for (int i = 0; i < maxThreads; i++) {\n        fc[i*CLPAD].store(nullptr, std::memory_order_relaxed);\n    }\n    // Filename for the mapping file\n    if (dommap) {\n        base_addr = (uint8_t*)0x7fdd40000000;\n        max_size = PM_REGION_SIZE;\n        // Check if the file already exists or not\n        struct stat buf;\n        if (stat(MMAP_FILENAME, &buf) == 0) {\n            // File exists\n            //std::cout << \"Re-using memory region\\n\";\n            fd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0755);\n            assert(fd >= 0);\n            // mmap() memory range\n            uint8_t* got_addr = (uint8_t *)mmap(base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED_VALIDATE | PM_FLAGS, fd, 0);\n            if (got_addr == MAP_FAILED || got_addr != base_addr) {\n                perror(\"ERROR: mmap() is not working !!! \");\n                printf(\"got_addr = %p instead of %p\\n\", got_addr, base_addr);\n                assert(false);\n            }\n            per = reinterpret_cast<PersistentHeader*>(base_addr);\n            if (per->id != MAGIC_ID) createFile();\n            g_main_size = (max_size - sizeof(PersistentHeader))/2;\n            main_addr = base_addr + sizeof(PersistentHeader);\n            back_addr = main_addr + g_main_size;\n            g_main_addr = main_addr;\n            recover();\n        } else {\n            createFile();\n        }\n    }\n}\n\n\nRomulusLog::~RomulusLog() {\n    delete[] fc;\n    // Must do munmap() if we did mmap()\n    if (dommap) {\n        //destroy_mspace(ms);\n        munmap(base_addr, max_size);\n        close(fd);\n    }\n    if(histoflag){\n    \tfor(int i=0;i<300;i++){\n    \t\tstd::cout<<i<<\":\"<<histo[i]<<\"\\n\";\n    \t}\n    }\n}\n\nvoid RomulusLog::createFile(){\n    // File doesn't exist\n    fd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0755);\n    assert(fd >= 0);\n    if (lseek(fd, max_size-1, SEEK_SET) == -1) {\n        perror(\"lseek() error\");\n    }\n    if (write(fd, \"\", 1) == -1) {\n        perror(\"write() error\");\n    }\n    // mmap() memory range\n    uint8_t* got_addr = (uint8_t *)mmap(base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED_VALIDATE | PM_FLAGS, fd, 0);\n    if (got_addr == MAP_FAILED || got_addr != base_addr) {\n        perror(\"ERROR: mmap() is not working !!! \");\n        printf(\"got_addr = %p instead of %p\\n\", got_addr, base_addr);\n        assert(false);\n    }\n    // No data in persistent memory, initialize\n    per = new (base_addr) PersistentHeader;\n    g_main_size = (max_size - sizeof(PersistentHeader))/2;\n    main_addr = base_addr + sizeof(PersistentHeader);\n    back_addr = main_addr + g_main_size;\n    g_main_addr = main_addr;\n    PWB(&per->id);\n    PWB(&per->state);\n    // We need to call create_mspace_with_base() from within a transaction so that\n    // the modifications on 'main' get replicated on 'back'. This means we temporarily\n    // need to set the 'used_size' to 'main_size' to make sure everything is copied.\n    begin_transaction();\n    // Just to force the copy of the whole main region\n    per->used_size = g_main_size;\n#ifdef USE_ESLOCO\n    esloco = new EsLoco<persist>(main_addr, g_main_size, false);\n    per->objects = (void**)esloco->malloc(sizeof(void*)*100);\n#else\n    per->ms = create_mspace_with_base(main_addr, g_main_size, false);\n    per->objects = (void**)mspace_malloc(per->ms, sizeof(void*)*100);\n#endif\n    for (int i = 0; i < 100; i++) {\n        per->objects[i] = nullptr;\n        add_to_log(&per->objects[i],sizeof(void*));\n        PWB(&per->objects[i]);\n    }\n    end_transaction();\n    // The used bytes in the main region\n    per->used_size = (uint8_t*)(&per->used_size) - ((uint8_t*)base_addr+sizeof(PersistentHeader))+128;\n    flush_range((uint8_t*)per,sizeof(PersistentHeader));\n    PFENCE();\n    // Finally, set the id to confirm that the whole initialization process has completed\n    per->id = MAGIC_ID;\n    PWB(&per->id);\n    PSYNC();\n}\n\nvoid RomulusLog::ns_reset(){\n    per->id = MAGIC_ID;\n    PWB(&per->id);\n    PFENCE();\n    std::memset(base_addr,0,max_size);\n\n    // No data in persistent memory, initialize\n    per = new (base_addr) PersistentHeader;\n    g_main_size = (max_size - sizeof(PersistentHeader))/2;\n    main_addr = base_addr + sizeof(PersistentHeader);\n    back_addr = main_addr + g_main_size;\n    PWB(&per->id);\n    PWB(&per->state);\n    // We need to call create_mspace_with_base() from within a transaction so that\n    // the modifications on 'main' get replicated on 'back'. This means we temporarily\n    // need to set the 'used_size' to 'main_size' to make sure everything is copied.\n    begin_transaction();\n    // Just to force the copy of the whole main region\n    per->used_size = g_main_size;\n#ifdef USE_ESLOCO\n    esloco = new EsLoco<persist>(main_addr, g_main_size, false);\n    per->objects = (void**)esloco->malloc(sizeof(void*)*100);\n#else\n    per->ms = create_mspace_with_base(main_addr, g_main_size, false);\n    per->objects = (void**)mspace_malloc(per->ms, sizeof(void*)*100);\n#endif\n    for (int i = 0; i < 100; i++) {\n        per->objects[i] = nullptr;\n        add_to_log(&per->objects[i],sizeof(void*));\n        PWB(&per->objects[i]);\n    }\n    end_transaction();\n    // The used bytes in the main region\n    per->used_size = (uint8_t*)(&per->used_size) - ((uint8_t*)base_addr+sizeof(PersistentHeader))+128;\n    flush_range((uint8_t*)per,sizeof(PersistentHeader));\n    PFENCE();\n    // Finally, set the id to confirm that the whole initialization process has completed\n    per->id = MAGIC_ID;\n    PWB(&per->id);\n    PSYNC();\n}\n\nvoid RomulusLog::reset(){\n    gRomLog.ns_reset();\n}\n\n/*\n * Recovers from an incomplete transaction if needed\n */\ninline void RomulusLog::recover() {\n    int lstate = per->state.load(std::memory_order_relaxed);\n    if (lstate == IDLE) {\n        return;\n    } else if (lstate == COPYING) {\n        printf(\"RomulusLog: Recovery from COPYING...\\n\");\n        copyMainToBack();\n    } else if (lstate == MUTATING) {\n        printf(\"RomulusLog: Recovery from MUTATING...\\n\");\n        copyBackToMain();\n    } else {\n        assert(false);\n        // ERROR: corrupted state\n    }\n    PFENCE();\n    per->state.store(IDLE, std::memory_order_relaxed);\n    return;\n}\n\n\n/*\n * Meant to be called from user code when something bad happens and the\n * whole transaction needs to be aborted.\n * TODO: fix this for nested transactions.\n */\ninline void RomulusLog::abort_transaction(void) {\n    // Check for nested transaction\n    --tl_nested_write_trans;\n    if (tl_nested_write_trans != 0) return;\n    // Apply the log to rollback the modifications\n    apply_log(back_addr, main_addr);\n\n}\n\n}\n"
  },
  {
    "path": "ptms/romuluslog/RomulusLog.hpp",
    "content": "#ifndef _ROMULUS_LOG_PERSISTENT_TRANSACTIONAL_MEMORY_\n#define _ROMULUS_LOG_PERSISTENT_TRANSACTIONAL_MEMORY_\n#include <atomic>\n#include <cstdint>\n#include <cassert>\n#include <string>\n#include <cstring>      // std::memcpy()\n#include <sys/mman.h>   // Needed if we use mmap()\n#include <sys/types.h>  // Needed by open() and close()\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>     // Needed by close()\n#include <linux/mman.h> // Needed by MAP_SHARED_VALIDATE\n#include <stdio.h>\n#include <functional>\n\n#include \"../../common/pfences.h\"\n#include \"ptms/rwlocks/CRWWP_SpinLock.hpp\"\n#include \"common/ThreadRegistry.hpp\"\n\n// Size of the persistent memory region\n#ifndef PM_REGION_SIZE\n#define PM_REGION_SIZE (400*1024*1024ULL) // 400 MB by default (to run on laptop)\n#endif\n// DAX flag (MAP_SYNC) is needed for Optane but not for /dev/shm/\n#ifdef PM_USE_DAX\n#define PM_FLAGS       MAP_SYNC\n#else\n#define PM_FLAGS       0\n#endif\n// Name of persistent file mapping\n#ifndef PM_FILE_NAME\n#define PM_FILE_NAME   \"/dev/shm/romulus_log_shared\"\n#endif\n\nnamespace romuluslog {\n\n// Forward declaration of RomulusLog to create a global instance\nclass RomulusLog;\nextern RomulusLog gRomLog;\n\nextern uint64_t g_main_size;\nextern uint8_t* g_main_addr;\n\n// Counter of nested write transactions\nextern thread_local int64_t tl_nested_write_trans;\n// Counter of nested read-only transactions\nextern thread_local int64_t tl_nested_read_trans;\nextern bool histoOn;\nextern bool histoflag;\n\n\n#ifdef USE_ESLOCO\n#include \"EsLoco/EsLoco.hpp\"\n// forward declaration\ntemplate<typename T> struct persist;\n#else\ntypedef void* mspace;\nextern void* mspace_malloc(mspace msp, size_t bytes);\nextern void mspace_free(mspace msp, void* mem);\n#endif\n\n/*\n * <h1> Romulus Log </h1>\n * TODO: explain this...\n *\n *\n *\n */\nclass RomulusLog {\n    // Id for sanity check of Romulus\n    static const uint64_t MAGIC_ID = 0x1337BAB2;\n\n    // Possible values for \"state\"\n    static const int IDLE = 0;\n    static const int MUTATING = 1;\n    static const int COPYING = 2;\n\n    // Number of log entries in a chunk of the log\n    static const int CHUNK_SIZE = 1024;\n\n    // Member variables\n    const char* MMAP_FILENAME = PM_FILE_NAME;\n    bool dommap;\n    int fd = -1;\n    uint8_t* base_addr;\n    uint64_t max_size;\n    uint8_t* main_addr;\n    uint8_t* back_addr;\n    CRWWPSpinLock rwlock {};\n\n    // Stuff used by the Flat Combining mechanism\n    static const int CLPAD = 128/sizeof(uintptr_t);\n    alignas(128) std::atomic< std::function<void()>* >* fc; // array of atomic pointers to functions\n    const int maxThreads;\n\n    // Each log entry is two words (8+8 = 16 bytes)\n    struct LogEntry {\n        size_t    offset;  // Pointer offset in bytes, relative to main_addr\n        uint64_t  length;  // Range length of data at pointer offset\n    };\n\n    struct LogChunk {\n        LogEntry  entries[CHUNK_SIZE];\n        uint64_t  num_entries { 0 };\n        LogChunk* next        { nullptr };\n    };\n\n    // There is always at least one (empty) chunk in the log, it's the head\n    LogChunk* log_head = new LogChunk;\n    LogChunk* log_tail = log_head;\n\n    // One instance of this is at the start of base_addr, in persistent memory\n    struct PersistentHeader {\n        uint64_t         id {0};          // Validates intialization\n        std::atomic<int> state {IDLE};    // Current state of consistency\n        void**           objects {};      // Objects directory\n#ifdef USE_ESLOCO\n#else\n        mspace           ms {};           // Pointer to allocator's metadata\n#endif\n        uint64_t         used_size {0};   // It has to be the last, to calculate the used_size\n    };\n\n    PersistentHeader* per {nullptr};      // Volatile pointer to start of persistent memory\n    uint64_t log_size = 0;\n    bool logEnabled = true;\n\n#ifdef USE_ESLOCO\n    EsLoco<persist> *esloco {nullptr};\n#endif\n\n    //\n    // Private methods\n    //\n\n    // Copy the data from 'main' to 'back'\n    void copyMainToBack();\n\n    // Copy the data from 'back' to 'main'\n    void copyBackToMain();\n\npublic:\n\n    int* histo  = new int[300]; // array of atomic pointers to functions\n    int storecount = 0;\n    // Flush touched cache lines\n    inline static void flush_range(uint8_t* addr, size_t length) noexcept {\n        const int cache_line_size = 64;\n        uint8_t* ptr = addr;\n        uint8_t* last = addr + length;\n        for (; ptr < last; ptr += cache_line_size) PWB(ptr);\n    }\n\n\n\nprivate:\n\n    /*\n     * Called to make every store persistent on main and back region\n     */\n    inline void apply_pwb(uint8_t* from_addr) {\n        // Apply the log to the instance on 'to_addr', copying data from the instance at 'from_addr'\n        LogChunk* chunk = log_head;\n        while (chunk != nullptr) {\n            for (int i = 0; i < chunk->num_entries; i++) {\n                LogEntry& e = chunk->entries[i];\n                //std::memcpy(to_addr + e.offset, from_addr + e.offset, e.length);\n                flush_range(from_addr + e.offset, e.length);\n\n            }\n            chunk = chunk->next;\n        }\n    }\n\n    /*\n     * Called at the end of a transaction to replicate the mutations on \"back\",\n     * or when abort_transaction() is called by the user, to rollback the\n     * mutations on \"main\".\n     * Deletes the log as it is being applied.\n     */\n    inline void apply_log(uint8_t* from_addr, uint8_t* to_addr) {\n        // Apply the log to the instance on 'to_addr', copying data from the instance at 'from_addr'\n        LogChunk* chunk = log_head;\n        while (chunk != nullptr) {\n            for (int i = 0; i < chunk->num_entries; i++) {\n                LogEntry& e = chunk->entries[i];\n                //printf(\"entry %i of %d from addr %p to addr %p  offset=%ld\\n\", i, chunk->num_entries, from_addr + e.offset, to_addr + e.offset, e.offset);\n                std::memcpy(to_addr + e.offset, from_addr + e.offset, e.length);\n            }\n            chunk = chunk->next;\n        }\n    }\n\n    inline void clear_log() {\n        LogChunk* chunk = log_head->next;\n        while (chunk != nullptr) {\n            LogChunk* next = chunk->next;\n            delete chunk;\n            chunk = next;\n        }\n        // Clear the log, leaving one chunk for next transaction, with zero'ed entries\n        log_tail = log_head;\n        log_head->num_entries = 0;\n        log_head->next = nullptr;\n    }\n\n\npublic:\n\n    /*\n        * Adds to the log the current contents of the memory location starting at\n        * 'addr' with a certain 'length' in bytes\n        */\n       inline void add_to_log(void* addr, int length) noexcept {\n           if (!logEnabled) return;\n           // If the log has more than 1/4 of the entire size then skip the log\n           // and copy the used size of the main region.\n           if (log_size > per->used_size/4) {\n               logEnabled = false;\n               return;\n           }\n\n           size_t addrCL = ((size_t)addr)>>6;\n           // Get the current chunk of log and if it is already full then create a new chunk and add the entry there.\n           LogChunk* chunk = log_tail;\n\n           bool sameCL = false;\n\n           if(addrCL == (size_t)((uint8_t*)addr+length)>>6){\n        \t   sameCL = true;\n        \t   int size = chunk->num_entries;\n        \t   for(int i=size-1;i>=0 && i>size-16;i--){\n        \t\t   LogEntry& e1 = chunk->entries[i];\n\n        \t\t   size_t offCL = (size_t)(e1.offset+main_addr)>>6;\n        \t\t   if(e1.length==64 && (size_t)(offCL<<6) == (size_t)(e1.offset+main_addr)){\n        \t\t\t   if(offCL == addrCL) return;\n        \t\t   }\n        \t   }\n           }\n           if (chunk->num_entries == CHUNK_SIZE) {\n               chunk = new LogChunk();\n               log_tail->next = chunk;\n               log_tail = chunk;\n           }\n           LogEntry& e = chunk->entries[chunk->num_entries];\n           if(histoOn) gRomLog.storecount+=2;\n           if(sameCL){\n        \t   size_t cl =addrCL<<6;\n               e.offset = (uint8_t*)cl - main_addr;\n               e.length = 64;\n           }else {\n        \t   e.offset = (uint8_t*)addr - main_addr;\n        \t   e.length = length;\n           }\n           log_size += length;\n           chunk->num_entries++;\n       }\n\n\n    RomulusLog();\n\n    ~RomulusLog();\n\n    static std::string className() { return \"RomulusLog\"; }\n\n\n    template <typename T>\n    static inline T* get_object(int idx) {\n        // Equivalent to persist<void*>.pload()\n        return (T*)gRomLog.per->objects[idx];\n    }\n\n    template <typename T>\n    static inline void put_object(int idx, T* obj) {\n        // Equivalent to persist<void*>.pstore()\n        gRomLog.add_to_log(&gRomLog.per->objects[idx],sizeof(T*));\n        gRomLog.per->objects[idx] = obj;\n        PWB(&gRomLog.per->objects[idx]);\n    }\n\n    void createFile();\n\n    void ns_reset();\n    static void reset();\n\n    /*\n     * Must be called at the beginning of each (write) transaction.\n     * This function has strict semantics.\n     */\n    inline void begin_transaction() {\n        // Check for nested transaction\n        tl_nested_write_trans++;\n        if (tl_nested_write_trans != 1) return;\n        per->state.store(MUTATING, std::memory_order_relaxed);\n        PWB(&per->state);\n        // One PFENCE() is enough for all user modifications because no ordering is needed between them.\n        PFENCE();\n    }\n\n\n    /*\n     * Must be called at the end of each (write) transaction.\n     * This function has strict semantics.\n     */\n    inline void end_transaction() {\n        // Check for nested transaction\n        --tl_nested_write_trans;\n        if (tl_nested_write_trans != 0) return;\n        // Do a PFENCE() to make persistent the stores done in 'main' and on\n        // the Romulus persistent data (due to memory allocation). We only care\n        // about ordering here, not durability, therefore, no need to block.\n        apply_pwb(main_addr);\n        PFENCE();\n        per->state.store(COPYING, std::memory_order_relaxed);\n        PWB(&per->state);\n        PWB(&per->used_size);\n        // PSYNC() here to have ACID Durability on the mutations done to 'main'\n        // and make the change of state visible.\n        PSYNC();\n        // Apply log, copying data from 'main' to 'back'\n        if (logEnabled) {\n            apply_log(main_addr, back_addr);\n            apply_pwb(back_addr);\n        } else {\n            copyMainToBack();\n            logEnabled = true;\n        }\n        clear_log();\n        log_size = 0;\n        PFENCE();\n        per->state.store(IDLE, std::memory_order_relaxed);\n    }\n\n\n    bool compareMainAndBack() {\n        if (std::memcmp(main_addr, back_addr, g_main_size) != 0) {\n            void* firstaddr = nullptr;\n            int sumdiff = 0;\n            for (size_t idx = 0; idx < g_main_size-sizeof(size_t); idx++) {\n                if (*(main_addr+idx) != *(back_addr+idx)) {\n                    printf(\"Difference at %p  main=%ld  back=%ld\\n\", main_addr+idx, *(int64_t*)(main_addr+idx), *(int64_t*)(back_addr+idx));\n                    sumdiff++;\n                    if (firstaddr == nullptr) firstaddr = main_addr+idx;\n                }\n            }\n            if (sumdiff != 0) {\n                printf(\"sumdiff=%d bytes\\n\", sumdiff);\n                printf(\"\\nThere seems to be a missing persist<T> in your code.\\n\");\n                printf(\"Rerun with gdb and set a watchpoint using the command\\nwatch * %p\\n\\n\", firstaddr);\n            }\n            assert(sumdiff == 0);\n        }\n        return true;\n    }\n\n\n    /*\n     * Recovers from an incomplete transaction if needed\n     */\n    inline void recover();\n\n\n    /*\n     * Meant to be called from user code when something bad happens and the\n     * whole transaction needs to be aborted.\n     */\n    inline void abort_transaction(void);\n\n\n    // Same as begin/end transaction, but with a lambda.\n    // Calling abort_transaction() from within the lambda is not allowed.\n    template<typename R, class F>\n    R transaction(F&& func) {\n        begin_transaction();\n        R retval = func();\n        end_transaction();\n        return retval;\n    }\n\n    template<class F>\n    static void transaction(F&& func) {\n        gRomLog.begin_transaction();\n        func();\n        gRomLog.end_transaction();\n    }\n\n\n    /*\n     * Non static, thread-safe\n     * Progress: Blocking (starvation-free)\n     */\n    template<class Func>\n    void ns_write_transaction(Func&& mutativeFunc) {\n        if (tl_nested_write_trans > 0) {\n            mutativeFunc();\n            return;\n        }\n        std::function<void()> myfunc = mutativeFunc;\n        int tid = ThreadRegistry::getTID();\n        // Add our mutation to the array of flat combining\n        fc[tid*CLPAD].store(&myfunc, std::memory_order_release);\n        // Lock writersMutex\n        while (true) {\n            if (rwlock.tryExclusiveLock()) break;\n            // Check if another thread executed my mutation\n            if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) return;\n            std::this_thread::yield();\n        }\n\n        bool somethingToDo = false;\n        const int maxTid = ThreadRegistry::getMaxThreads();\n        // Save a local copy of the flat combining array\n        std::function<void()>* lfc[maxTid];\n        for (int i = 0; i < maxTid; i++) {\n            lfc[i] = fc[i*CLPAD].load(std::memory_order_acquire);\n            if (lfc[i] != nullptr) somethingToDo = true;\n        }\n        // Check if there is at least one operation to apply\n        if (!somethingToDo) {\n            rwlock.exclusiveUnlock();\n            return;\n        }\n\n        if(histoflag) storecount=0;\n        per->state.store(MUTATING, std::memory_order_relaxed);\n        PWB(&per->state);\n        // One PFENCE() is enough for all user modifications because no ordering is needed between them.\n        PFENCE();\n        rwlock.waitForReaders();\n\n        ++tl_nested_write_trans;\n        // Apply all mutativeFunc\n        for (int i = 0; i < maxTid; i++) {\n            if (lfc[i] == nullptr) continue;\n            (*lfc[i])();\n        }\n        apply_pwb(main_addr);\n        PFENCE();\n        per->state.store(COPYING, std::memory_order_relaxed);\n        PWB(&per->state);\n        // PSYNC() here to have ACID Durability on the mutations done to 'main' and make the change of state visible\n        PSYNC();\n        // After changing changing state to COPYING all applied mutativeFunc are visible and persisted\n        for (int i = 0; i < maxTid; i++) {\n            if (lfc[i] == nullptr) continue;\n            fc[i*CLPAD].store(nullptr, std::memory_order_release);\n        }\n        // Apply log, copying data from 'main' to 'back'\n        if (logEnabled) {\n            apply_log(main_addr, back_addr);\n            apply_pwb(back_addr);\n        } else {\n            copyMainToBack();\n            logEnabled = true;\n        }\n        clear_log();\n        log_size = 0;\n\n        PFENCE();\n        per->state.store(IDLE, std::memory_order_relaxed);\n        if(histoflag) histo[storecount]++;\n        rwlock.exclusiveUnlock();\n        --tl_nested_write_trans;\n        //consistency_check();\n    }\n\n    // Non-static thread-safe read-only transaction\n    template<class Func>\n    void ns_read_transaction(Func&& readFunc) {\n        if (tl_nested_read_trans > 0) {\n            readFunc();\n            return;\n        }\n        int tid = ThreadRegistry::getTID();\n        ++tl_nested_read_trans;\n        rwlock.sharedLock(tid);\n        readFunc();\n        rwlock.sharedUnlock(tid);\n        --tl_nested_read_trans;\n    }\n\n    // static thread-safe read-only transaction\n    static void begin_read_transaction() {\n        int tid = ThreadRegistry::getTID();\n        gRomLog.rwlock.sharedLock(tid);\n    }\n\n    // static thread-safe read-only transaction\n    static void end_read_transaction() {\n        int tid = ThreadRegistry::getTID();\n        gRomLog.rwlock.sharedUnlock(tid);\n    }\n\n    /*\n     * Allocator\n     * This method calls Doug Lea's allocator to get a piece of persistent\n     * memory large enough to hold T, and then calls the constructor of T for\n     * that memory region.\n     */\n    template <typename T, typename... Args>\n    static T* tmNew(Args&&... args) {\n    \t//if(histoflag) histoOn = true;\n        const RomulusLog& r = gRomLog;\n#ifdef USE_ESLOCO\n        void* addr = r.esloco->malloc(sizeof(T));\n        assert(addr != nullptr);\n#else\n        void* addr = mspace_malloc(r.per->ms, sizeof(T));\n        assert(addr != 0);\n#endif\n        T* ptr = new (addr) T(std::forward<Args>(args)...); // placement new\n        if (r.per->used_size < (uint8_t*)addr - r.main_addr + sizeof(T)+128) {\n            r.per->used_size = (uint8_t*)addr - r.main_addr + sizeof(T)+128;\n            PWB(&r.per->used_size);\n        }\n        //if(histoflag) histoOn = false;\n        return ptr;\n    }\n\n\n    /*\n     * De-allocator\n     * Calls destructor of T and then reclaims the memory using Doug Lea's free\n     */\n    template<typename T>\n    static void tmDelete(T* obj) {\n        if (obj == nullptr) return;\n        //if(histoflag) histoOn =true;\n        obj->~T();\n#ifdef USE_ESLOCO\n        gRomLog.esloco->free(obj);\n#else\n        mspace_free(gRomLog.per->ms,obj);\n#endif\n        //if(histoflag) histoOn =false;\n    }\n\n\n    /* Allocator for C methods (like memcached) */\n    static void* pmalloc(size_t size) {\n    \t//if(histoflag) histoOn =true;\n        const RomulusLog& r = gRomLog;\n#ifdef USE_ESLOCO\n        void* addr = r.esloco->malloc(size);\n        assert(addr != nullptr);\n#else\n        void* addr = mspace_malloc(r.per->ms, size);\n        assert(addr != 0);\n#endif\n        if (r.per->used_size < (uint8_t*)addr - r.main_addr + size + 128) {\n            r.per->used_size = (uint8_t*)addr - r.main_addr + size + 128;\n            PWB(&r.per->used_size);\n        }\n        //if(histoflag) histoOn =false;\n        return addr;\n    }\n\n\n    /* De-allocator for C methods (like memcached) */\n    static void pfree(void* ptr) {\n    \t//if(histoflag) histoOn =true;\n#ifdef USE_ESLOCO\n        gRomLog.esloco->free(ptr);\n#else\n        mspace_free(gRomLog.per->ms,ptr);\n#endif\n    \t//if(histoflag) histoOn =false;\n    }\n\n    template<class F>\n    inline static void readTx(F&& func) {\n        gRomLog.ns_read_transaction(func);\n    }\n\n    template<class F>\n    inline static void updateTx(F&& func) {\n        gRomLog.ns_write_transaction(func);\n    }\n\n\n    // TODO: Remove these two once we make CX have void transactions\n    template<typename R,class F>\n    inline static R readTx(F&& func) {\n        gRomLog.ns_read_transaction([&]() {func();});\n        return R{};\n    }\n    template<typename R,class F>\n    inline static R updateTx(F&& func) {\n        gRomLog.ns_write_transaction([&]() {func();});\n        return R{};\n    }\n\n\n/*\n     * Thread-safe. Compares the contents of 'main' and 'back'.\n     * This method MUST be called outside a transaction.\n     */\n    static bool consistency_check(void) {\n        if (tl_nested_write_trans > 0) {\n            printf(\"Warning: don't call consistency_check() inside a transaction\\n\");\n        } else {\n            while (!gRomLog.rwlock.tryExclusiveLock()) std::this_thread::yield();\n            gRomLog.compareMainAndBack();\n            gRomLog.rwlock.exclusiveUnlock();\n        }\n        return true;\n    }\n};\n\n\n\n/*\n * Definition of persist<> type for RomulusLog.\n * In RomulusLog we need to interpose the stores and add them to the log, see pstore().\n */\ntemplate<typename T>\nstruct persist {\n    // Stores the actual value\n    T val;\n\n    persist() { }\n\n    persist(T initVal) {\n        pstore(initVal);\n    }\n\n    // Casting operator\n    operator T() {\n        return pload();\n    }\n\n    // Prefix increment operator: ++x\n    void operator++ () {\n        pstore(pload()+1);\n    }\n\n    // Prefix decrement operator: --x\n    void operator-- () {\n        pstore(pload()-1);\n    }\n\n    void operator++ (int) {\n        pstore(pload()+1);\n    }\n\n    void operator-- (int) {\n        pstore(pload()-1);\n    }\n\n    // Equals operator: first downcast to T and then compare\n    bool operator == (const T& otherval) const {\n        return pload() == otherval;\n    }\n\n    // Difference operator: first downcast to T and then compare\n    bool operator != (const T& otherval) const {\n        return pload() != otherval;\n    }\n\n    // Relational operators\n    bool operator < (const T& rhs) {\n        return pload() < rhs;\n    }\n    bool operator > (const T& rhs) {\n        return pload() > rhs;\n    }\n    bool operator <= (const T& rhs) {\n        return pload() <= rhs;\n    }\n    bool operator >= (const T& rhs) {\n        return pload() >= rhs;\n    }\n\n    T operator % (const T& rhs) {\n        return pload() % rhs;\n    }\n\n    // Operator arrow ->\n    T operator->() {\n        return pload();\n    }\n\n    // Operator &\n    T* operator&() {\n        return &val;\n    }\n\n    // Copy constructor\n    persist<T>(const persist<T>& other) {\n        pstore(other.pload());\n    }\n\n    // Assignment operator from an atomic_mwc\n    persist<T>& operator=(const persist<T>& other) {\n        pstore(other.pload());\n        return *this;\n    }\n\n    // Assignment operator from a value\n    persist<T>& operator=(T value) {\n        pstore(value);\n        return *this;\n    }\n\n    persist<T>& operator&=(T value) {\n        pstore(pload() & value);\n        return *this;\n    }\n\n    persist<T>& operator|=(T value) {\n        pstore(pload() | value);\n        return *this;\n    }\n    persist<T>& operator+=(T value) {\n        pstore(pload() + value);\n        return *this;\n    }\n    persist<T>& operator-=(T value) {\n        pstore(pload() - value);\n        return *this;\n    }\n\n    // Implementation is after RomulusLog class\n    inline void pstore(T newVal) {\n        val = newVal;\n        const uint8_t* valaddr = (uint8_t*)&val;\n        if (valaddr >= g_main_addr && valaddr < g_main_addr+g_main_size) {\n            //PWB(&val);\n            gRomLog.add_to_log(&val,sizeof(T));\n        }\n    }\n\n    inline T pload() const {\n        return val;\n    }\n};\n\n} // end of romuluslog namespace\n#endif  // _ROMULUS_LOG_PERSISTENT_TRANSACTIONAL_MEMORY_\n"
  },
  {
    "path": "ptms/romuluslog/malloc.cpp",
    "content": "/*\n  This is a version (aka dlmalloc) of malloc/free/realloc written by\n  Doug Lea and released to the public domain, as explained at\n  http://creativecommons.org/publicdomain/zero/1.0/ Send questions,\n  comments, complaints, performance data, etc to dl@cs.oswego.edu\n\n* Version 2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea\n   Note: There may be an updated version of this malloc obtainable at\n           ftp://gee.cs.oswego.edu/pub/misc/malloc.c\n         Check before installing!\n\n* Quickstart\n\n  This library is all in one file to simplify the most common usage:\n  ftp it, compile it (-O3), and link it into another program. All of\n  the compile-time options default to reasonable values for use on\n  most platforms.  You might later want to step through various\n  compile-time and dynamic tuning options.\n\n  For convenience, an include file for code using this malloc is at:\n     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h\n  You don't really need this .h file unless you call functions not\n  defined in your system include files.  The .h file contains only the\n  excerpts from this file needed for using this malloc on ANSI C/C++\n  systems, so long as you haven't changed compile-time options about\n  naming and tuning parameters.  If you do, then you can create your\n  own malloc.h that does include all settings by cutting at the point\n  indicated below. Note that you may already by default be using a C\n  library containing a malloc that is based on some version of this\n  malloc (for example in linux). You might still want to use the one\n  in this file to customize settings or to avoid overheads associated\n  with library versions.\n\n* Vital statistics:\n\n  Supported pointer/size_t representation:       4 or 8 bytes\n       size_t MUST be an unsigned type of the same width as\n       pointers. (If you are using an ancient system that declares\n       size_t as a signed type, or need it to be a different width\n       than pointers, you can use a previous release of this malloc\n       (e.g. 2.7.2) supporting these.)\n\n  Alignment:                                     8 bytes (minimum)\n       This suffices for nearly all current machines and C compilers.\n       However, you can define MALLOC_ALIGNMENT to be wider than this\n       if necessary (up to 128bytes), at the expense of using more space.\n\n  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)\n                                          8 or 16 bytes (if 8byte sizes)\n       Each malloced chunk has a hidden word of overhead holding size\n       and status information, and additional cross-check word\n       if FOOTERS is defined.\n\n  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)\n                          8-byte ptrs:  32 bytes    (including overhead)\n\n       Even a request for zero bytes (i.e., malloc(0)) returns a\n       pointer to something of the minimum allocatable size.\n       The maximum overhead wastage (i.e., number of extra bytes\n       allocated than were requested in malloc) is less than or equal\n       to the minimum size, except for requests >= mmap_threshold that\n       are serviced via mmap(), where the worst case wastage is about\n       32 bytes plus the remainder from a system page (the minimal\n       mmap unit); typically 4096 or 8192 bytes.\n\n  Security: static-safe; optionally more or less\n       The \"security\" of malloc refers to the ability of malicious\n       code to accentuate the effects of errors (for example, freeing\n       space that is not currently malloc'ed or overwriting past the\n       ends of chunks) in code that calls malloc.  This malloc\n       guarantees not to modify any memory locations below the base of\n       heap, i.e., static variables, even in the presence of usage\n       errors.  The routines additionally detect most improper frees\n       and reallocs.  All this holds as long as the static bookkeeping\n       for malloc itself is not corrupted by some other means.  This\n       is only one aspect of security -- these checks do not, and\n       cannot, detect all possible programming errors.\n\n       If FOOTERS is defined nonzero, then each allocated chunk\n       carries an additional check word to verify that it was malloced\n       from its space.  These check words are the same within each\n       execution of a program using malloc, but differ across\n       executions, so externally crafted fake chunks cannot be\n       freed. This improves security by rejecting frees/reallocs that\n       could corrupt heap memory, in addition to the checks preventing\n       writes to statics that are always on.  This may further improve\n       security at the expense of time and space overhead.  (Note that\n       FOOTERS may also be worth using with MSPACES.)\n\n       By default detected errors cause the program to abort (calling\n       \"abort()\"). You can override this to instead proceed past\n       errors by defining PROCEED_ON_ERROR.  In this case, a bad free\n       has no effect, and a malloc that encounters a bad address\n       caused by user overwrites will ignore the bad address by\n       dropping pointers and indices to all known memory. This may\n       be appropriate for programs that should continue if at all\n       possible in the face of programming errors, although they may\n       run out of memory because dropped memory is never reclaimed.\n\n       If you don't like either of these options, you can define\n       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything\n       else. And if if you are sure that your program using malloc has\n       no errors or vulnerabilities, you can define INSECURE to 1,\n       which might (or might not) provide a small performance improvement.\n\n       It is also possible to limit the maximum total allocatable\n       space, using malloc_set_footprint_limit. This is not\n       designed as a security feature in itself (calls to set limits\n       are not screened or privileged), but may be useful as one\n       aspect of a secure implementation.\n\n  Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero\n       When USE_LOCKS is defined, each public call to malloc, free,\n       etc is surrounded with a lock. By default, this uses a plain\n       pthread mutex, win32 critical section, or a spin-lock if if\n       available for the platform and not disabled by setting\n       USE_SPIN_LOCKS=0.  However, if USE_RECURSIVE_LOCKS is defined,\n       recursive versions are used instead (which are not required for\n       base functionality but may be needed in layered extensions).\n       Using a global lock is not especially fast, and can be a major\n       bottleneck.  It is designed only to provide minimal protection\n       in concurrent environments, and to provide a basis for\n       extensions.  If you are using malloc in a concurrent program,\n       consider instead using nedmalloc\n       (http://www.nedprod.com/programs/portable/nedmalloc/) or\n       ptmalloc (See http://www.malloc.de), which are derived from\n       versions of this malloc.\n\n  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP\n       This malloc can use unix sbrk or any emulation (invoked using\n       the CALL_MORECORE macro) and/or mmap/munmap or any emulation\n       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system\n       memory.  On most unix systems, it tends to work best if both\n       MORECORE and MMAP are enabled.  On Win32, it uses emulations\n       based on VirtualAlloc. It also uses common C library functions\n       like memset.\n\n  Compliance: I believe it is compliant with the Single Unix Specification\n       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably\n       others as well.\n\n* Overview of algorithms\n\n  This is not the fastest, most space-conserving, most portable, or\n  most tunable malloc ever written. However it is among the fastest\n  while also being among the most space-conserving, portable and\n  tunable.  Consistent balance across these factors results in a good\n  general-purpose allocator for malloc-intensive programs.\n\n  In most ways, this malloc is a best-fit allocator. Generally, it\n  chooses the best-fitting existing chunk for a request, with ties\n  broken in approximately least-recently-used order. (This strategy\n  normally maintains low fragmentation.) However, for requests less\n  than 256bytes, it deviates from best-fit when there is not an\n  exactly fitting available chunk by preferring to use space adjacent\n  to that used for the previous small request, as well as by breaking\n  ties in approximately most-recently-used order. (These enhance\n  locality of series of small allocations.)  And for very large requests\n  (>= 256Kb by default), it relies on system memory mapping\n  facilities, if supported.  (This helps avoid carrying around and\n  possibly fragmenting memory used only for large chunks.)\n\n  All operations (except malloc_stats and mallinfo) have execution\n  times that are bounded by a constant factor of the number of bits in\n  a size_t, not counting any clearing in calloc or copying in realloc,\n  or actions surrounding MORECORE and MMAP that have times\n  proportional to the number of non-contiguous regions returned by\n  system allocation routines, which is often just 1. In real-time\n  applications, you can optionally suppress segment traversals using\n  NO_SEGMENT_TRAVERSAL, which assures bounded execution even when\n  system allocators return non-contiguous spaces, at the typical\n  expense of carrying around more memory and increased fragmentation.\n\n  The implementation is not very modular and seriously overuses\n  macros. Perhaps someday all C compilers will do as good a job\n  inlining modular code as can now be done by brute-force expansion,\n  but now, enough of them seem not to.\n\n  Some compilers issue a lot of warnings about code that is\n  dead/unreachable only on some platforms, and also about intentional\n  uses of negation on unsigned types. All known cases of each can be\n  ignored.\n\n  For a longer but out of date high-level description, see\n     http://gee.cs.oswego.edu/dl/html/malloc.html\n\n* MSPACES\n  If MSPACES is defined, then in addition to malloc, free, etc.,\n  this file also defines mspace_malloc, mspace_free, etc. These\n  are versions of malloc routines that take an \"mspace\" argument\n  obtained using create_mspace, to control all internal bookkeeping.\n  If ONLY_MSPACES is defined, only these versions are compiled.\n  So if you would like to use this allocator for only some allocations,\n  and your system malloc for others, you can compile with\n  ONLY_MSPACES and then do something like...\n    static mspace mymspace = create_mspace(0,0); // for example\n    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)\n\n  (Note: If you only need one instance of an mspace, you can instead\n  use \"USE_DL_PREFIX\" to relabel the global malloc.)\n\n  You can similarly create thread-local allocators by storing\n  mspaces as thread-locals. For example:\n    static __thread mspace tlms = 0;\n    void*  tlmalloc(size_t bytes) {\n      if (tlms == 0) tlms = create_mspace(0, 0);\n      return mspace_malloc(tlms, bytes);\n    }\n    void  tlfree(void* mem) { mspace_free(tlms, mem); }\n\n  Unless FOOTERS is defined, each mspace is completely independent.\n  You cannot allocate from one and free to another (although\n  conformance is only weakly checked, so usage errors are not always\n  caught). If FOOTERS is defined, then each chunk carries around a tag\n  indicating its originating mspace, and frees are directed to their\n  originating spaces. Normally, this requires use of locks.\n\n -------------------------  Compile-time options ---------------------------\n\nBe careful in setting #define values for numerical constants of type\nsize_t. On some systems, literal values are not automatically extended\nto size_t precision unless they are explicitly casted. You can also\nuse the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.\n\nWIN32                    default: defined if _WIN32 defined\n  Defining WIN32 sets up defaults for MS environment and compilers.\n  Otherwise defaults are for unix. Beware that there seem to be some\n  cases where this malloc might not be a pure drop-in replacement for\n  Win32 malloc: Random-looking failures from Win32 GDI API's (eg;\n  SetDIBits()) may be due to bugs in some video driver implementations\n  when pixel buffers are malloc()ed, and the region spans more than\n  one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)\n  default granularity, pixel buffers may straddle virtual allocation\n  regions more often than when using the Microsoft allocator.  You can\n  avoid this by using VirtualAlloc() and VirtualFree() for all pixel\n  buffers rather than using malloc().  If this is not possible,\n  recompile this malloc with a larger DEFAULT_GRANULARITY. Note:\n  in cases where MSC and gcc (cygwin) are known to differ on WIN32,\n  conditions use _MSC_VER to distinguish them.\n\nDLMALLOC_EXPORT       default: extern\n  Defines how public APIs are declared. If you want to export via a\n  Windows DLL, you might define this as\n    #define DLMALLOC_EXPORT extern  __declspec(dllexport)\n  If you want a POSIX ELF shared object, you might use\n    #define DLMALLOC_EXPORT extern __attribute__((visibility(\"default\")))\n\nMALLOC_ALIGNMENT         default: (size_t)(2 * sizeof(void *))\n  Controls the minimum alignment for malloc'ed chunks.  It must be a\n  power of two and at least 8, even on machines for which smaller\n  alignments would suffice. It may be defined as larger than this\n  though. Note however that code and data structures are optimized for\n  the case of 8-byte alignment.\n\nMSPACES                  default: 0 (false)\n  If true, compile in support for independent allocation spaces.\n  This is only supported if HAVE_MMAP is true.\n\nONLY_MSPACES             default: 0 (false)\n  If true, only compile in mspace versions, not regular versions.\n\nUSE_LOCKS                default: 0 (false)\n  Causes each call to each public routine to be surrounded with\n  pthread or WIN32 mutex lock/unlock. (If set true, this can be\n  overridden on a per-mspace basis for mspace versions.) If set to a\n  non-zero value other than 1, locks are used, but their\n  implementation is left out, so lock functions must be supplied manually,\n  as described below.\n\nUSE_SPIN_LOCKS           default: 1 iff USE_LOCKS and spin locks available\n  If true, uses custom spin locks for locking. This is currently\n  supported only gcc >= 4.1, older gccs on x86 platforms, and recent\n  MS compilers.  Otherwise, posix locks or win32 critical sections are\n  used.\n\nUSE_RECURSIVE_LOCKS      default: not defined\n  If defined nonzero, uses recursive (aka reentrant) locks, otherwise\n  uses plain mutexes. This is not required for malloc proper, but may\n  be needed for layered allocators such as nedmalloc.\n\nLOCK_AT_FORK            default: not defined\n  If defined nonzero, performs pthread_atfork upon initialization\n  to initialize child lock while holding parent lock. The implementation\n  assumes that pthread locks (not custom locks) are being used. In other\n  cases, you may need to customize the implementation.\n\nFOOTERS                  default: 0\n  If true, provide extra checking and dispatching by placing\n  information in the footers of allocated chunks. This adds\n  space and time overhead.\n\nINSECURE                 default: 0\n  If true, omit checks for usage errors and heap space overwrites.\n\nUSE_DL_PREFIX            default: NOT defined\n  Causes compiler to prefix all public routines with the string 'dl'.\n  This can be useful when you only want to use this malloc in one part\n  of a program, using your regular system malloc elsewhere.\n\nMALLOC_INSPECT_ALL       default: NOT defined\n  If defined, compiles malloc_inspect_all and mspace_inspect_all, that\n  perform traversal of all heap space.  Unless access to these\n  functions is otherwise restricted, you probably do not want to\n  include them in secure implementations.\n\nABORT                    default: defined as abort()\n  Defines how to abort on failed checks.  On most systems, a failed\n  check cannot die with an \"assert\" or even print an informative\n  message, because the underlying print routines in turn call malloc,\n  which will fail again.  Generally, the best policy is to simply call\n  abort(). It's not very useful to do more than this because many\n  errors due to overwriting will show up as address faults (null, odd\n  addresses etc) rather than malloc-triggered checks, so will also\n  abort.  Also, most compilers know that abort() does not return, so\n  can better optimize code conditionally calling it.\n\nPROCEED_ON_ERROR           default: defined as 0 (false)\n  Controls whether detected bad addresses cause them to bypassed\n  rather than aborting. If set, detected bad arguments to free and\n  realloc are ignored. And all bookkeeping information is zeroed out\n  upon a detected overwrite of freed heap space, thus losing the\n  ability to ever return it from malloc again, but enabling the\n  application to proceed. If PROCEED_ON_ERROR is defined, the\n  static variable malloc_corruption_error_count is compiled in\n  and can be examined to see if errors have occurred. This option\n  generates slower code than the default abort policy.\n\nDEBUG                    default: NOT defined\n  The DEBUG setting is mainly intended for people trying to modify\n  this code or diagnose problems when porting to new platforms.\n  However, it may also be able to better isolate user errors than just\n  using runtime checks.  The assertions in the check routines spell\n  out in more detail the assumptions and invariants underlying the\n  algorithms.  The checking is fairly extensive, and will slow down\n  execution noticeably. Calling malloc_stats or mallinfo with DEBUG\n  set will attempt to check every non-mmapped allocated and free chunk\n  in the course of computing the summaries.\n\nABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)\n  Debugging assertion failures can be nearly impossible if your\n  version of the assert macro causes malloc to be called, which will\n  lead to a cascade of further failures, blowing the runtime stack.\n  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),\n  which will usually make debugging easier.\n\nMALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32\n  The action to take before \"return 0\" when malloc fails to be able to\n  return memory because there is none available.\n\nHAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES\n  True if this system supports sbrk or an emulation of it.\n\nMORECORE                  default: sbrk\n  The name of the sbrk-style system routine to call to obtain more\n  memory.  See below for guidance on writing custom MORECORE\n  functions. The type of the argument to sbrk/MORECORE varies across\n  systems.  It cannot be size_t, because it supports negative\n  arguments, so it is normally the signed type of the same width as\n  size_t (sometimes declared as \"intptr_t\").  It doesn't much matter\n  though. Internally, we only call it with arguments less than half\n  the max value of a size_t, which should work across all reasonable\n  possibilities, although sometimes generating compiler warnings.\n\nMORECORE_CONTIGUOUS       default: 1 (true) if HAVE_MORECORE\n  If true, take advantage of fact that consecutive calls to MORECORE\n  with positive arguments always return contiguous increasing\n  addresses.  This is true of unix sbrk. It does not hurt too much to\n  set it true anyway, since malloc copes with non-contiguities.\n  Setting it false when definitely non-contiguous saves time\n  and possibly wasted space it would take to discover this though.\n\nMORECORE_CANNOT_TRIM      default: NOT defined\n  True if MORECORE cannot release space back to the system when given\n  negative arguments. This is generally necessary only if you are\n  using a hand-crafted MORECORE function that cannot handle negative\n  arguments.\n\nNO_SEGMENT_TRAVERSAL       default: 0\n  If non-zero, suppresses traversals of memory segments\n  returned by either MORECORE or CALL_MMAP. This disables\n  merging of segments that are contiguous, and selectively\n  releasing them to the OS if unused, but bounds execution times.\n\nHAVE_MMAP                 default: 1 (true)\n  True if this system supports mmap or an emulation of it.  If so, and\n  HAVE_MORECORE is not true, MMAP is used for all system\n  allocation. If set and HAVE_MORECORE is true as well, MMAP is\n  primarily used to directly allocate very large blocks. It is also\n  used as a backup strategy in cases where MORECORE fails to provide\n  space from system. Note: A single call to MUNMAP is assumed to be\n  able to unmap memory that may have be allocated using multiple calls\n  to MMAP, so long as they are adjacent.\n\nHAVE_MREMAP               default: 1 on linux, else 0\n  If true realloc() uses mremap() to re-allocate large blocks and\n  extend or shrink allocation spaces.\n\nMMAP_CLEARS               default: 1 except on WINCE.\n  True if mmap clears memory so calloc doesn't need to. This is true\n  for standard unix mmap using /dev/zero and on WIN32 except for WINCE.\n\nUSE_BUILTIN_FFS            default: 0 (i.e., not used)\n  Causes malloc to use the builtin ffs() function to compute indices.\n  Some compilers may recognize and intrinsify ffs to be faster than the\n  supplied C version. Also, the case of x86 using gcc is special-cased\n  to an asm instruction, so is already as fast as it can be, and so\n  this setting has no effect. Similarly for Win32 under recent MS compilers.\n  (On most x86s, the asm version is only slightly faster than the C version.)\n\nmalloc_getpagesize         default: derive from system includes, or 4096.\n  The system page size. To the extent possible, this malloc manages\n  memory from the system in page-size units.  This may be (and\n  usually is) a function rather than a constant. This is ignored\n  if WIN32, where page size is determined using getSystemInfo during\n  initialization.\n\nUSE_DEV_RANDOM             default: 0 (i.e., not used)\n  Causes malloc to use /dev/random to initialize secure magic seed for\n  stamping footers. Otherwise, the current time is used.\n\nNO_MALLINFO                default: 0\n  If defined, don't compile \"mallinfo\". This can be a simple way\n  of dealing with mismatches between system declarations and\n  those in this file.\n\nMALLINFO_FIELD_TYPE        default: size_t\n  The type of the fields in the mallinfo struct. This was originally\n  defined as \"int\" in SVID etc, but is more usefully defined as\n  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set\n\nNO_MALLOC_STATS            default: 0\n  If defined, don't compile \"malloc_stats\". This avoids calls to\n  fprintf and bringing in stdio dependencies you might not want.\n\nREALLOC_ZERO_BYTES_FREES    default: not defined\n  This should be set if a call to realloc with zero bytes should\n  be the same as a call to free. Some people think it should. Otherwise,\n  since this malloc returns a unique pointer for malloc(0), so does\n  realloc(p, 0).\n\nLACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H\nLACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H\nLACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H  default: NOT defined unless on WIN32\n  Define these if your system does not have these header files.\n  You might need to manually insert some of the declarations they provide.\n\nDEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,\n                                system_info.dwAllocationGranularity in WIN32,\n                                otherwise 64K.\n      Also settable using mallopt(M_GRANULARITY, x)\n  The unit for allocating and deallocating memory from the system.  On\n  most systems with contiguous MORECORE, there is no reason to\n  make this more than a page. However, systems with MMAP tend to\n  either require or encourage larger granularities.  You can increase\n  this value to prevent system allocation functions to be called so\n  often, especially if they are slow.  The value must be at least one\n  page and must be a power of two.  Setting to 0 causes initialization\n  to either page size or win32 region size.  (Note: In previous\n  versions of malloc, the equivalent of this option was called\n  \"TOP_PAD\")\n\nDEFAULT_TRIM_THRESHOLD    default: 2MB\n      Also settable using mallopt(M_TRIM_THRESHOLD, x)\n  The maximum amount of unused top-most memory to keep before\n  releasing via malloc_trim in free().  Automatic trimming is mainly\n  useful in long-lived programs using contiguous MORECORE.  Because\n  trimming via sbrk can be slow on some systems, and can sometimes be\n  wasteful (in cases where programs immediately afterward allocate\n  more large chunks) the value should be high enough so that your\n  overall system performance would improve by releasing this much\n  memory.  As a rough guide, you might set to a value close to the\n  average size of a process (program) running on your system.\n  Releasing this much memory would allow such a process to run in\n  memory.  Generally, it is worth tuning trim thresholds when a\n  program undergoes phases where several large chunks are allocated\n  and released in ways that can reuse each other's storage, perhaps\n  mixed with phases where there are no such chunks at all. The trim\n  value must be greater than page size to have any useful effect.  To\n  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick\n  some people use of mallocing a huge space and then freeing it at\n  program startup, in an attempt to reserve system memory, doesn't\n  have the intended effect under automatic trimming, since that memory\n  will immediately be returned to the system.\n\nDEFAULT_MMAP_THRESHOLD       default: 256K\n      Also settable using mallopt(M_MMAP_THRESHOLD, x)\n  The request size threshold for using MMAP to directly service a\n  request. Requests of at least this size that cannot be allocated\n  using already-existing space will be serviced via mmap.  (If enough\n  normal freed space already exists it is used instead.)  Using mmap\n  segregates relatively large chunks of memory so that they can be\n  individually obtained and released from the host system. A request\n  serviced through mmap is never reused by any other request (at least\n  not directly; the system may just so happen to remap successive\n  requests to the same locations).  Segregating space in this way has\n  the benefits that: Mmapped space can always be individually released\n  back to the system, which helps keep the system level memory demands\n  of a long-lived program low.  Also, mapped memory doesn't become\n  `locked' between other chunks, as can happen with normally allocated\n  chunks, which means that even trimming via malloc_trim would not\n  release them.  However, it has the disadvantage that the space\n  cannot be reclaimed, consolidated, and then used to service later\n  requests, as happens with normal chunks.  The advantages of mmap\n  nearly always outweigh disadvantages for \"large\" chunks, but the\n  value of \"large\" may vary across systems.  The default is an\n  empirically derived value that works well in most systems. You can\n  disable mmap by setting to MAX_SIZE_T.\n\nMAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP\n  The number of consolidated frees between checks to release\n  unused segments when freeing. When using non-contiguous segments,\n  especially with multiple mspaces, checking only for topmost space\n  doesn't always suffice to trigger trimming. To compensate for this,\n  free() will, with a period of MAX_RELEASE_CHECK_RATE (or the\n  current number of segments, if greater) try to release unused\n  segments to the OS when freeing chunks that result in\n  consolidation. The best value for this parameter is a compromise\n  between slowing down frees with relatively costly checks that\n  rarely trigger versus holding on to unused memory. To effectively\n  disable, set to MAX_SIZE_T. This may lead to a very slight speed\n  improvement at the expense of carrying around more memory.\n*/\n#include \"RomulusLog.hpp\"\n//modification by Andreia\n#define ONLY_MSPACES 1\n\n/* Version identifier to allow people to support multiple versions */\n#ifndef DLMALLOC_VERSION\n#define DLMALLOC_VERSION 20806\n#endif /* DLMALLOC_VERSION */\n\n#ifndef DLMALLOC_EXPORT\n#define DLMALLOC_EXPORT extern\n#endif\n\n#ifndef WIN32\n#ifdef _WIN32\n#define WIN32 1\n#endif  /* _WIN32 */\n#ifdef _WIN32_WCE\n#define LACKS_FCNTL_H\n#define WIN32 1\n#endif /* _WIN32_WCE */\n#endif  /* WIN32 */\n#ifdef WIN32\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <tchar.h>\n#define HAVE_MMAP 1\n#define HAVE_MORECORE 0\n#define LACKS_UNISTD_H\n#define LACKS_SYS_PARAM_H\n#define LACKS_SYS_MMAN_H\n#define LACKS_STRING_H\n#define LACKS_STRINGS_H\n#define LACKS_SYS_TYPES_H\n#define LACKS_ERRNO_H\n#define LACKS_SCHED_H\n#ifndef MALLOC_FAILURE_ACTION\n#define MALLOC_FAILURE_ACTION\n#endif /* MALLOC_FAILURE_ACTION */\n#ifndef MMAP_CLEARS\n#ifdef _WIN32_WCE /* WINCE reportedly does not clear */\n#define MMAP_CLEARS 0\n#else\n#define MMAP_CLEARS 1\n#endif /* _WIN32_WCE */\n#endif /*MMAP_CLEARS */\n#endif  /* WIN32 */\n\n#if defined(DARWIN) || defined(_DARWIN)\n/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */\n#ifndef HAVE_MORECORE\n#define HAVE_MORECORE 0\n#define HAVE_MMAP 1\n/* OSX allocators provide 16 byte alignment */\n#ifndef MALLOC_ALIGNMENT\n#define MALLOC_ALIGNMENT ((size_t)16U)\n#endif\n#endif  /* HAVE_MORECORE */\n#endif  /* DARWIN */\n\n#ifndef LACKS_SYS_TYPES_H\n#include <sys/types.h>  /* For size_t */\n#endif  /* LACKS_SYS_TYPES_H */\n\n/* The maximum possible size_t value has all bits set */\n#define MAX_SIZE_T           (~(size_t)0)\n\n#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */\n#define USE_LOCKS  ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \\\n                    (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0))\n#endif /* USE_LOCKS */\n\n#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */\n#if ((defined(__GNUC__) &&                                              \\\n      ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) ||      \\\n       defined(__i386__) || defined(__x86_64__))) ||                    \\\n     (defined(_MSC_VER) && _MSC_VER>=1310))\n#ifndef USE_SPIN_LOCKS\n#define USE_SPIN_LOCKS 1\n#endif /* USE_SPIN_LOCKS */\n#elif USE_SPIN_LOCKS\n#error \"USE_SPIN_LOCKS defined without implementation\"\n#endif /* ... locks available... */\n#elif !defined(USE_SPIN_LOCKS)\n#define USE_SPIN_LOCKS 0\n#endif /* USE_LOCKS */\n\n#ifndef ONLY_MSPACES\n#define ONLY_MSPACES 0\n#endif  /* ONLY_MSPACES */\n#ifndef MSPACES\n#if ONLY_MSPACES\n#define MSPACES 1\n#else   /* ONLY_MSPACES */\n#define MSPACES 0\n#endif  /* ONLY_MSPACES */\n#endif  /* MSPACES */\n#ifndef MALLOC_ALIGNMENT\n#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))\n#endif  /* MALLOC_ALIGNMENT */\n#ifndef FOOTERS\n#define FOOTERS 0\n#endif  /* FOOTERS */\n#ifndef ABORT\n#define ABORT  abort()\n#endif  /* ABORT */\n#ifndef ABORT_ON_ASSERT_FAILURE\n#define ABORT_ON_ASSERT_FAILURE 1\n#endif  /* ABORT_ON_ASSERT_FAILURE */\n#ifndef PROCEED_ON_ERROR\n#define PROCEED_ON_ERROR 0\n#endif  /* PROCEED_ON_ERROR */\n\n#ifndef INSECURE\n#define INSECURE 0\n#endif  /* INSECURE */\n#ifndef MALLOC_INSPECT_ALL\n#define MALLOC_INSPECT_ALL 0\n#endif  /* MALLOC_INSPECT_ALL */\n#ifndef HAVE_MMAP\n#define HAVE_MMAP 1\n#endif  /* HAVE_MMAP */\n#ifndef MMAP_CLEARS\n#define MMAP_CLEARS 1\n#endif  /* MMAP_CLEARS */\n#ifndef HAVE_MREMAP\n#ifdef linux\n#define HAVE_MREMAP 1\n#define _GNU_SOURCE /* Turns on mremap() definition */\n#else   /* linux */\n#define HAVE_MREMAP 0\n#endif  /* linux */\n#endif  /* HAVE_MREMAP */\n#ifndef MALLOC_FAILURE_ACTION\n#define MALLOC_FAILURE_ACTION  errno = ENOMEM;\n#endif  /* MALLOC_FAILURE_ACTION */\n#ifndef HAVE_MORECORE\n#if ONLY_MSPACES\n#define HAVE_MORECORE 0\n#else   /* ONLY_MSPACES */\n#define HAVE_MORECORE 1\n#endif  /* ONLY_MSPACES */\n#endif  /* HAVE_MORECORE */\n#if !HAVE_MORECORE\n#define MORECORE_CONTIGUOUS 0\n#else   /* !HAVE_MORECORE */\n#define MORECORE_DEFAULT sbrk\n#ifndef MORECORE_CONTIGUOUS\n#define MORECORE_CONTIGUOUS 1\n#endif  /* MORECORE_CONTIGUOUS */\n#endif  /* HAVE_MORECORE */\n#ifndef DEFAULT_GRANULARITY\n#if (MORECORE_CONTIGUOUS || defined(WIN32))\n#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */\n#else   /* MORECORE_CONTIGUOUS */\n#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)\n#endif  /* MORECORE_CONTIGUOUS */\n#endif  /* DEFAULT_GRANULARITY */\n#ifndef DEFAULT_TRIM_THRESHOLD\n#ifndef MORECORE_CANNOT_TRIM\n#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)\n#else   /* MORECORE_CANNOT_TRIM */\n#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T\n#endif  /* MORECORE_CANNOT_TRIM */\n#endif  /* DEFAULT_TRIM_THRESHOLD */\n#ifndef DEFAULT_MMAP_THRESHOLD\n#if HAVE_MMAP\n#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)\n#else   /* HAVE_MMAP */\n#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T\n#endif  /* HAVE_MMAP */\n#endif  /* DEFAULT_MMAP_THRESHOLD */\n#ifndef MAX_RELEASE_CHECK_RATE\n#if HAVE_MMAP\n#define MAX_RELEASE_CHECK_RATE 4095\n#else\n#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T\n#endif /* HAVE_MMAP */\n#endif /* MAX_RELEASE_CHECK_RATE */\n#ifndef USE_BUILTIN_FFS\n#define USE_BUILTIN_FFS 0\n#endif  /* USE_BUILTIN_FFS */\n#ifndef USE_DEV_RANDOM\n#define USE_DEV_RANDOM 0\n#endif  /* USE_DEV_RANDOM */\n#ifndef NO_MALLINFO\n#define NO_MALLINFO 0\n#endif  /* NO_MALLINFO */\n#ifndef MALLINFO_FIELD_TYPE\n#define MALLINFO_FIELD_TYPE size_t\n#endif  /* MALLINFO_FIELD_TYPE */\n#ifndef NO_MALLOC_STATS\n#define NO_MALLOC_STATS 0\n#endif  /* NO_MALLOC_STATS */\n#ifndef NO_SEGMENT_TRAVERSAL\n#define NO_SEGMENT_TRAVERSAL 0\n#endif /* NO_SEGMENT_TRAVERSAL */\n\n/*\n  mallopt tuning options.  SVID/XPG defines four standard parameter\n  numbers for mallopt, normally defined in malloc.h.  None of these\n  are used in this malloc, so setting them has no effect. But this\n  malloc does support the following options.\n*/\n\n#define M_TRIM_THRESHOLD     (-1)\n#define M_GRANULARITY        (-2)\n#define M_MMAP_THRESHOLD     (-3)\n\n/* ------------------------ Mallinfo declarations ------------------------ */\n\n#if !NO_MALLINFO\n/*\n  This version of malloc supports the standard SVID/XPG mallinfo\n  routine that returns a struct containing usage properties and\n  statistics. It should work on any system that has a\n  /usr/include/malloc.h defining struct mallinfo.  The main\n  declaration needed is the mallinfo struct that is returned (by-copy)\n  by mallinfo().  The malloinfo struct contains a bunch of fields that\n  are not even meaningful in this version of malloc.  These fields are\n  are instead filled by mallinfo() with other numbers that might be of\n  interest.\n\n  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a\n  /usr/include/malloc.h file that includes a declaration of struct\n  mallinfo.  If so, it is included; else a compliant version is\n  declared below.  These must be precisely the same for mallinfo() to\n  work.  The original SVID version of this struct, defined on most\n  systems with mallinfo, declares all fields as ints. But some others\n  define as unsigned long. If your system defines the fields using a\n  type of different width than listed here, you MUST #include your\n  system version and #define HAVE_USR_INCLUDE_MALLOC_H.\n*/\n\n/* #define HAVE_USR_INCLUDE_MALLOC_H */\n\n#ifdef HAVE_USR_INCLUDE_MALLOC_H\n#include \"/usr/include/malloc.h\"\n#else /* HAVE_USR_INCLUDE_MALLOC_H */\n#ifndef STRUCT_MALLINFO_DECLARED\n/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */\n#define _STRUCT_MALLINFO\n#define STRUCT_MALLINFO_DECLARED 1\nstruct mallinfo {\n  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */\n  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */\n  MALLINFO_FIELD_TYPE smblks;   /* always 0 */\n  MALLINFO_FIELD_TYPE hblks;    /* always 0 */\n  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */\n  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */\n  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */\n  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */\n  MALLINFO_FIELD_TYPE fordblks; /* total free space */\n  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */\n};\n#endif /* STRUCT_MALLINFO_DECLARED */\n#endif /* HAVE_USR_INCLUDE_MALLOC_H */\n#endif /* NO_MALLINFO */\n\n/*\n  Try to persuade compilers to inline. The most critical functions for\n  inlining are defined as macros, so these aren't used for them.\n*/\n\n#ifndef FORCEINLINE\n  #if defined(__GNUC__)\n#define FORCEINLINE __inline __attribute__ ((always_inline))\n  #elif defined(_MSC_VER)\n    #define FORCEINLINE __forceinline\n  #endif\n#endif\n#ifndef NOINLINE\n  #if defined(__GNUC__)\n    #define NOINLINE __attribute__ ((noinline))\n  #elif defined(_MSC_VER)\n    #define NOINLINE __declspec(noinline)\n  #else\n    #define NOINLINE\n  #endif\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#ifndef FORCEINLINE\n #define FORCEINLINE inline\n#endif\n#endif /* __cplusplus */\n#ifndef FORCEINLINE\n #define FORCEINLINE\n#endif\n\n#if !ONLY_MSPACES\n\n/* ------------------- Declarations of public routines ------------------- */\n\n#ifndef USE_DL_PREFIX\n#define dlcalloc               calloc\n#define dlfree                 free\n#define dlmalloc               malloc\n#define dlmemalign             memalign\n#define dlposix_memalign       posix_memalign\n#define dlrealloc              realloc\n#define dlrealloc_in_place     realloc_in_place\n#define dlvalloc               valloc\n#define dlpvalloc              pvalloc\n#define dlmallinfo             mallinfo\n#define dlmallopt              mallopt\n#define dlmalloc_trim          malloc_trim\n#define dlmalloc_stats         malloc_stats\n#define dlmalloc_usable_size   malloc_usable_size\n#define dlmalloc_footprint     malloc_footprint\n#define dlmalloc_max_footprint malloc_max_footprint\n#define dlmalloc_footprint_limit malloc_footprint_limit\n#define dlmalloc_set_footprint_limit malloc_set_footprint_limit\n#define dlmalloc_inspect_all   malloc_inspect_all\n#define dlindependent_calloc   independent_calloc\n#define dlindependent_comalloc independent_comalloc\n#define dlbulk_free            bulk_free\n#endif /* USE_DL_PREFIX */\n\n/*\n  malloc(size_t n)\n  Returns a pointer to a newly allocated chunk of at least n bytes, or\n  null if no space is available, in which case errno is set to ENOMEM\n  on ANSI C systems.\n\n  If n is zero, malloc returns a minimum-sized chunk. (The minimum\n  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit\n  systems.)  Note that size_t is an unsigned type, so calls with\n  arguments that would be negative if signed are interpreted as\n  requests for huge amounts of space, which will often fail. The\n  maximum supported value of n differs across systems, but is in all\n  cases less than the maximum representable value of a size_t.\n*/\nDLMALLOC_EXPORT void* dlmalloc(size_t);\n\n/*\n  free(void* p)\n  Releases the chunk of memory pointed to by p, that had been previously\n  allocated using malloc or a related routine such as realloc.\n  It has no effect if p is null. If p was not malloced or already\n  freed, free(p) will by default cause the current program to abort.\n*/\nDLMALLOC_EXPORT void  dlfree(void*);\n\n/*\n  calloc(size_t n_elements, size_t element_size);\n  Returns a pointer to n_elements * element_size bytes, with all locations\n  set to zero.\n*/\nDLMALLOC_EXPORT void* dlcalloc(size_t, size_t);\n\n/*\n  realloc(void* p, size_t n)\n  Returns a pointer to a chunk of size n that contains the same data\n  as does chunk p up to the minimum of (n, p's size) bytes, or null\n  if no space is available.\n\n  The returned pointer may or may not be the same as p. The algorithm\n  prefers extending p in most cases when possible, otherwise it\n  employs the equivalent of a malloc-copy-free sequence.\n\n  If p is null, realloc is equivalent to malloc.\n\n  If space is not available, realloc returns null, errno is set (if on\n  ANSI) and p is NOT freed.\n\n  if n is for fewer bytes than already held by p, the newly unused\n  space is lopped off and freed if possible.  realloc with a size\n  argument of zero (re)allocates a minimum-sized chunk.\n\n  The old unix realloc convention of allowing the last-free'd chunk\n  to be used as an argument to realloc is not supported.\n*/\nDLMALLOC_EXPORT void* dlrealloc(void*, size_t);\n\n/*\n  realloc_in_place(void* p, size_t n)\n  Resizes the space allocated for p to size n, only if this can be\n  done without moving p (i.e., only if there is adjacent space\n  available if n is greater than p's current allocated size, or n is\n  less than or equal to p's size). This may be used instead of plain\n  realloc if an alternative allocation strategy is needed upon failure\n  to expand space; for example, reallocation of a buffer that must be\n  memory-aligned or cleared. You can use realloc_in_place to trigger\n  these alternatives only when needed.\n\n  Returns p if successful; otherwise null.\n*/\nDLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);\n\n/*\n  memalign(size_t alignment, size_t n);\n  Returns a pointer to a newly allocated chunk of n bytes, aligned\n  in accord with the alignment argument.\n\n  The alignment argument should be a power of two. If the argument is\n  not a power of two, the nearest greater power is used.\n  8-byte alignment is guaranteed by normal malloc calls, so don't\n  bother calling memalign with an argument of 8 or less.\n\n  Overreliance on memalign is a sure way to fragment space.\n*/\nDLMALLOC_EXPORT void* dlmemalign(size_t, size_t);\n\n/*\n  int posix_memalign(void** pp, size_t alignment, size_t n);\n  Allocates a chunk of n bytes, aligned in accord with the alignment\n  argument. Differs from memalign only in that it (1) assigns the\n  allocated memory to *pp rather than returning it, (2) fails and\n  returns EINVAL if the alignment is not a power of two (3) fails and\n  returns ENOMEM if memory cannot be allocated.\n*/\nDLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);\n\n/*\n  valloc(size_t n);\n  Equivalent to memalign(pagesize, n), where pagesize is the page\n  size of the system. If the pagesize is unknown, 4096 is used.\n*/\nDLMALLOC_EXPORT void* dlvalloc(size_t);\n\n/*\n  mallopt(int parameter_number, int parameter_value)\n  Sets tunable parameters The format is to provide a\n  (parameter-number, parameter-value) pair.  mallopt then sets the\n  corresponding parameter to the argument value if it can (i.e., so\n  long as the value is meaningful), and returns 1 if successful else\n  0.  To workaround the fact that mallopt is specified to use int,\n  not size_t parameters, the value -1 is specially treated as the\n  maximum unsigned size_t value.\n\n  SVID/XPG/ANSI defines four standard param numbers for mallopt,\n  normally defined in malloc.h.  None of these are use in this malloc,\n  so setting them has no effect. But this malloc also supports other\n  options in mallopt. See below for details.  Briefly, supported\n  parameters are as follows (listed defaults are for \"typical\"\n  configurations).\n\n  Symbol            param #  default    allowed param values\n  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1 disables)\n  M_GRANULARITY        -2     page size   any power of 2 >= page size\n  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)\n*/\nDLMALLOC_EXPORT int dlmallopt(int, int);\n\n/*\n  malloc_footprint();\n  Returns the number of bytes obtained from the system.  The total\n  number of bytes allocated by malloc, realloc etc., is less than this\n  value. Unlike mallinfo, this function returns only a precomputed\n  result, so can be called frequently to monitor memory consumption.\n  Even if locks are otherwise defined, this function does not use them,\n  so results might not be up to date.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_footprint(void);\n\n/*\n  malloc_max_footprint();\n  Returns the maximum number of bytes obtained from the system. This\n  value will be greater than current footprint if deallocated space\n  has been reclaimed by the system. The peak number of bytes allocated\n  by malloc, realloc etc., is less than this value. Unlike mallinfo,\n  this function returns only a precomputed result, so can be called\n  frequently to monitor memory consumption.  Even if locks are\n  otherwise defined, this function does not use them, so results might\n  not be up to date.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);\n\n/*\n  malloc_footprint_limit();\n  Returns the number of bytes that the heap is allowed to obtain from\n  the system, returning the last value returned by\n  malloc_set_footprint_limit, or the maximum size_t value if\n  never set. The returned value reflects a permission. There is no\n  guarantee that this number of bytes can actually be obtained from\n  the system.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_footprint_limit();\n\n/*\n  malloc_set_footprint_limit();\n  Sets the maximum number of bytes to obtain from the system, causing\n  failure returns from malloc and related functions upon attempts to\n  exceed this value. The argument value may be subject to page\n  rounding to an enforceable limit; this actual value is returned.\n  Using an argument of the maximum possible size_t effectively\n  disables checks. If the argument is less than or equal to the\n  current malloc_footprint, then all future allocations that require\n  additional system memory will fail. However, invocation cannot\n  retroactively deallocate existing used memory.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);\n\n#if MALLOC_INSPECT_ALL\n/*\n  malloc_inspect_all(void(*handler)(void *start,\n                                    void *end,\n                                    size_t used_bytes,\n                                    void* callback_arg),\n                      void* arg);\n  Traverses the heap and calls the given handler for each managed\n  region, skipping all bytes that are (or may be) used for bookkeeping\n  purposes.  Traversal does not include include chunks that have been\n  directly memory mapped. Each reported region begins at the start\n  address, and continues up to but not including the end address.  The\n  first used_bytes of the region contain allocated data. If\n  used_bytes is zero, the region is unallocated. The handler is\n  invoked with the given callback argument. If locks are defined, they\n  are held during the entire traversal. It is a bad idea to invoke\n  other malloc functions from within the handler.\n\n  For example, to count the number of in-use chunks with size greater\n  than 1000, you could write:\n  static int count = 0;\n  void count_chunks(void* start, void* end, size_t used, void* arg) {\n    if (used >= 1000) ++count;\n  }\n  then:\n    malloc_inspect_all(count_chunks, NULL);\n\n  malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.\n*/\nDLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),\n                           void* arg);\n\n#endif /* MALLOC_INSPECT_ALL */\n\n#if !NO_MALLINFO\n/*\n  mallinfo()\n  Returns (by copy) a struct containing various summary statistics:\n\n  arena:     current total non-mmapped bytes allocated from system\n  ordblks:   the number of free chunks\n  smblks:    always zero.\n  hblks:     current number of mmapped regions\n  hblkhd:    total bytes held in mmapped regions\n  usmblks:   the maximum total allocated space. This will be greater\n                than current total if trimming has occurred.\n  fsmblks:   always zero\n  uordblks:  current total allocated space (normal or mmapped)\n  fordblks:  total free space\n  keepcost:  the maximum number of bytes that could ideally be released\n               back to system via malloc_trim. (\"ideally\" means that\n               it ignores page restrictions etc.)\n\n  Because these fields are ints, but internal bookkeeping may\n  be kept as longs, the reported values may wrap around zero and\n  thus be inaccurate.\n*/\nDLMALLOC_EXPORT struct mallinfo dlmallinfo(void);\n#endif /* NO_MALLINFO */\n\n/*\n  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);\n\n  independent_calloc is similar to calloc, but instead of returning a\n  single cleared space, it returns an array of pointers to n_elements\n  independent elements that can hold contents of size elem_size, each\n  of which starts out cleared, and can be independently freed,\n  realloc'ed etc. The elements are guaranteed to be adjacently\n  allocated (this is not guaranteed to occur with multiple callocs or\n  mallocs), which may also improve cache locality in some\n  applications.\n\n  The \"chunks\" argument is optional (i.e., may be null, which is\n  probably the most typical usage). If it is null, the returned array\n  is itself dynamically allocated and should also be freed when it is\n  no longer needed. Otherwise, the chunks array must be of at least\n  n_elements in length. It is filled in with the pointers to the\n  chunks.\n\n  In either case, independent_calloc returns this pointer array, or\n  null if the allocation failed.  If n_elements is zero and \"chunks\"\n  is null, it returns a chunk representing an array with zero elements\n  (which should be freed if not wanted).\n\n  Each element must be freed when it is no longer needed. This can be\n  done all at once using bulk_free.\n\n  independent_calloc simplifies and speeds up implementations of many\n  kinds of pools.  It may also be useful when constructing large data\n  structures that initially have a fixed number of fixed-sized nodes,\n  but the number is not known at compile time, and some of the nodes\n  may later need to be freed. For example:\n\n  struct Node { int item; struct Node* next; };\n\n  struct Node* build_list() {\n    struct Node** pool;\n    int n = read_number_of_nodes_needed();\n    if (n <= 0) return 0;\n    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);\n    if (pool == 0) die();\n    // organize into a linked list...\n    struct Node* first = pool[0];\n    for (i = 0; i < n-1; ++i)\n      pool[i]->next = pool[i+1];\n    free(pool);     // Can now free the array (or not, if it is needed later)\n    return first;\n  }\n*/\nDLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);\n\n/*\n  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);\n\n  independent_comalloc allocates, all at once, a set of n_elements\n  chunks with sizes indicated in the \"sizes\" array.    It returns\n  an array of pointers to these elements, each of which can be\n  independently freed, realloc'ed etc. The elements are guaranteed to\n  be adjacently allocated (this is not guaranteed to occur with\n  multiple callocs or mallocs), which may also improve cache locality\n  in some applications.\n\n  The \"chunks\" argument is optional (i.e., may be null). If it is null\n  the returned array is itself dynamically allocated and should also\n  be freed when it is no longer needed. Otherwise, the chunks array\n  must be of at least n_elements in length. It is filled in with the\n  pointers to the chunks.\n\n  In either case, independent_comalloc returns this pointer array, or\n  null if the allocation failed.  If n_elements is zero and chunks is\n  null, it returns a chunk representing an array with zero elements\n  (which should be freed if not wanted).\n\n  Each element must be freed when it is no longer needed. This can be\n  done all at once using bulk_free.\n\n  independent_comallac differs from independent_calloc in that each\n  element may have a different size, and also that it does not\n  automatically clear elements.\n\n  independent_comalloc can be used to speed up allocation in cases\n  where several structs or objects must always be allocated at the\n  same time.  For example:\n\n  struct Head { ... }\n  struct Foot { ... }\n\n  void send_message(char* msg) {\n    int msglen = strlen(msg);\n    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };\n    void* chunks[3];\n    if (independent_comalloc(3, sizes, chunks) == 0)\n      die();\n    struct Head* head = (struct Head*)(chunks[0]);\n    char*        body = (char*)(chunks[1]);\n    struct Foot* foot = (struct Foot*)(chunks[2]);\n    // ...\n  }\n\n  In general though, independent_comalloc is worth using only for\n  larger values of n_elements. For small values, you probably won't\n  detect enough difference from series of malloc calls to bother.\n\n  Overuse of independent_comalloc can increase overall memory usage,\n  since it cannot reuse existing noncontiguous small chunks that\n  might be available for some of the elements.\n*/\nDLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);\n\n/*\n  bulk_free(void* array[], size_t n_elements)\n  Frees and clears (sets to null) each non-null pointer in the given\n  array.  This is likely to be faster than freeing them one-by-one.\n  If footers are used, pointers that have been allocated in different\n  mspaces are not freed or cleared, and the count of all such pointers\n  is returned.  For large arrays of pointers with poor locality, it\n  may be worthwhile to sort this array before calling bulk_free.\n*/\nDLMALLOC_EXPORT size_t  dlbulk_free(void**, size_t n_elements);\n\n/*\n  pvalloc(size_t n);\n  Equivalent to valloc(minimum-page-that-holds(n)), that is,\n  round up n to nearest pagesize.\n */\nDLMALLOC_EXPORT void*  dlpvalloc(size_t);\n\n/*\n  malloc_trim(size_t pad);\n\n  If possible, gives memory back to the system (via negative arguments\n  to sbrk) if there is unused memory at the `high' end of the malloc\n  pool or in unused MMAP segments. You can call this after freeing\n  large blocks of memory to potentially reduce the system-level memory\n  requirements of a program. However, it cannot guarantee to reduce\n  memory. Under some allocation patterns, some large free blocks of\n  memory will be locked between two used chunks, so they cannot be\n  given back to the system.\n\n  The `pad' argument to malloc_trim represents the amount of free\n  trailing space to leave untrimmed. If this argument is zero, only\n  the minimum amount of memory to maintain internal data structures\n  will be left. Non-zero arguments can be supplied to maintain enough\n  trailing space to service future expected allocations without having\n  to re-obtain memory from the system.\n\n  Malloc_trim returns 1 if it actually released any memory, else 0.\n*/\nDLMALLOC_EXPORT int  dlmalloc_trim(size_t);\n\n/*\n  malloc_stats();\n  Prints on stderr the amount of space obtained from the system (both\n  via sbrk and mmap), the maximum amount (which may be more than\n  current if malloc_trim and/or munmap got called), and the current\n  number of bytes allocated via malloc (or realloc, etc) but not yet\n  freed. Note that this is the number of bytes allocated, not the\n  number requested. It will be larger than the number requested\n  because of alignment and bookkeeping overhead. Because it includes\n  alignment wastage as being in use, this figure may be greater than\n  zero even when no user-level chunks are allocated.\n\n  The reported current and maximum system memory can be inaccurate if\n  a program makes other calls to system memory allocation functions\n  (normally sbrk) outside of malloc.\n\n  malloc_stats prints only the most commonly interesting statistics.\n  More information can be obtained by calling mallinfo.\n*/\nDLMALLOC_EXPORT void  dlmalloc_stats(void);\n\n/*\n  malloc_usable_size(void* p);\n\n  Returns the number of bytes you can actually use in\n  an allocated chunk, which may be more than you requested (although\n  often not) due to alignment and minimum size constraints.\n  You can use this many bytes without worrying about\n  overwriting other allocated objects. This is not a particularly great\n  programming practice. malloc_usable_size can be more useful in\n  debugging and assertions, for example:\n\n  p = malloc(n);\n  assert(malloc_usable_size(p) >= 256);\n*/\nsize_t dlmalloc_usable_size(void*);\n\n#endif /* ONLY_MSPACES */\n\n#if MSPACES\n\n/*\n  mspace is an opaque type representing an independent\n  region of space that supports mspace_malloc, etc.\n*/\ntypedef void* mspace;\n\n/*\n  create_mspace creates and returns a new independent space with the\n  given initial capacity, or, if 0, the default granularity size.  It\n  returns null if there is no system memory available to create the\n  space.  If argument locked is non-zero, the space uses a separate\n  lock to control access. The capacity of the space will grow\n  dynamically as needed to service mspace_malloc requests.  You can\n  control the sizes of incremental increases of this space by\n  compiling with a different DEFAULT_GRANULARITY or dynamically\n  setting with mallopt(M_GRANULARITY, value).\n*/\nDLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);\n\n/*\n  destroy_mspace destroys the given space, and attempts to return all\n  of its memory back to the system, returning the total number of\n  bytes freed. After destruction, the results of access to all memory\n  used by the space become undefined.\n*/\nDLMALLOC_EXPORT size_t destroy_mspace(mspace msp);\n\n/*\n  create_mspace_with_base uses the memory supplied as the initial base\n  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this\n  space is used for bookkeeping, so the capacity must be at least this\n  large. (Otherwise 0 is returned.) When this initial space is\n  exhausted, additional memory will be obtained from the system.\n  Destroying this space will deallocate all additionally allocated\n  space (if possible) but not the initial base.\n*/\nDLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);\n\n/*\n  mspace_track_large_chunks controls whether requests for large chunks\n  are allocated in their own untracked mmapped regions, separate from\n  others in this mspace. By default large chunks are not tracked,\n  which reduces fragmentation. However, such chunks are not\n  necessarily released to the system upon destroy_mspace.  Enabling\n  tracking by setting to true may increase fragmentation, but avoids\n  leakage when relying on destroy_mspace to release all memory\n  allocated using this space.  The function returns the previous\n  setting.\n*/\nDLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);\n\n\n/*\n  mspace_malloc behaves as malloc, but operates within\n  the given space.\n*/\nDLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);\n\n/*\n  mspace_free behaves as free, but operates within\n  the given space.\n\n  If compiled with FOOTERS==1, mspace_free is not actually needed.\n  free may be called instead of mspace_free because freed chunks from\n  any space are handled by their originating spaces.\n*/\nDLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);\n\n/*\n  mspace_realloc behaves as realloc, but operates within\n  the given space.\n\n  If compiled with FOOTERS==1, mspace_realloc is not actually\n  needed.  realloc may be called instead of mspace_realloc because\n  realloced chunks from any space are handled by their originating\n  spaces.\n*/\nDLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);\n\n/*\n  mspace_calloc behaves as calloc, but operates within\n  the given space.\n*/\nDLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);\n\n/*\n  mspace_memalign behaves as memalign, but operates within\n  the given space.\n*/\nDLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);\n\n/*\n  mspace_independent_calloc behaves as independent_calloc, but\n  operates within the given space.\n*/\nDLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,\n                                 size_t elem_size, void* chunks[]);\n\n/*\n  mspace_independent_comalloc behaves as independent_comalloc, but\n  operates within the given space.\n*/\nDLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,\n                                   size_t sizes[], void* chunks[]);\n\n/*\n  mspace_footprint() returns the number of bytes obtained from the\n  system for this space.\n*/\nDLMALLOC_EXPORT size_t mspace_footprint(mspace msp);\n\n/*\n  mspace_max_footprint() returns the peak number of bytes obtained from the\n  system for this space.\n*/\nDLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);\n\n\n#if !NO_MALLINFO\n/*\n  mspace_mallinfo behaves as mallinfo, but reports properties of\n  the given space.\n*/\nDLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);\n#endif /* NO_MALLINFO */\n\n/*\n  malloc_usable_size(void* p) behaves the same as malloc_usable_size;\n*/\nDLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);\n\n/*\n  mspace_malloc_stats behaves as malloc_stats, but reports\n  properties of the given space.\n*/\nDLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);\n\n/*\n  mspace_trim behaves as malloc_trim, but\n  operates within the given space.\n*/\nDLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);\n\n/*\n  An alias for mallopt.\n*/\nDLMALLOC_EXPORT int mspace_mallopt(int, int);\n\n#endif /* MSPACES */\n\n#ifdef __cplusplus\n}  /* end of extern \"C\" */\n#endif /* __cplusplus */\n\n/*\n  ========================================================================\n  To make a fully customizable malloc.h header file, cut everything\n  above this line, put into file malloc.h, edit to suit, and #include it\n  on the next line, as well as in programs that use this malloc.\n  ========================================================================\n*/\n\n/* #include \"malloc.h\" */\n\n/*------------------------------ internal #includes ---------------------- */\n\n#ifdef _MSC_VER\n#pragma warning( disable : 4146 ) /* no \"unsigned\" warnings */\n#endif /* _MSC_VER */\n#if !NO_MALLOC_STATS\n#include <stdio.h>       /* for printing in malloc_stats */\n#endif /* NO_MALLOC_STATS */\n#ifndef LACKS_ERRNO_H\n#include <errno.h>       /* for MALLOC_FAILURE_ACTION */\n#endif /* LACKS_ERRNO_H */\n#ifdef DEBUG\n#if ABORT_ON_ASSERT_FAILURE\n#undef assert\n#define assert(x) if(!(x)) ABORT\n#else /* ABORT_ON_ASSERT_FAILURE */\n#include <assert.h>\n#endif /* ABORT_ON_ASSERT_FAILURE */\n#else  /* DEBUG */\n#ifndef assert\n#define assert(x)\n#endif\n#define DEBUG 0\n#endif /* DEBUG */\n#if !defined(WIN32) && !defined(LACKS_TIME_H)\n#include <time.h>        /* for magic initialization */\n#endif /* WIN32 */\n#ifndef LACKS_STDLIB_H\n#include <stdlib.h>      /* for abort() */\n#endif /* LACKS_STDLIB_H */\n#ifndef LACKS_STRING_H\n#include <string.h>      /* for memset etc */\n#endif  /* LACKS_STRING_H */\n#if USE_BUILTIN_FFS\n#ifndef LACKS_STRINGS_H\n#include <strings.h>     /* for ffs */\n#endif /* LACKS_STRINGS_H */\n#endif /* USE_BUILTIN_FFS */\n#if HAVE_MMAP\n#ifndef LACKS_SYS_MMAN_H\n/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */\n#if (defined(linux) && !defined(__USE_GNU))\n#define __USE_GNU 1\n#include <sys/mman.h>    /* for mmap */\n#undef __USE_GNU\n#else\n#include <sys/mman.h>    /* for mmap */\n#endif /* linux */\n#endif /* LACKS_SYS_MMAN_H */\n#ifndef LACKS_FCNTL_H\n#include <fcntl.h>\n#endif /* LACKS_FCNTL_H */\n#endif /* HAVE_MMAP */\n#ifndef LACKS_UNISTD_H\n#include <unistd.h>     /* for sbrk, sysconf */\n#else /* LACKS_UNISTD_H */\n#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)\nextern void*     sbrk(ptrdiff_t);\n#endif /* FreeBSD etc */\n#endif /* LACKS_UNISTD_H */\n\n/* Declarations for locking */\n#if USE_LOCKS\n#ifndef WIN32\n#if defined (__SVR4) && defined (__sun)  /* solaris */\n#include <thread.h>\n#elif !defined(LACKS_SCHED_H)\n#include <sched.h>\n#endif /* solaris or LACKS_SCHED_H */\n#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS\n#include <pthread.h>\n#endif /* USE_RECURSIVE_LOCKS ... */\n#elif defined(_MSC_VER)\n#ifndef _M_AMD64\n/* These are already defined on AMD64 builds */\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\nLONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);\nLONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n#endif /* _M_AMD64 */\n#pragma intrinsic (_InterlockedCompareExchange)\n#pragma intrinsic (_InterlockedExchange)\n#define interlockedcompareexchange _InterlockedCompareExchange\n#define interlockedexchange _InterlockedExchange\n#elif defined(WIN32) && defined(__GNUC__)\n#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)\n#define interlockedexchange __sync_lock_test_and_set\n#endif /* Win32 */\n#else /* USE_LOCKS */\n#endif /* USE_LOCKS */\n\n#ifndef LOCK_AT_FORK\n#define LOCK_AT_FORK 0\n#endif\n\n/* Declarations for bit scanning on win32 */\n#if defined(_MSC_VER) && _MSC_VER>=1300\n#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\nunsigned char _BitScanForward(unsigned long *index, unsigned long mask);\nunsigned char _BitScanReverse(unsigned long *index, unsigned long mask);\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#define BitScanForward _BitScanForward\n#define BitScanReverse _BitScanReverse\n#pragma intrinsic(_BitScanForward)\n#pragma intrinsic(_BitScanReverse)\n#endif /* BitScanForward */\n#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */\n\n#ifndef WIN32\n#ifndef malloc_getpagesize\n#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */\n#    ifndef _SC_PAGE_SIZE\n#      define _SC_PAGE_SIZE _SC_PAGESIZE\n#    endif\n#  endif\n#  ifdef _SC_PAGE_SIZE\n#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)\n#  else\n#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)\n       extern size_t getpagesize();\n#      define malloc_getpagesize getpagesize()\n#    else\n#      ifdef WIN32 /* use supplied emulation of getpagesize */\n#        define malloc_getpagesize getpagesize()\n#      else\n#        ifndef LACKS_SYS_PARAM_H\n#          include <sys/param.h>\n#        endif\n#        ifdef EXEC_PAGESIZE\n#          define malloc_getpagesize EXEC_PAGESIZE\n#        else\n#          ifdef NBPG\n#            ifndef CLSIZE\n#              define malloc_getpagesize NBPG\n#            else\n#              define malloc_getpagesize (NBPG * CLSIZE)\n#            endif\n#          else\n#            ifdef NBPC\n#              define malloc_getpagesize NBPC\n#            else\n#              ifdef PAGESIZE\n#                define malloc_getpagesize PAGESIZE\n#              else /* just guess */\n#                define malloc_getpagesize ((size_t)4096U)\n#              endif\n#            endif\n#          endif\n#        endif\n#      endif\n#    endif\n#  endif\n#endif\n#endif\n\n/* ------------------- size_t and alignment properties -------------------- */\nnamespace romuluslog{\n/* The byte and bit size of a size_t */\n#define SIZE_T_SIZE         (sizeof(size_t))\n#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)\n\n/* Some constants coerced to size_t */\n/* Annoying but necessary to avoid errors on some platforms */\n#define SIZE_T_ZERO         ((size_t)0)\n#define SIZE_T_ONE          ((size_t)1)\n#define SIZE_T_TWO          ((size_t)2)\n#define SIZE_T_FOUR         ((size_t)4)\n#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)\n#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)\n#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)\n#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)\n\n/* The bit mask value corresponding to MALLOC_ALIGNMENT */\n#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)\n\n/* True if address a has acceptable alignment */\n#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)\n\n/* the number of bytes to offset an address to align it */\n#define align_offset(A)\\\n ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\\\n  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))\n\n/* -------------------------- MMAP preliminaries ------------------------- */\n\n/*\n   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and\n   checks to fail so compiler optimizer can delete code rather than\n   using so many \"#if\"s.\n*/\n\n\n/* MORECORE and MMAP must return MFAIL on failure */\n#define MFAIL                ((void*)(MAX_SIZE_T))\n#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */\n\n#if HAVE_MMAP\n\n#ifndef WIN32\n#define MUNMAP_DEFAULT(a, s)  munmap((a), (s))\n#define MMAP_PROT            (PROT_READ|PROT_WRITE)\n#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)\n#define MAP_ANONYMOUS        MAP_ANON\n#endif /* MAP_ANON */\n#ifdef MAP_ANONYMOUS\n#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)\n#define MMAP_DEFAULT(s)       mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)\n#else /* MAP_ANONYMOUS */\n/*\n   Nearly all versions of mmap support MAP_ANONYMOUS, so the following\n   is unlikely to be needed, but is supplied just in case.\n*/\n#define MMAP_FLAGS           (MAP_PRIVATE)\nstatic int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */\n#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \\\n           (dev_zero_fd = open(\"/dev/zero\", O_RDWR), \\\n            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \\\n            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))\n#endif /* MAP_ANONYMOUS */\n\n#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)\n\n#else /* WIN32 */\n\n/* Win32 MMAP via VirtualAlloc */\nstatic FORCEINLINE void* win32mmap(size_t size) {\n  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);\n  return (ptr != 0)? ptr: MFAIL;\n}\n\n/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */\nstatic FORCEINLINE void* win32direct_mmap(size_t size) {\n  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,\n                           PAGE_READWRITE);\n  return (ptr != 0)? ptr: MFAIL;\n}\n\n/* This function supports releasing coalesed segments */\nstatic FORCEINLINE int win32munmap(void* ptr, size_t size) {\n  MEMORY_BASIC_INFORMATION minfo;\n  char* cptr = (char*)ptr;\n  while (size) {\n    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)\n      return -1;\n    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||\n        minfo.State != MEM_COMMIT || minfo.RegionSize > size)\n      return -1;\n    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)\n      return -1;\n    cptr += minfo.RegionSize;\n    size -= minfo.RegionSize;\n  }\n  return 0;\n}\n\n#define MMAP_DEFAULT(s)             win32mmap(s)\n#define MUNMAP_DEFAULT(a, s)        win32munmap((a), (s))\n#define DIRECT_MMAP_DEFAULT(s)      win32direct_mmap(s)\n#endif /* WIN32 */\n#endif /* HAVE_MMAP */\n\n#if HAVE_MREMAP\n#ifndef WIN32\n#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))\n#endif /* WIN32 */\n#endif /* HAVE_MREMAP */\n\n/**\n * Define CALL_MORECORE\n */\n#if HAVE_MORECORE\n    #ifdef MORECORE\n        #define CALL_MORECORE(S)    MORECORE(S)\n    #else  /* MORECORE */\n        #define CALL_MORECORE(S)    MORECORE_DEFAULT(S)\n    #endif /* MORECORE */\n#else  /* HAVE_MORECORE */\n    #define CALL_MORECORE(S)        MFAIL\n#endif /* HAVE_MORECORE */\n\n/**\n * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP\n */\n#if HAVE_MMAP\n    #define USE_MMAP_BIT            (SIZE_T_ONE)\n\n    #ifdef MMAP\n        #define CALL_MMAP(s)        MMAP(s)\n    #else /* MMAP */\n        #define CALL_MMAP(s)        MMAP_DEFAULT(s)\n    #endif /* MMAP */\n    #ifdef MUNMAP\n        #define CALL_MUNMAP(a, s)   MUNMAP((a), (s))\n    #else /* MUNMAP */\n        #define CALL_MUNMAP(a, s)   MUNMAP_DEFAULT((a), (s))\n    #endif /* MUNMAP */\n    #ifdef DIRECT_MMAP\n        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)\n    #else /* DIRECT_MMAP */\n        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)\n    #endif /* DIRECT_MMAP */\n#else  /* HAVE_MMAP */\n    #define USE_MMAP_BIT            (SIZE_T_ZERO)\n\n    #define MMAP(s)                 MFAIL\n    #define MUNMAP(a, s)            (-1)\n    #define DIRECT_MMAP(s)          MFAIL\n    #define CALL_DIRECT_MMAP(s)     DIRECT_MMAP(s)\n    #define CALL_MMAP(s)            MMAP(s)\n    #define CALL_MUNMAP(a, s)       MUNMAP((a), (s))\n#endif /* HAVE_MMAP */\n\n/**\n * Define CALL_MREMAP\n */\n#if HAVE_MMAP && HAVE_MREMAP\n    #ifdef MREMAP\n        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))\n    #else /* MREMAP */\n        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))\n    #endif /* MREMAP */\n#else  /* HAVE_MMAP && HAVE_MREMAP */\n    #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL\n#endif /* HAVE_MMAP && HAVE_MREMAP */\n\n/* mstate bit set if continguous morecore disabled or failed */\n#define USE_NONCONTIGUOUS_BIT (4U)\n\n/* segment bit set in create_mspace_with_base */\n#define EXTERN_BIT            (8U)\n\n\n/* --------------------------- Lock preliminaries ------------------------ */\n\n/*\n  When locks are defined, there is one global lock, plus\n  one per-mspace lock.\n\n  The global lock_ensures that mparams.magic and other unique\n  mparams values are initialized only once. It also protects\n  sequences of calls to MORECORE.  In many cases sys_alloc requires\n  two calls, that should not be interleaved with calls by other\n  threads.  This does not protect against direct calls to MORECORE\n  by other threads not using this lock, so there is still code to\n  cope the best we can on interference.\n\n  Per-mspace locks surround calls to malloc, free, etc.\n  By default, locks are simple non-reentrant mutexes.\n\n  Because lock-protected regions generally have bounded times, it is\n  OK to use the supplied simple spinlocks. Spinlocks are likely to\n  improve performance for lightly contended applications, but worsen\n  performance under heavy contention.\n\n  If USE_LOCKS is > 1, the definitions of lock routines here are\n  bypassed, in which case you will need to define the type MLOCK_T,\n  and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK\n  and TRY_LOCK.  You must also declare a\n    static MLOCK_T malloc_global_mutex = { initialization values };.\n\n*/\n\n#if !USE_LOCKS\n#define USE_LOCK_BIT               (0U)\n#define INITIAL_LOCK(l)            (0)\n#define DESTROY_LOCK(l)            (0)\n#define ACQUIRE_MALLOC_GLOBAL_LOCK()\n#define RELEASE_MALLOC_GLOBAL_LOCK()\n\n#else\n#if USE_LOCKS > 1\n/* -----------------------  User-defined locks ------------------------ */\n/* Define your own lock implementation here */\n/* #define INITIAL_LOCK(lk)  ... */\n/* #define DESTROY_LOCK(lk)  ... */\n/* #define ACQUIRE_LOCK(lk)  ... */\n/* #define RELEASE_LOCK(lk)  ... */\n/* #define TRY_LOCK(lk) ... */\n/* static MLOCK_T malloc_global_mutex = ... */\n\n#elif USE_SPIN_LOCKS\n\n/* First, define CAS_LOCK and CLEAR_LOCK on ints */\n/* Note CAS_LOCK defined to return 0 on success */\n\n#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))\n#define CAS_LOCK(sl)     __sync_lock_test_and_set(sl, 1)\n#define CLEAR_LOCK(sl)   __sync_lock_release(sl)\n\n#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))\n/* Custom spin locks for older gcc on x86 */\nstatic FORCEINLINE int x86_cas_lock(int *sl) {\n  int ret;\n  int val = 1;\n  int cmp = 0;\n  __asm__ __volatile__  (\"lock; cmpxchgl %1, %2\"\n                         : \"=a\" (ret)\n                         : \"r\" (val), \"m\" (*(sl)), \"0\"(cmp)\n                         : \"memory\", \"cc\");\n  return ret;\n}\n\nstatic FORCEINLINE void x86_clear_lock(int* sl) {\n  assert(*sl != 0);\n  int prev = 0;\n  int ret;\n  __asm__ __volatile__ (\"lock; xchgl %0, %1\"\n                        : \"=r\" (ret)\n                        : \"m\" (*(sl)), \"0\"(prev)\n                        : \"memory\");\n}\n\n#define CAS_LOCK(sl)     x86_cas_lock(sl)\n#define CLEAR_LOCK(sl)   x86_clear_lock(sl)\n\n#else /* Win32 MSC */\n#define CAS_LOCK(sl)     interlockedexchange(sl, (LONG)1)\n#define CLEAR_LOCK(sl)   interlockedexchange (sl, (LONG)0)\n\n#endif /* ... gcc spins locks ... */\n\n/* How to yield for a spin lock */\n#define SPINS_PER_YIELD       63\n#if defined(_MSC_VER)\n#define SLEEP_EX_DURATION     50 /* delay for yield/sleep */\n#define SPIN_LOCK_YIELD  SleepEx(SLEEP_EX_DURATION, FALSE)\n#elif defined (__SVR4) && defined (__sun) /* solaris */\n#define SPIN_LOCK_YIELD   thr_yield();\n#elif !defined(LACKS_SCHED_H)\n#define SPIN_LOCK_YIELD   sched_yield();\n#else\n#define SPIN_LOCK_YIELD\n#endif /* ... yield ... */\n\n#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0\n/* Plain spin locks use single word (embedded in malloc_states) */\nstatic int spin_acquire_lock(int *sl) {\n  int spins = 0;\n  while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {\n    if ((++spins & SPINS_PER_YIELD) == 0) {\n      SPIN_LOCK_YIELD;\n    }\n  }\n  return 0;\n}\n\n#define MLOCK_T               int\n#define TRY_LOCK(sl)          !CAS_LOCK(sl)\n#define RELEASE_LOCK(sl)      CLEAR_LOCK(sl)\n#define ACQUIRE_LOCK(sl)      (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0)\n#define INITIAL_LOCK(sl)      (*sl = 0)\n#define DESTROY_LOCK(sl)      (0)\nstatic MLOCK_T malloc_global_mutex = 0;\n\n#else /* USE_RECURSIVE_LOCKS */\n/* types for lock owners */\n#ifdef WIN32\n#define THREAD_ID_T           DWORD\n#define CURRENT_THREAD        GetCurrentThreadId()\n#define EQ_OWNER(X,Y)         ((X) == (Y))\n#else\n/*\n  Note: the following assume that pthread_t is a type that can be\n  initialized to (casted) zero. If this is not the case, you will need to\n  somehow redefine these or not use spin locks.\n*/\n#define THREAD_ID_T           pthread_t\n#define CURRENT_THREAD        pthread_self()\n#define EQ_OWNER(X,Y)         pthread_equal(X, Y)\n#endif\n\nstruct malloc_recursive_lock {\n  int sl;\n  unsigned int c;\n  THREAD_ID_T threadid;\n};\n\n#define MLOCK_T  struct malloc_recursive_lock\nstatic MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0};\n\nstatic FORCEINLINE void recursive_release_lock(MLOCK_T *lk) {\n  assert(lk->sl != 0);\n  if (--lk->c == 0) {\n    CLEAR_LOCK(&lk->sl);\n  }\n}\n\nstatic FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) {\n  THREAD_ID_T mythreadid = CURRENT_THREAD;\n  int spins = 0;\n  for (;;) {\n    if (*((volatile int *)(&lk->sl)) == 0) {\n      if (!CAS_LOCK(&lk->sl)) {\n        lk->threadid = mythreadid;\n        lk->c = 1;\n        return 0;\n      }\n    }\n    else if (EQ_OWNER(lk->threadid, mythreadid)) {\n      ++lk->c;\n      return 0;\n    }\n    if ((++spins & SPINS_PER_YIELD) == 0) {\n      SPIN_LOCK_YIELD;\n    }\n  }\n}\n\nstatic FORCEINLINE int recursive_try_lock(MLOCK_T *lk) {\n  THREAD_ID_T mythreadid = CURRENT_THREAD;\n  if (*((volatile int *)(&lk->sl)) == 0) {\n    if (!CAS_LOCK(&lk->sl)) {\n      lk->threadid = mythreadid;\n      lk->c = 1;\n      return 1;\n    }\n  }\n  else if (EQ_OWNER(lk->threadid, mythreadid)) {\n    ++lk->c;\n    return 1;\n  }\n  return 0;\n}\n\n#define RELEASE_LOCK(lk)      recursive_release_lock(lk)\n#define TRY_LOCK(lk)          recursive_try_lock(lk)\n#define ACQUIRE_LOCK(lk)      recursive_acquire_lock(lk)\n#define INITIAL_LOCK(lk)      ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0)\n#define DESTROY_LOCK(lk)      (0)\n#endif /* USE_RECURSIVE_LOCKS */\n\n#elif defined(WIN32) /* Win32 critical sections */\n#define MLOCK_T               CRITICAL_SECTION\n#define ACQUIRE_LOCK(lk)      (EnterCriticalSection(lk), 0)\n#define RELEASE_LOCK(lk)      LeaveCriticalSection(lk)\n#define TRY_LOCK(lk)          TryEnterCriticalSection(lk)\n#define INITIAL_LOCK(lk)      (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000))\n#define DESTROY_LOCK(lk)      (DeleteCriticalSection(lk), 0)\n#define NEED_GLOBAL_LOCK_INIT\n\nstatic MLOCK_T malloc_global_mutex;\nstatic volatile LONG malloc_global_mutex_status;\n\n/* Use spin loop to initialize global lock */\nstatic void init_malloc_global_mutex() {\n  for (;;) {\n    long stat = malloc_global_mutex_status;\n    if (stat > 0)\n      return;\n    /* transition to < 0 while initializing, then to > 0) */\n    if (stat == 0 &&\n        interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) {\n      InitializeCriticalSection(&malloc_global_mutex);\n      interlockedexchange(&malloc_global_mutex_status, (LONG)1);\n      return;\n    }\n    SleepEx(0, FALSE);\n  }\n}\n\n#else /* pthreads-based locks */\n#define MLOCK_T               pthread_mutex_t\n#define ACQUIRE_LOCK(lk)      pthread_mutex_lock(lk)\n#define RELEASE_LOCK(lk)      pthread_mutex_unlock(lk)\n#define TRY_LOCK(lk)          (!pthread_mutex_trylock(lk))\n#define INITIAL_LOCK(lk)      pthread_init_lock(lk)\n#define DESTROY_LOCK(lk)      pthread_mutex_destroy(lk)\n\n#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE)\n/* Cope with old-style linux recursive lock initialization by adding */\n/* skipped internal declaration from pthread.h */\nextern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,\n                                              int __kind));\n#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP\n#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)\n#endif /* USE_RECURSIVE_LOCKS ... */\n\nstatic MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;\n\nstatic int pthread_init_lock (MLOCK_T *lk) {\n  pthread_mutexattr_t attr;\n  if (pthread_mutexattr_init(&attr)) return 1;\n#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0\n  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;\n#endif\n  if (pthread_mutex_init(lk, &attr)) return 1;\n  if (pthread_mutexattr_destroy(&attr)) return 1;\n  return 0;\n}\n\n#endif /* ... lock types ... */\n\n/* Common code for all lock types */\n#define USE_LOCK_BIT               (2U)\n\n#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK\n#define ACQUIRE_MALLOC_GLOBAL_LOCK()  ACQUIRE_LOCK(&malloc_global_mutex);\n#endif\n\n#ifndef RELEASE_MALLOC_GLOBAL_LOCK\n#define RELEASE_MALLOC_GLOBAL_LOCK()  RELEASE_LOCK(&malloc_global_mutex);\n#endif\n\n#endif /* USE_LOCKS */\n\n/* -----------------------  Chunk representations ------------------------ */\n\n/*\n  (The following includes lightly edited explanations by Colin Plumb.)\n\n  The malloc_chunk declaration below is misleading (but accurate and\n  necessary).  It declares a \"view\" into memory allowing access to\n  necessary fields at known offsets from a given base.\n\n  Chunks of memory are maintained using a `boundary tag' method as\n  originally described by Knuth.  (See the paper by Paul Wilson\n  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such\n  techniques.)  Sizes of free chunks are stored both in the front of\n  each chunk and at the end.  This makes consolidating fragmented\n  chunks into bigger chunks fast.  The head fields also hold bits\n  representing whether chunks are free or in use.\n\n  Here are some pictures to make it clearer.  They are \"exploded\" to\n  show that the state of a chunk can be thought of as extending from\n  the high 31 bits of the head field of its header through the\n  prev_foot and PINUSE_BIT bit of the following chunk header.\n\n  A chunk that's in use looks like:\n\n   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n           | Size of previous chunk (if P = 0)                             |\n           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|\n         | Size of this chunk                                         1| +-+\n   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         |                                                               |\n         +-                                                             -+\n         |                                                               |\n         +-                                                             -+\n         |                                                               :\n         +-      size - sizeof(size_t) available payload bytes          -+\n         :                                                               |\n chunk-> +-                                                             -+\n         |                                                               |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|\n       | Size of next chunk (may or may not be in use)               | +-+\n mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n\n    And if it's free, it looks like this:\n\n   chunk-> +-                                                             -+\n           | User payload (must be in use, or we would have merged!)       |\n           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|\n         | Size of this chunk                                         0| +-+\n   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         | Next pointer                                                  |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         | Prev pointer                                                  |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         |                                                               :\n         +-      size - sizeof(struct chunk) unused bytes               -+\n         :                                                               |\n chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         | Size of this chunk                                            |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|\n       | Size of next chunk (must be in use, or we would have merged)| +-+\n mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n       |                                                               :\n       +- User payload                                                -+\n       :                                                               |\n       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n                                                                     |0|\n                                                                     +-+\n  Note that since we always merge adjacent free chunks, the chunks\n  adjacent to a free chunk must be in use.\n\n  Given a pointer to a chunk (which can be derived trivially from the\n  payload pointer) we can, in O(1) time, find out whether the adjacent\n  chunks are free, and if so, unlink them from the lists that they\n  are on and merge them with the current chunk.\n\n  Chunks always begin on even word boundaries, so the mem portion\n  (which is returned to the user) is also on an even word boundary, and\n  thus at least double-word aligned.\n\n  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the\n  chunk size (which is always a multiple of two words), is an in-use\n  bit for the *previous* chunk.  If that bit is *clear*, then the\n  word before the current chunk size contains the previous chunk\n  size, and can be used to find the front of the previous chunk.\n  The very first chunk allocated always has this bit set, preventing\n  access to non-existent (or non-owned) memory. If pinuse is set for\n  any given chunk, then you CANNOT determine the size of the\n  previous chunk, and might even get a memory addressing fault when\n  trying to do so.\n\n  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of\n  the chunk size redundantly records whether the current chunk is\n  inuse (unless the chunk is mmapped). This redundancy enables usage\n  checks within free and realloc, and reduces indirection when freeing\n  and consolidating chunks.\n\n  Each freshly allocated chunk must have both cinuse and pinuse set.\n  That is, each allocated chunk borders either a previously allocated\n  and still in-use chunk, or the base of its memory arena. This is\n  ensured by making all allocations from the `lowest' part of any\n  found chunk.  Further, no free chunk physically borders another one,\n  so each free chunk is known to be preceded and followed by either\n  inuse chunks or the ends of memory.\n\n  Note that the `foot' of the current chunk is actually represented\n  as the prev_foot of the NEXT chunk. This makes it easier to\n  deal with alignments etc but can be very confusing when trying\n  to extend or adapt this code.\n\n  The exceptions to all this are\n\n     1. The special chunk `top' is the top-most available chunk (i.e.,\n        the one bordering the end of available memory). It is treated\n        specially.  Top is never included in any bin, is used only if\n        no other chunk is available, and is released back to the\n        system if it is very large (see M_TRIM_THRESHOLD).  In effect,\n        the top chunk is treated as larger (and thus less well\n        fitting) than any other available chunk.  The top chunk\n        doesn't update its trailing size field since there is no next\n        contiguous chunk that would have to index off it. However,\n        space is still allocated for it (TOP_FOOT_SIZE) to enable\n        separation or merging when space is extended.\n\n     3. Chunks allocated via mmap, have both cinuse and pinuse bits\n        cleared in their head fields.  Because they are allocated\n        one-by-one, each must carry its own prev_foot field, which is\n        also used to hold the offset this chunk has within its mmapped\n        region, which is needed to preserve alignment. Each mmapped\n        chunk is trailed by the first two fields of a fake next-chunk\n        for sake of usage checks.\n\n*/\n\nstruct malloc_chunk {\n  persist<size_t>               prev_foot;  /* Size of previous chunk (if free).  */\n  persist<size_t>               head;       /* Size and inuse bits. */\n  persist<struct malloc_chunk*> fd;         /* double links -- used only if free. */\n  persist<struct malloc_chunk*> bk;\n};\n\ntypedef struct malloc_chunk  mchunk;\ntypedef struct malloc_chunk* mchunkptr;\ntypedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */\ntypedef unsigned int bindex_t;         /* Described below */\ntypedef unsigned int binmap_t;         /* Described below */\ntypedef unsigned int flag_t;           /* The type of various bit flag sets */\n\n/* ------------------- Chunks sizes and alignments ----------------------- */\n\n#define MCHUNK_SIZE         (sizeof(mchunk))\n\n#if FOOTERS\n#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)\n#else /* FOOTERS */\n#define CHUNK_OVERHEAD      (SIZE_T_SIZE)\n#endif /* FOOTERS */\n\n/* MMapped chunks need a second word of overhead ... */\n#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)\n/* ... and additional padding for fake next-chunk at foot */\n#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)\n\n/* The smallest size we can malloc is an aligned minimal chunk */\n#define MIN_CHUNK_SIZE\\\n  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)\n\n/* conversion from malloc headers to user pointers, and back */\n#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))\n#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))\n/* chunk associated with aligned address A */\n#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))\n\n/* Bounds on request (not chunk) sizes. */\n#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)\n#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)\n\n/* pad request bytes into a usable size */\n#define pad_request(req) \\\n   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)\n\n/* pad request, checking for minimum (but not maximum) */\n#define request2size(req) \\\n  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))\n\n\n/* ------------------ Operations on head and foot fields ----------------- */\n\n/*\n  The head field of a chunk is or'ed with PINUSE_BIT when previous\n  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in\n  use, unless mmapped, in which case both bits are cleared.\n\n  FLAG4_BIT is not used by this malloc, but might be useful in extensions.\n*/\n\n#define PINUSE_BIT          (SIZE_T_ONE)\n#define CINUSE_BIT          (SIZE_T_TWO)\n#define FLAG4_BIT           (SIZE_T_FOUR)\n#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)\n#define FLAG_BITS           (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)\n\n/* Head value for fenceposts */\n#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)\n\n/* extraction of fields from head words */\n#define cinuse(p)           ((p)->head & CINUSE_BIT)\n#define pinuse(p)           ((p)->head & PINUSE_BIT)\n#define flag4inuse(p)       ((p)->head & FLAG4_BIT)\n#define is_inuse(p)         (((p)->head & INUSE_BITS) != PINUSE_BIT)\n#define is_mmapped(p)       (((p)->head & INUSE_BITS) == 0)\n\n#define chunksize(p)        ((p)->head & ~(FLAG_BITS))\n\n#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)\n#define set_flag4(p)        ((p)->head |= FLAG4_BIT)\n#define clear_flag4(p)      ((p)->head &= ~FLAG4_BIT)\n\n/* Treat space at ptr +/- offset as a chunk */\n#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))\n#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))\n\n/* Ptr to next or previous physical malloc_chunk. */\n#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))\n#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))\n\n/* extract next chunk's pinuse bit */\n#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)\n\n/* Get/set size at footer */\n#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)\n#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))\n\n/* Set size, pinuse bit, and foot */\n#define set_size_and_pinuse_of_free_chunk(p, s)\\\n  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))\n\n/* Set size, pinuse bit, foot, and clear next pinuse */\n#define set_free_with_pinuse(p, s, n)\\\n  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))\n\n/* Get the internal overhead associated with chunk p */\n#define overhead_for(p)\\\n (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)\n\n/* Return true if malloced space is not necessarily cleared */\n#if MMAP_CLEARS\n#define calloc_must_clear(p) (!is_mmapped(p))\n#else /* MMAP_CLEARS */\n#define calloc_must_clear(p) (1)\n#endif /* MMAP_CLEARS */\n\n/* ---------------------- Overlaid data structures ----------------------- */\n\n/*\n  When chunks are not in use, they are treated as nodes of either\n  lists or trees.\n\n  \"Small\"  chunks are stored in circular doubly-linked lists, and look\n  like this:\n\n    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Size of previous chunk                            |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `head:' |             Size of chunk, in bytes                         |P|\n      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Forward pointer to next chunk in list             |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Back pointer to previous chunk in list            |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Unused space (may be 0 bytes long)                .\n            .                                                               .\n            .                                                               |\nnextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `foot:' |             Size of chunk, in bytes                           |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n\n  Larger chunks are kept in a form of bitwise digital trees (aka\n  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for\n  free chunks greater than 256 bytes, their size doesn't impose any\n  constraints on user chunk sizes.  Each node looks like:\n\n    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Size of previous chunk                            |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `head:' |             Size of chunk, in bytes                         |P|\n      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Forward pointer to next chunk of same size        |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Back pointer to previous chunk of same size       |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Pointer to left child (child[0])                  |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Pointer to right child (child[1])                 |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Pointer to parent                                 |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             bin index of this chunk                           |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Unused space                                      .\n            .                                                               |\nnextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `foot:' |             Size of chunk, in bytes                           |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n\n  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks\n  of the same size are arranged in a circularly-linked list, with only\n  the oldest chunk (the next to be used, in our FIFO ordering)\n  actually in the tree.  (Tree members are distinguished by a non-null\n  parent pointer.)  If a chunk with the same size an an existing node\n  is inserted, it is linked off the existing node using pointers that\n  work in the same way as fd/bk pointers of small chunks.\n\n  Each tree contains a power of 2 sized range of chunk sizes (the\n  smallest is 0x100 <= x < 0x180), which is is divided in half at each\n  tree level, with the chunks in the smaller half of the range (0x100\n  <= x < 0x140 for the top nose) in the left subtree and the larger\n  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,\n  done by inspecting individual bits.\n\n  Using these rules, each node's left subtree contains all smaller\n  sizes than its right subtree.  However, the node at the root of each\n  subtree has no particular ordering relationship to either.  (The\n  dividing line between the subtree sizes is based on trie relation.)\n  If we remove the last chunk of a given size from the interior of the\n  tree, we need to replace it with a leaf node.  The tree ordering\n  rules permit a node to be replaced by any leaf below it.\n\n  The smallest chunk in a tree (a common operation in a best-fit\n  allocator) can be found by walking a path to the leftmost leaf in\n  the tree.  Unlike a usual binary tree, where we follow left child\n  pointers until we reach a null, here we follow the right child\n  pointer any time the left one is null, until we reach a leaf with\n  both child pointers null. The smallest chunk in the tree will be\n  somewhere along that path.\n\n  The worst case number of steps to add, find, or remove a node is\n  bounded by the number of bits differentiating chunks within\n  bins. Under current bin calculations, this ranges from 6 up to 21\n  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case\n  is of course much better.\n*/\n\nstruct malloc_tree_chunk {\n  /* The first four fields must be compatible with malloc_chunk */\n  persist<size_t>                    prev_foot;\n  persist<size_t>                    head;\n  persist<struct malloc_tree_chunk*> fd;\n  persist<struct malloc_tree_chunk*> bk;\n\n  persist<struct malloc_tree_chunk*> child[2];\n  persist<struct malloc_tree_chunk*> parent;\n  persist<bindex_t>                  index;\n};\n\ntypedef struct malloc_tree_chunk  tchunk;\ntypedef struct malloc_tree_chunk* tchunkptr;\ntypedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */\n\n/* A little helper macro for trees */\n#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])\n\n/* ----------------------------- Segments -------------------------------- */\n\n/*\n  Each malloc space may include non-contiguous segments, held in a\n  list headed by an embedded malloc_segment record representing the\n  top-most space. Segments also include flags holding properties of\n  the space. Large chunks that are directly allocated by mmap are not\n  included in this list. They are instead independently created and\n  destroyed without otherwise keeping track of them.\n\n  Segment management mainly comes into play for spaces allocated by\n  MMAP.  Any call to MMAP might or might not return memory that is\n  adjacent to an existing segment.  MORECORE normally contiguously\n  extends the current space, so this space is almost always adjacent,\n  which is simpler and faster to deal with. (This is why MORECORE is\n  used preferentially to MMAP when both are available -- see\n  sys_alloc.)  When allocating using MMAP, we don't use any of the\n  hinting mechanisms (inconsistently) supported in various\n  implementations of unix mmap, or distinguish reserving from\n  committing memory. Instead, we just ask for space, and exploit\n  contiguity when we get it.  It is probably possible to do\n  better than this on some systems, but no general scheme seems\n  to be significantly better.\n\n  Management entails a simpler variant of the consolidation scheme\n  used for chunks to reduce fragmentation -- new adjacent memory is\n  normally prepended or appended to an existing segment. However,\n  there are limitations compared to chunk consolidation that mostly\n  reflect the fact that segment processing is relatively infrequent\n  (occurring only when getting memory from system) and that we\n  don't expect to have huge numbers of segments:\n\n  * Segments are not indexed, so traversal requires linear scans.  (It\n    would be possible to index these, but is not worth the extra\n    overhead and complexity for most programs on most platforms.)\n  * New segments are only appended to old ones when holding top-most\n    memory; if they cannot be prepended to others, they are held in\n    different segments.\n\n  Except for the top-most segment of an mstate, each segment record\n  is kept at the tail of its segment. Segments are added by pushing\n  segment records onto the list headed by &mstate.seg for the\n  containing mstate.\n\n  Segment flags control allocation/merge/deallocation policies:\n  * If EXTERN_BIT set, then we did not allocate this segment,\n    and so should not try to deallocate or merge with others.\n    (This currently holds only for the initial segment passed\n    into create_mspace_with_base.)\n  * If USE_MMAP_BIT set, the segment may be merged with\n    other surrounding mmapped segments and trimmed/de-allocated\n    using munmap.\n  * If neither bit is set, then the segment was obtained using\n    MORECORE so can be merged with surrounding MORECORE'd segments\n    and deallocated/trimmed using MORECORE with negative arguments.\n*/\n\nstruct malloc_segment {\n  persist<char*>       base;             /* base address */\n  persist<size_t>       size;             /* allocated size */\n  persist<struct malloc_segment*> next;   /* ptr to next segment */\n  persist<flag_t>       sflags;           /* mmap and extern flag */\n};\n\n#define is_mmapped_segment(S)  ((S)->sflags & USE_MMAP_BIT)\n#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)\n\ntypedef struct malloc_segment  msegment;\ntypedef struct malloc_segment* msegmentptr;\n\n/* ---------------------------- malloc_state ----------------------------- */\n\n/*\n   A malloc_state holds all of the bookkeeping for a space.\n   The main fields are:\n\n  Top\n    The topmost chunk of the currently active segment. Its size is\n    cached in topsize.  The actual size of topmost space is\n    topsize+TOP_FOOT_SIZE, which includes space reserved for adding\n    fenceposts and segment records if necessary when getting more\n    space from the system.  The size at which to autotrim top is\n    cached from mparams in trim_check, except that it is disabled if\n    an autotrim fails.\n\n  Designated victim (dv)\n    This is the preferred chunk for servicing small requests that\n    don't have exact fits.  It is normally the chunk split off most\n    recently to service another small request.  Its size is cached in\n    dvsize. The link fields of this chunk are not maintained since it\n    is not kept in a bin.\n\n  SmallBins\n    An array of bin headers for free chunks.  These bins hold chunks\n    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains\n    chunks of all the same size, spaced 8 bytes apart.  To simplify\n    use in double-linked lists, each bin header acts as a malloc_chunk\n    pointing to the real first node, if it exists (else pointing to\n    itself).  This avoids special-casing for headers.  But to avoid\n    waste, we allocate only the fd/bk pointers of bins, and then use\n    repositioning tricks to treat these as the fields of a chunk.\n\n  TreeBins\n    Treebins are pointers to the roots of trees holding a range of\n    sizes. There are 2 equally spaced treebins for each power of two\n    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything\n    larger.\n\n  Bin maps\n    There is one bit map for small bins (\"smallmap\") and one for\n    treebins (\"treemap).  Each bin sets its bit when non-empty, and\n    clears the bit when empty.  Bit operations are then used to avoid\n    bin-by-bin searching -- nearly all \"search\" is done without ever\n    looking at bins that won't be selected.  The bit maps\n    conservatively use 32 bits per map word, even if on 64bit system.\n    For a good description of some of the bit-based techniques used\n    here, see Henry S. Warren Jr's book \"Hacker's Delight\" (and\n    supplement at http://hackersdelight.org/). Many of these are\n    intended to reduce the branchiness of paths through malloc etc, as\n    well as to reduce the number of memory locations read or written.\n\n  Segments\n    A list of segments headed by an embedded malloc_segment record\n    representing the initial space.\n\n  Address check support\n    The least_addr field is the least address ever obtained from\n    MORECORE or MMAP. Attempted frees and reallocs of any address less\n    than this are trapped (unless INSECURE is defined).\n\n  Magic tag\n    A cross-check field that should always hold same value as mparams.magic.\n\n  Max allowed footprint\n    The maximum allowed bytes to allocate from system (zero means no limit)\n\n  Flags\n    Bits recording whether to use MMAP, locks, or contiguous MORECORE\n\n  Statistics\n    Each space keeps track of current and maximum system memory\n    obtained via MORECORE or MMAP.\n\n  Trim support\n    Fields holding the amount of unused topmost memory that should trigger\n    trimming, and a counter to force periodic scanning to release unused\n    non-topmost segments.\n\n  Locking\n    If USE_LOCKS is defined, the \"mutex\" lock is acquired and released\n    around every public call using this mspace.\n\n  Extension support\n    A void* pointer and a size_t field that can be used to help implement\n    extensions to this malloc.\n*/\n\n/* Bin types, widths and sizes */\n#define NSMALLBINS        (32U)\n#define NTREEBINS         (32U)\n#define SMALLBIN_SHIFT    (3U)\n#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)\n#define TREEBIN_SHIFT     (8U)\n#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)\n#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)\n#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)\n\nstruct malloc_state {\n  persist<binmap_t>   smallmap;\n  persist<binmap_t>   treemap;\n  persist<size_t>     dvsize;\n  persist<size_t>     topsize;\n  persist<char*>      least_addr;\n  persist<mchunkptr>  dv;\n  persist<mchunkptr>  top;\n  persist<size_t>     trim_check;\n  persist<size_t>     release_checks;\n  persist<size_t>     magic;\n  persist<mchunkptr>  smallbins[(NSMALLBINS+1)*2];\n  persist<tbinptr>    treebins[NTREEBINS];\n  persist<size_t>     footprint;\n  persist<size_t>     max_footprint;\n  persist<size_t>     footprint_limit; /* zero means no limit */\n  persist<flag_t>     mflags;\n#if USE_LOCKS\n  MLOCK_T    mutex;     /* locate lock among fields that rarely change */\n#endif /* USE_LOCKS */\n  msegment   seg;\n  persist<void*>      extp;      /* Unused but available for extensions */\n  persist<size_t>     exts;\n};\n\ntypedef struct malloc_state*    mstate;\n\n/* ------------- Global malloc_state and malloc_params ------------------- */\n\n/*\n  malloc_params holds global properties, including those that can be\n  dynamically set using mallopt. There is a single instance, mparams,\n  initialized in init_mparams. Note that the non-zeroness of \"magic\"\n  also serves as an initialization flag.\n*/\n\nstruct malloc_params {\n  size_t magic;\n  size_t page_size;\n  size_t granularity;\n  size_t mmap_threshold;\n  size_t trim_threshold;\n  flag_t default_mflags;\n};\n\nstatic struct malloc_params mparams;\n\n/* Ensure mparams initialized */\n#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())\n\n#if !ONLY_MSPACES\n\n/* The global malloc_state used for all non-\"mspace\" calls */\nstatic struct malloc_state _gm_;\n#define gm                 (&_gm_)\n#define is_global(M)       ((M) == &_gm_)\n\n#endif /* !ONLY_MSPACES */\n\n#define is_initialized(M)  ((M)->top != 0)\n\n/* -------------------------- system alloc setup ------------------------- */\n\n/* Operations on mflags */\n\n#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)\n#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)\n#if USE_LOCKS\n#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)\n#else\n#define disable_lock(M)\n#endif\n\n#define use_mmap(M)           ((M)->mflags &   (flag_t)USE_MMAP_BIT)\n#define enable_mmap(M)        ((M)->mflags |=  (flag_t)USE_MMAP_BIT)\n#if HAVE_MMAP\n#define disable_mmap(M)       ((M)->mflags &=  (flag_t)~USE_MMAP_BIT)\n#else\n#define disable_mmap(M)\n#endif\n\n#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)\n#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)\n\n#define set_lock(M,L)\\\n ((M)->mflags = (L)?\\\n  ((M)->mflags | USE_LOCK_BIT) :\\\n  ((M)->mflags & ~USE_LOCK_BIT))\n\n/* page-align a size */\n#define page_align(S)\\\n (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))\n\n/* granularity-align a size */\n#define granularity_align(S)\\\n  (((S) + (mparams.granularity - SIZE_T_ONE))\\\n   & ~(mparams.granularity - SIZE_T_ONE))\n\n\n/* For mmap, use granularity alignment on windows, else page-align */\n#ifdef WIN32\n#define mmap_align(S) granularity_align(S)\n#else\n#define mmap_align(S) page_align(S)\n#endif\n\n/* For sys_alloc, enough padding to ensure can malloc request on success */\n#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)\n\n#define is_page_aligned(S)\\\n   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)\n#define is_granularity_aligned(S)\\\n   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)\n\n/*  True if segment S holds address A */\n#define segment_holds(S, A)\\\n  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)\n\n/* Return segment holding given address */\nstatic msegmentptr segment_holding(mstate m, char* addr) {\n  msegmentptr sp = &m->seg;\n  for (;;) {\n    if (addr >= sp->base && addr < sp->base + sp->size)\n      return sp;\n    if ((sp = sp->next) == 0)\n      return 0;\n  }\n}\n\n/* Return true if segment contains a segment link */\nstatic int has_segment_link(mstate m, msegmentptr ss) {\n  msegmentptr sp = &m->seg;\n  for (;;) {\n    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)\n      return 1;\n    if ((sp = sp->next) == 0)\n      return 0;\n  }\n}\n\n#ifndef MORECORE_CANNOT_TRIM\n#define should_trim(M,s)  ((s) > (M)->trim_check)\n#else  /* MORECORE_CANNOT_TRIM */\n#define should_trim(M,s)  (0)\n#endif /* MORECORE_CANNOT_TRIM */\n\n/*\n  TOP_FOOT_SIZE is padding at the end of a segment, including space\n  that may be needed to place segment records and fenceposts when new\n  noncontiguous segments are added.\n*/\n#define TOP_FOOT_SIZE\\\n  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)\n\n\n/* -------------------------------  Hooks -------------------------------- */\n\n/*\n  PREACTION should be defined to return 0 on success, and nonzero on\n  failure. If you are not using locking, you can redefine these to do\n  anything you like.\n*/\n\n#if USE_LOCKS\n#define PREACTION(M)  ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)\n#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }\n#else /* USE_LOCKS */\n\n#ifndef PREACTION\n#define PREACTION(M) (0)\n#endif  /* PREACTION */\n\n#ifndef POSTACTION\n#define POSTACTION(M)\n#endif  /* POSTACTION */\n\n#endif /* USE_LOCKS */\n\n/*\n  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.\n  USAGE_ERROR_ACTION is triggered on detected bad frees and\n  reallocs. The argument p is an address that might have triggered the\n  fault. It is ignored by the two predefined actions, but might be\n  useful in custom actions that try to help diagnose errors.\n*/\n\n#if PROCEED_ON_ERROR\n\n/* A count of the number of corruption errors causing resets */\nint malloc_corruption_error_count;\n\n/* default corruption action */\nstatic void reset_on_error(mstate m);\n\n#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)\n#define USAGE_ERROR_ACTION(m, p)\n\n#else /* PROCEED_ON_ERROR */\n\n#ifndef CORRUPTION_ERROR_ACTION\n#define CORRUPTION_ERROR_ACTION(m) ABORT\n#endif /* CORRUPTION_ERROR_ACTION */\n\n#ifndef USAGE_ERROR_ACTION\n#define USAGE_ERROR_ACTION(m,p) ABORT\n#endif /* USAGE_ERROR_ACTION */\n\n#endif /* PROCEED_ON_ERROR */\n\n\n/* -------------------------- Debugging setup ---------------------------- */\n\n#if ! DEBUG\n\n#define check_free_chunk(M,P)\n#define check_inuse_chunk(M,P)\n#define check_malloced_chunk(M,P,N)\n#define check_mmapped_chunk(M,P)\n#define check_malloc_state(M)\n#define check_top_chunk(M,P)\n\n#else /* DEBUG */\n#define check_free_chunk(M,P)       do_check_free_chunk(M,P)\n#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)\n#define check_top_chunk(M,P)        do_check_top_chunk(M,P)\n#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)\n#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)\n#define check_malloc_state(M)       do_check_malloc_state(M)\n\nstatic void   do_check_any_chunk(mstate m, mchunkptr p);\nstatic void   do_check_top_chunk(mstate m, mchunkptr p);\nstatic void   do_check_mmapped_chunk(mstate m, mchunkptr p);\nstatic void   do_check_inuse_chunk(mstate m, mchunkptr p);\nstatic void   do_check_free_chunk(mstate m, mchunkptr p);\nstatic void   do_check_malloced_chunk(mstate m, void* mem, size_t s);\nstatic void   do_check_tree(mstate m, tchunkptr t);\nstatic void   do_check_treebin(mstate m, bindex_t i);\nstatic void   do_check_smallbin(mstate m, bindex_t i);\nstatic void   do_check_malloc_state(mstate m);\nstatic int    bin_find(mstate m, mchunkptr x);\nstatic size_t traverse_and_check(mstate m);\n#endif /* DEBUG */\n\n/* ---------------------------- Indexing Bins ---------------------------- */\n\n#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)\n#define small_index(s)      (bindex_t)((s)  >> SMALLBIN_SHIFT)\n#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)\n#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))\n\n/* addressing by index. See above about smallbin repositioning */\n#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))\n#define treebin_at(M,i)     ((persist<tbinptr>*)&((M)->treebins[i]))\n\n/* assign tree index for size S to variable I. Use x86 asm if possible  */\n#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))\n#define compute_tree_index(S, I)\\\n{\\\n  unsigned int X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \\\n    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\\\n  }\\\n}\n\n#elif defined (__INTEL_COMPILER)\n#define compute_tree_index(S, I)\\\n{\\\n  size_t X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int K = _bit_scan_reverse (X); \\\n    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\\\n  }\\\n}\n\n#elif defined(_MSC_VER) && _MSC_VER>=1300\n#define compute_tree_index(S, I)\\\n{\\\n  size_t X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int K;\\\n    _BitScanReverse((DWORD *) &K, (DWORD) X);\\\n    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\\\n  }\\\n}\n\n#else /* GNUC */\n#define compute_tree_index(S, I)\\\n{\\\n  size_t X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int Y = (unsigned int)X;\\\n    unsigned int N = ((Y - 0x100) >> 16) & 8;\\\n    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\\\n    N += K;\\\n    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\\\n    K = 14 - N + ((Y <<= K) >> 15);\\\n    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\\\n  }\\\n}\n#endif /* GNUC */\n\n/* Bit representing maximum resolved size in a treebin at i */\n#define bit_for_tree_index(i) \\\n   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)\n\n/* Shift placing maximum resolved bit in a treebin at i as sign bit */\n#define leftshift_for_tree_index(i) \\\n   ((i == NTREEBINS-1)? 0 : \\\n    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))\n\n/* The size of the smallest chunk held in bin with index i */\n#define minsize_for_tree_index(i) \\\n   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \\\n   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))\n\n\n/* ------------------------ Operations on bin maps ----------------------- */\n\n/* bit corresponding to given index */\n#define idx2bit(i)              ((binmap_t)(1) << (i))\n\n/* Mark/Clear bits with given index */\n#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))\n#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))\n#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))\n\n#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))\n#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))\n#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))\n\n/* isolate the least set bit of a bitmap */\n#define least_bit(x)         ((x) & -(x))\n\n/* mask with all bits to left of least bit of x on */\n#define left_bits(x)         ((x<<1) | -(x<<1))\n\n/* mask with all bits to left of or equal to least bit of x on */\n#define same_or_left_bits(x) ((x) | -(x))\n\n/* index corresponding to given bit. Use x86 asm if possible */\n\n#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int J;\\\n  J = __builtin_ctz(X); \\\n  I = (bindex_t)J;\\\n}\n\n#elif defined (__INTEL_COMPILER)\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int J;\\\n  J = _bit_scan_forward (X); \\\n  I = (bindex_t)J;\\\n}\n\n#elif defined(_MSC_VER) && _MSC_VER>=1300\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int J;\\\n  _BitScanForward((DWORD *) &J, X);\\\n  I = (bindex_t)J;\\\n}\n\n#elif USE_BUILTIN_FFS\n#define compute_bit2idx(X, I) I = ffs(X)-1\n\n#else\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int Y = X - 1;\\\n  unsigned int K = Y >> (16-4) & 16;\\\n  unsigned int N = K;        Y >>= K;\\\n  N += K = Y >> (8-3) &  8;  Y >>= K;\\\n  N += K = Y >> (4-2) &  4;  Y >>= K;\\\n  N += K = Y >> (2-1) &  2;  Y >>= K;\\\n  N += K = Y >> (1-0) &  1;  Y >>= K;\\\n  I = (bindex_t)(N + Y);\\\n}\n#endif /* GNUC */\n\n\n/* ----------------------- Runtime Check Support ------------------------- */\n\n/*\n  For security, the main invariant is that malloc/free/etc never\n  writes to a static address other than malloc_state, unless static\n  malloc_state itself has been corrupted, which cannot occur via\n  malloc (because of these checks). In essence this means that we\n  believe all pointers, sizes, maps etc held in malloc_state, but\n  check all of those linked or offsetted from other embedded data\n  structures.  These checks are interspersed with main code in a way\n  that tends to minimize their run-time cost.\n\n  When FOOTERS is defined, in addition to range checking, we also\n  verify footer fields of inuse chunks, which can be used guarantee\n  that the mstate controlling malloc/free is intact.  This is a\n  streamlined version of the approach described by William Robertson\n  et al in \"Run-time Detection of Heap-based Overflows\" LISA'03\n  http://www.usenix.org/events/lisa03/tech/robertson.html The footer\n  of an inuse chunk holds the xor of its mstate and a random seed,\n  that is checked upon calls to free() and realloc().  This is\n  (probabalistically) unguessable from outside the program, but can be\n  computed by any code successfully malloc'ing any chunk, so does not\n  itself provide protection against code that has already broken\n  security through some other means.  Unlike Robertson et al, we\n  always dynamically check addresses of all offset chunks (previous,\n  next, etc). This turns out to be cheaper than relying on hashes.\n*/\n\n#if !INSECURE\n/* Check if address a is at least as high as any from MORECORE or MMAP */\n#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)\n/* Check if address of next chunk n is higher than base chunk p */\n#define ok_next(p, n)    ((char*)(p) < (char*)(n))\n/* Check if p has inuse status */\n#define ok_inuse(p)     is_inuse(p)\n/* Check if p has its pinuse bit on */\n#define ok_pinuse(p)     pinuse(p)\n\n#else /* !INSECURE */\n#define ok_address(M, a) (1)\n#define ok_next(b, n)    (1)\n#define ok_inuse(p)      (1)\n#define ok_pinuse(p)     (1)\n#endif /* !INSECURE */\n\n#if (FOOTERS && !INSECURE)\n/* Check if (alleged) mstate m has expected magic field */\n#define ok_magic(M)      ((M)->magic == mparams.magic)\n#else  /* (FOOTERS && !INSECURE) */\n#define ok_magic(M)      (1)\n#endif /* (FOOTERS && !INSECURE) */\n\n/* In gcc, use __builtin_expect to minimize impact of checks */\n#if !INSECURE\n#if defined(__GNUC__) && __GNUC__ >= 3\n#define RTCHECK(e)  __builtin_expect(e, 1)\n#else /* GNUC */\n#define RTCHECK(e)  (e)\n#endif /* GNUC */\n#else /* !INSECURE */\n#define RTCHECK(e)  (1)\n#endif /* !INSECURE */\n\n/* macros to set up inuse chunks with or without footers */\n\n#if !FOOTERS\n\n#define mark_inuse_foot(M,p,s)\n\n/* Macros for setting head/foot of non-mmapped chunks */\n\n/* Set cinuse bit and pinuse bit of next chunk */\n#define set_inuse(M,p,s)\\\n  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\\\n  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)\n\n/* Set cinuse and pinuse of this chunk and pinuse of next chunk */\n#define set_inuse_and_pinuse(M,p,s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\\\n  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)\n\n/* Set size, cinuse and pinuse bit of this chunk */\n#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))\n\n#else /* FOOTERS */\n\n/* Set foot of inuse chunk to be xor of mstate and seed */\n#define mark_inuse_foot(M,p,s)\\\n  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))\n\n#define get_mstate_for(p)\\\n  ((mstate)(((mchunkptr)((char*)(p) +\\\n    (chunksize(p))))->prev_foot ^ mparams.magic))\n\n#define set_inuse(M,p,s)\\\n  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\\\n  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \\\n  mark_inuse_foot(M,p,s))\n\n#define set_inuse_and_pinuse(M,p,s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\\\n  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\\\n mark_inuse_foot(M,p,s))\n\n#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\\\n  mark_inuse_foot(M, p, s))\n\n#endif /* !FOOTERS */\n\n/* ---------------------------- setting mparams -------------------------- */\n\n#if LOCK_AT_FORK\nstatic void pre_fork(void)         { ACQUIRE_LOCK(&(gm)->mutex); }\nstatic void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); }\nstatic void post_fork_child(void)  { INITIAL_LOCK(&(gm)->mutex); }\n#endif /* LOCK_AT_FORK */\n\n/* Initialize mparams */\nstatic int init_mparams(void) {\n#ifdef NEED_GLOBAL_LOCK_INIT\n  if (malloc_global_mutex_status <= 0)\n    init_malloc_global_mutex();\n#endif\n\n  ACQUIRE_MALLOC_GLOBAL_LOCK();\n  if (mparams.magic == 0) {\n    size_t magic;\n    size_t psize;\n    size_t gsize;\n\n#ifndef WIN32\n    psize = malloc_getpagesize;\n    gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);\n#else /* WIN32 */\n    {\n      SYSTEM_INFO system_info;\n      GetSystemInfo(&system_info);\n      psize = system_info.dwPageSize;\n      gsize = ((DEFAULT_GRANULARITY != 0)?\n               DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);\n    }\n#endif /* WIN32 */\n\n    /* Sanity-check configuration:\n       size_t must be unsigned and as wide as pointer type.\n       ints must be at least 4 bytes.\n       alignment must be at least 8.\n       Alignment, min chunk size, and page size must all be powers of 2.\n    */\n    if ((sizeof(size_t) != sizeof(char*)) ||\n        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||\n        (sizeof(int) < 4)  ||\n        (MALLOC_ALIGNMENT < (size_t)8U) ||\n        ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||\n        ((MCHUNK_SIZE      & (MCHUNK_SIZE-SIZE_T_ONE))      != 0) ||\n        ((gsize            & (gsize-SIZE_T_ONE))            != 0) ||\n        ((psize            & (psize-SIZE_T_ONE))            != 0))\n      ABORT;\n    mparams.granularity = gsize;\n    mparams.page_size = psize;\n    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;\n    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;\n#if MORECORE_CONTIGUOUS\n    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;\n#else  /* MORECORE_CONTIGUOUS */\n    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;\n#endif /* MORECORE_CONTIGUOUS */\n\n#if !ONLY_MSPACES\n    /* Set up lock for main malloc area */\n    gm->mflags = mparams.default_mflags;\n    (void)INITIAL_LOCK(&gm->mutex);\n#endif\n#if LOCK_AT_FORK\n    pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);\n#endif\n\n    {\n#if USE_DEV_RANDOM\n      int fd;\n      unsigned char buf[sizeof(size_t)];\n      /* Try to use /dev/urandom, else fall back on using time */\n      if ((fd = open(\"/dev/urandom\", O_RDONLY)) >= 0 &&\n          read(fd, buf, sizeof(buf)) == sizeof(buf)) {\n        magic = *((size_t *) buf);\n        close(fd);\n      }\n      else\n#endif /* USE_DEV_RANDOM */\n#ifdef WIN32\n      magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);\n#elif defined(LACKS_TIME_H)\n      magic = (size_t)&magic ^ (size_t)0x55555555U;\n#else\n      magic = (size_t)(time(0) ^ (size_t)0x55555555U);\n#endif\n      magic |= (size_t)8U;    /* ensure nonzero */\n      magic &= ~(size_t)7U;   /* improve chances of fault for bad values */\n      /* Until memory modes commonly available, use volatile-write */\n      (*(volatile size_t *)(&(mparams.magic))) = magic;\n    }\n  }\n\n  RELEASE_MALLOC_GLOBAL_LOCK();\n  return 1;\n}\n\n/* support for mallopt */\nstatic int change_mparam(int param_number, int value) {\n  size_t val;\n  ensure_initialization();\n  val = (value == -1)? MAX_SIZE_T : (size_t)value;\n  switch(param_number) {\n  case M_TRIM_THRESHOLD:\n    mparams.trim_threshold = val;\n    return 1;\n  case M_GRANULARITY:\n    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {\n      mparams.granularity = val;\n      return 1;\n    }\n    else\n      return 0;\n  case M_MMAP_THRESHOLD:\n    mparams.mmap_threshold = val;\n    return 1;\n  default:\n    return 0;\n  }\n}\n\n#if DEBUG\n/* ------------------------- Debugging Support --------------------------- */\n\n/* Check properties of any chunk, whether free, inuse, mmapped etc  */\nstatic void do_check_any_chunk(mstate m, mchunkptr p) {\n  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));\n  assert(ok_address(m, p));\n}\n\n/* Check properties of top chunk */\nstatic void do_check_top_chunk(mstate m, mchunkptr p) {\n  msegmentptr sp = segment_holding(m, (char*)p);\n  size_t  sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */\n  assert(sp != 0);\n  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));\n  assert(ok_address(m, p));\n  assert(sz == m->topsize);\n  assert(sz > 0);\n  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);\n  assert(pinuse(p));\n  assert(!pinuse(chunk_plus_offset(p, sz)));\n}\n\n/* Check properties of (inuse) mmapped chunks */\nstatic void do_check_mmapped_chunk(mstate m, mchunkptr p) {\n  size_t  sz = chunksize(p);\n  size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);\n  assert(is_mmapped(p));\n  assert(use_mmap(m));\n  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));\n  assert(ok_address(m, p));\n  assert(!is_small(sz));\n  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);\n  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);\n  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);\n}\n\n/* Check properties of inuse chunks */\nstatic void do_check_inuse_chunk(mstate m, mchunkptr p) {\n  do_check_any_chunk(m, p);\n  assert(is_inuse(p));\n  assert(next_pinuse(p));\n  /* If not pinuse and not mmapped, previous chunk has OK offset */\n  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);\n  if (is_mmapped(p))\n    do_check_mmapped_chunk(m, p);\n}\n\n/* Check properties of free chunks */\nstatic void do_check_free_chunk(mstate m, mchunkptr p) {\n  size_t sz = chunksize(p);\n  mchunkptr next = chunk_plus_offset(p, sz);\n  do_check_any_chunk(m, p);\n  assert(!is_inuse(p));\n  assert(!next_pinuse(p));\n  assert (!is_mmapped(p));\n  if (p != m->dv && p != m->top) {\n    if (sz >= MIN_CHUNK_SIZE) {\n      assert((sz & CHUNK_ALIGN_MASK) == 0);\n      assert(is_aligned(chunk2mem(p)));\n      assert(next->prev_foot == sz);\n      assert(pinuse(p));\n      assert (next == m->top || is_inuse(next));\n      assert(p->fd->bk == p);\n      assert(p->bk->fd == p);\n    }\n    else  /* markers are always of size SIZE_T_SIZE */\n      assert(sz == SIZE_T_SIZE);\n  }\n}\n\n/* Check properties of malloced chunks at the point they are malloced */\nstatic void do_check_malloced_chunk(mstate m, void* mem, size_t s) {\n  if (mem != 0) {\n    mchunkptr p = mem2chunk(mem);\n    size_t sz = p->head & ~INUSE_BITS;\n    do_check_inuse_chunk(m, p);\n    assert((sz & CHUNK_ALIGN_MASK) == 0);\n    assert(sz >= MIN_CHUNK_SIZE);\n    assert(sz >= s);\n    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */\n    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));\n  }\n}\n\n/* Check a tree and its subtrees.  */\nstatic void do_check_tree(mstate m, tchunkptr t) {\n  tchunkptr head = 0;\n  tchunkptr u = t;\n  bindex_t tindex = t->index;\n  size_t tsize = chunksize(t);\n  bindex_t idx;\n  compute_tree_index(tsize, idx);\n  assert(tindex == idx);\n  assert(tsize >= MIN_LARGE_SIZE);\n  assert(tsize >= minsize_for_tree_index(idx));\n  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));\n\n  do { /* traverse through chain of same-sized nodes */\n    do_check_any_chunk(m, ((mchunkptr)u));\n    assert(u->index == tindex);\n    assert(chunksize(u) == tsize);\n    assert(!is_inuse(u));\n    assert(!next_pinuse(u));\n    assert(u->fd->bk == u);\n    assert(u->bk->fd == u);\n    if (u->parent == 0) {\n      assert(u->child[0] == 0);\n      assert(u->child[1] == 0);\n    }\n    else {\n      assert(head == 0); /* only one node on chain has parent */\n      head = u;\n      assert(u->parent != u);\n      assert (u->parent->child[0] == u ||\n              u->parent->child[1] == u ||\n              *((tbinptr*)(u->parent)) == u);\n      if (u->child[0] != 0) {\n        assert(u->child[0]->parent == u);\n        assert(u->child[0] != u);\n        do_check_tree(m, u->child[0]);\n      }\n      if (u->child[1] != 0) {\n        assert(u->child[1]->parent == u);\n        assert(u->child[1] != u);\n        do_check_tree(m, u->child[1]);\n      }\n      if (u->child[0] != 0 && u->child[1] != 0) {\n        assert(chunksize(u->child[0]) < chunksize(u->child[1]));\n      }\n    }\n    u = u->fd;\n  } while (u != t);\n  assert(head != 0);\n}\n\n/*  Check all the chunks in a treebin.  */\nstatic void do_check_treebin(mstate m, bindex_t i) {\n  tbinptr* tb = treebin_at(m, i);\n  tchunkptr t = *tb;\n  int empty = (m->treemap & (1U << i)) == 0;\n  if (t == 0)\n    assert(empty);\n  if (!empty)\n    do_check_tree(m, t);\n}\n\n/*  Check all the chunks in a smallbin.  */\nstatic void do_check_smallbin(mstate m, bindex_t i) {\n  sbinptr b = smallbin_at(m, i);\n  mchunkptr p = b->bk;\n  unsigned int empty = (m->smallmap & (1U << i)) == 0;\n  if (p == b)\n    assert(empty);\n  if (!empty) {\n    for (; p != b; p = p->bk) {\n      size_t size = chunksize(p);\n      mchunkptr q;\n      /* each chunk claims to be free */\n      do_check_free_chunk(m, p);\n      /* chunk belongs in bin */\n      assert(small_index(size) == i);\n      assert(p->bk == b || chunksize(p->bk) == chunksize(p));\n      /* chunk is followed by an inuse chunk */\n      q = next_chunk(p);\n      if (q->head != FENCEPOST_HEAD)\n        do_check_inuse_chunk(m, q);\n    }\n  }\n}\n\n/* Find x in a bin. Used in other check functions. */\nstatic int bin_find(mstate m, mchunkptr x) {\n  size_t size = chunksize(x);\n  if (is_small(size)) {\n    bindex_t sidx = small_index(size);\n    sbinptr b = smallbin_at(m, sidx);\n    if (smallmap_is_marked(m, sidx)) {\n      mchunkptr p = b;\n      do {\n        if (p == x)\n          return 1;\n      } while ((p = p->fd) != b);\n    }\n  }\n  else {\n    bindex_t tidx;\n    compute_tree_index(size, tidx);\n    if (treemap_is_marked(m, tidx)) {\n      tchunkptr t = *treebin_at(m, tidx);\n      size_t sizebits = size << leftshift_for_tree_index(tidx);\n      while (t != 0 && chunksize(t) != size) {\n        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];\n        sizebits <<= 1;\n      }\n      if (t != 0) {\n        tchunkptr u = t;\n        do {\n          if (u == (tchunkptr)x)\n            return 1;\n        } while ((u = u->fd) != t);\n      }\n    }\n  }\n  return 0;\n}\n\n/* Traverse each chunk and check it; return total */\nstatic size_t traverse_and_check(mstate m) {\n  size_t sum = 0;\n  if (is_initialized(m)) {\n    msegmentptr s = &m->seg;\n    sum += m->topsize + TOP_FOOT_SIZE;\n    while (s != 0) {\n      mchunkptr q = align_as_chunk(s->base);\n      mchunkptr lastq = 0;\n      assert(pinuse(q));\n      while (segment_holds(s, q) &&\n             q != m->top && q->head != FENCEPOST_HEAD) {\n        sum += chunksize(q);\n        if (is_inuse(q)) {\n          assert(!bin_find(m, q));\n          do_check_inuse_chunk(m, q);\n        }\n        else {\n          assert(q == m->dv || bin_find(m, q));\n          assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */\n          do_check_free_chunk(m, q);\n        }\n        lastq = q;\n        q = next_chunk(q);\n      }\n      s = s->next;\n    }\n  }\n  return sum;\n}\n\n\n/* Check all properties of malloc_state. */\nstatic void do_check_malloc_state(mstate m) {\n  bindex_t i;\n  size_t total;\n  /* check bins */\n  for (i = 0; i < NSMALLBINS; ++i)\n    do_check_smallbin(m, i);\n  for (i = 0; i < NTREEBINS; ++i)\n    do_check_treebin(m, i);\n\n  if (m->dvsize != 0) { /* check dv chunk */\n    do_check_any_chunk(m, m->dv);\n    assert(m->dvsize == chunksize(m->dv));\n    assert(m->dvsize >= MIN_CHUNK_SIZE);\n    assert(bin_find(m, m->dv) == 0);\n  }\n\n  if (m->top != 0) {   /* check top chunk */\n    do_check_top_chunk(m, m->top);\n    /*assert(m->topsize == chunksize(m->top)); redundant */\n    assert(m->topsize > 0);\n    assert(bin_find(m, m->top) == 0);\n  }\n\n  total = traverse_and_check(m);\n  assert(total <= m->footprint);\n  assert(m->footprint <= m->max_footprint);\n}\n#endif /* DEBUG */\n\n/* ----------------------------- statistics ------------------------------ */\n\n#if !NO_MALLINFO\nstatic struct mallinfo internal_mallinfo(mstate m) {\n  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\n  ensure_initialization();\n  if (!PREACTION(m)) {\n    check_malloc_state(m);\n    if (is_initialized(m)) {\n      size_t nfree = SIZE_T_ONE; /* top always free */\n      size_t mfree = m->topsize + TOP_FOOT_SIZE;\n      size_t sum = mfree;\n      msegmentptr s = &m->seg;\n      while (s != 0) {\n        mchunkptr q = align_as_chunk(s->base);\n        while (segment_holds(s, q) &&\n               q != m->top && q->head != FENCEPOST_HEAD) {\n          size_t sz = chunksize(q);\n          sum += sz;\n          if (!is_inuse(q)) {\n            mfree += sz;\n            ++nfree;\n          }\n          q = next_chunk(q);\n        }\n        s = s->next;\n      }\n\n      nm.arena    = sum;\n      nm.ordblks  = nfree;\n      nm.hblkhd   = m->footprint - sum;\n      nm.usmblks  = m->max_footprint;\n      nm.uordblks = m->footprint - mfree;\n      nm.fordblks = mfree;\n      nm.keepcost = m->topsize;\n    }\n\n    POSTACTION(m);\n  }\n  return nm;\n}\n#endif /* !NO_MALLINFO */\n\n#if !NO_MALLOC_STATS\nstatic void internal_malloc_stats(mstate m) {\n  ensure_initialization();\n  if (!PREACTION(m)) {\n    size_t maxfp = 0;\n    size_t fp = 0;\n    size_t used = 0;\n    check_malloc_state(m);\n    if (is_initialized(m)) {\n      msegmentptr s = &m->seg;\n      maxfp = m->max_footprint;\n      fp = m->footprint;\n      used = fp - (m->topsize + TOP_FOOT_SIZE);\n\n      while (s != 0) {\n        mchunkptr q = align_as_chunk(s->base);\n        while (segment_holds(s, q) &&\n               q != m->top && q->head != FENCEPOST_HEAD) {\n          if (!is_inuse(q))\n            used -= chunksize(q);\n          q = next_chunk(q);\n        }\n        s = s->next;\n      }\n    }\n    POSTACTION(m); /* drop lock */\n    fprintf(stderr, \"max system bytes = %10lu\\n\", (unsigned long)(maxfp));\n    fprintf(stderr, \"system bytes     = %10lu\\n\", (unsigned long)(fp));\n    fprintf(stderr, \"in use bytes     = %10lu\\n\", (unsigned long)(used));\n  }\n}\n#endif /* NO_MALLOC_STATS */\n\n/* ----------------------- Operations on smallbins ----------------------- */\n\n/*\n  Various forms of linking and unlinking are defined as macros.  Even\n  the ones for trees, which are very long but have very short typical\n  paths.  This is ugly but reduces reliance on inlining support of\n  compilers.\n*/\n\n/* Link a free chunk into a smallbin  */\n#define insert_small_chunk(M, P, S) {\\\n  bindex_t I  = small_index(S);\\\n  mchunkptr B = smallbin_at(M, I);\\\n  mchunkptr F = B;\\\n  assert(S >= MIN_CHUNK_SIZE);\\\n  if (!smallmap_is_marked(M, I))\\\n    mark_smallmap(M, I);\\\n  else if (RTCHECK(ok_address(M, B->fd.pload())))\\\n    F = B->fd;\\\n  else {\\\n    CORRUPTION_ERROR_ACTION(M);\\\n  }\\\n  B->fd = P;\\\n  F->bk = P;\\\n  P->fd = F;\\\n  P->bk = B;\\\n}\n\n/* Unlink a chunk from a smallbin  */\n#define unlink_small_chunk(M, P, S) {\\\n  mchunkptr F = P->fd;\\\n  mchunkptr B = P->bk;\\\n  bindex_t I = small_index(S);\\\n  assert(P != B);\\\n  assert(P != F);\\\n  assert(chunksize(P) == small_index2size(I));\\\n  if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \\\n    if (B == F) {\\\n      clear_smallmap(M, I);\\\n    }\\\n    else if (RTCHECK(B == smallbin_at(M,I) ||\\\n                     (ok_address(M, B) && B->fd == P))) {\\\n      F->bk = B;\\\n      B->fd = F;\\\n    }\\\n    else {\\\n      CORRUPTION_ERROR_ACTION(M);\\\n    }\\\n  }\\\n  else {\\\n    CORRUPTION_ERROR_ACTION(M);\\\n  }\\\n}\n\n/* Unlink the first chunk from a smallbin */\n#define unlink_first_small_chunk(M, B, P, I) {\\\n  mchunkptr F = P->fd;\\\n  assert(P != B);\\\n  assert(P != F);\\\n  assert(chunksize(P) == small_index2size(I));\\\n  if (B == F) {\\\n    clear_smallmap(M, I);\\\n  }\\\n  else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\\\n    F->bk = B;\\\n    B->fd = F;\\\n  }\\\n  else {\\\n    CORRUPTION_ERROR_ACTION(M);\\\n  }\\\n}\n\n/* Replace dv node, binning the old one */\n/* Used only when dvsize known to be small */\n#define replace_dv(M, P, S) {\\\n  size_t DVS = M->dvsize;\\\n  assert(is_small(DVS));\\\n  if (DVS != 0) {\\\n    mchunkptr DV = M->dv;\\\n    insert_small_chunk(M, DV, DVS);\\\n  }\\\n  M->dvsize = S;\\\n  M->dv = P;\\\n}\n\n/* ------------------------- Operations on trees ------------------------- */\n\n/* Insert chunk into tree */\n#define insert_large_chunk(M, X, S) {\\\n  persist<tbinptr>* H;\\\n  bindex_t I;\\\n  compute_tree_index(S, I);\\\n  H = treebin_at(M, I);\\\n  X->index = I;\\\n  X->child[0] = X->child[1] = 0;\\\n  if (!treemap_is_marked(M, I)) {\\\n    mark_treemap(M, I);\\\n    *H = X;\\\n    X->parent = (tchunkptr)H;\\\n    X->fd = X->bk = X;\\\n  }\\\n  else {\\\n    tchunkptr T = *H;\\\n    size_t K = S << leftshift_for_tree_index(I);\\\n    for (;;) {\\\n      if (chunksize(T) != S) {\\\n        persist<tchunkptr>* C = (persist<tchunkptr>*)&(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\\\n        K <<= 1;\\\n        if (*C != 0)\\\n          T = *C;\\\n        else if (RTCHECK(ok_address(M, C))) {\\\n          *C = X;\\\n          X->parent = T;\\\n          X->fd = X->bk = X;\\\n          break;\\\n        }\\\n        else {\\\n          CORRUPTION_ERROR_ACTION(M);\\\n          break;\\\n        }\\\n      }\\\n      else {\\\n        tchunkptr F = T->fd;\\\n        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\\\n          T->fd = F->bk = X;\\\n          X->fd = F;\\\n          X->bk = T;\\\n          X->parent = 0;\\\n          break;\\\n        }\\\n        else {\\\n          CORRUPTION_ERROR_ACTION(M);\\\n          break;\\\n        }\\\n      }\\\n    }\\\n  }\\\n}\n\n/*\n  Unlink steps:\n\n  1. If x is a chained node, unlink it from its same-sized fd/bk links\n     and choose its bk node as its replacement.\n  2. If x was the last node of its size, but not a leaf node, it must\n     be replaced with a leaf node (not merely one with an open left or\n     right), to make sure that lefts and rights of descendents\n     correspond properly to bit masks.  We use the rightmost descendent\n     of x.  We could use any other leaf, but this is easy to locate and\n     tends to counteract removal of leftmosts elsewhere, and so keeps\n     paths shorter than minimally guaranteed.  This doesn't loop much\n     because on average a node in a tree is near the bottom.\n  3. If x is the base of a chain (i.e., has parent links) relink\n     x's parent and children to x's replacement (or null if none).\n*/\n\n#define unlink_large_chunk(M, X) {\\\n  tchunkptr XP = X->parent;\\\n  tchunkptr R;\\\n  if (X->bk != X) {\\\n    tchunkptr F = X->fd;\\\n    R = X->bk;\\\n    if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\\\n      F->bk = R;\\\n      R->fd = F;\\\n    }\\\n    else {\\\n      CORRUPTION_ERROR_ACTION(M);\\\n    }\\\n  }\\\n  else {\\\n    persist<tchunkptr>* RP;\\\n    if (((R = *(RP = (persist<tchunkptr>*)&(X->child[1]))) != 0) ||\\\n        ((R = *(RP = (persist<tchunkptr>*)&(X->child[0]))) != 0)) {\\\n      persist<tchunkptr>* CP;\\\n      while ((*(CP = (persist<tchunkptr>*)&(R->child[1])) != 0) ||\\\n             (*(CP = (persist<tchunkptr>*)&(R->child[0])) != 0)) {\\\n        R = *(RP = CP);\\\n      }\\\n      if (RTCHECK(ok_address(M, RP)))\\\n        *RP = 0;\\\n      else {\\\n        CORRUPTION_ERROR_ACTION(M);\\\n      }\\\n    }\\\n  }\\\n  if (XP != 0) {\\\n    persist<tbinptr>* H = treebin_at(M, X->index);\\\n    if (X == *H) {\\\n      if ((*H = R) == 0) \\\n        clear_treemap(M, X->index);\\\n    }\\\n    else if (RTCHECK(ok_address(M, XP))) {\\\n      if (XP->child[0] == X) \\\n        XP->child[0] = R;\\\n      else \\\n        XP->child[1] = R;\\\n    }\\\n    else\\\n      CORRUPTION_ERROR_ACTION(M);\\\n    if (R != 0) {\\\n      if (RTCHECK(ok_address(M, R))) {\\\n        tchunkptr C0, C1;\\\n        R->parent = XP;\\\n        if ((C0 = X->child[0]) != 0) {\\\n          if (RTCHECK(ok_address(M, C0))) {\\\n            R->child[0] = C0;\\\n            C0->parent = R;\\\n          }\\\n          else\\\n            CORRUPTION_ERROR_ACTION(M);\\\n        }\\\n        if ((C1 = X->child[1]) != 0) {\\\n          if (RTCHECK(ok_address(M, C1))) {\\\n            R->child[1] = C1;\\\n            C1->parent = R;\\\n          }\\\n          else\\\n            CORRUPTION_ERROR_ACTION(M);\\\n        }\\\n      }\\\n      else\\\n        CORRUPTION_ERROR_ACTION(M);\\\n    }\\\n  }\\\n}\n\n/* Relays to large vs small bin operations */\n\n#define insert_chunk(M, P, S)\\\n  if (is_small(S)) insert_small_chunk(M, P, S)\\\n  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }\n\n#define unlink_chunk(M, P, S)\\\n  if (is_small(S)) unlink_small_chunk(M, P, S)\\\n  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }\n\n\n/* Relays to internal calls to malloc/free from realloc, memalign etc */\n\n#if ONLY_MSPACES\n#define internal_malloc(m, b) mspace_malloc(m, b)\n#define internal_free(m, mem) mspace_free(m,mem);\n#else /* ONLY_MSPACES */\n#if MSPACES\n#define internal_malloc(m, b)\\\n  ((m == gm)? dlmalloc(b) : mspace_malloc(m, b))\n#define internal_free(m, mem)\\\n   if (m == gm) dlfree(mem); else mspace_free(m,mem);\n#else /* MSPACES */\n#define internal_malloc(m, b) dlmalloc(b)\n#define internal_free(m, mem) dlfree(mem)\n#endif /* MSPACES */\n#endif /* ONLY_MSPACES */\n\n/* -----------------------  Direct-mmapping chunks ----------------------- */\n\n/*\n  Directly mmapped chunks are set up with an offset to the start of\n  the mmapped region stored in the prev_foot field of the chunk. This\n  allows reconstruction of the required argument to MUNMAP when freed,\n  and also allows adjustment of the returned chunk to meet alignment\n  requirements (especially in memalign).\n*/\n\n/* Malloc using mmap */\nstatic void* mmap_alloc(mstate m, size_t nb) {\n  size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);\n  if (m->footprint_limit.pload() != 0) {\n    size_t fp = m->footprint + mmsize;\n    if (fp <= m->footprint || fp > m->footprint_limit)\n      return 0;\n  }\n  if (mmsize > nb) {     /* Check for wrap around 0 */\n    char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));\n    if (mm != CMFAIL) {\n      size_t offset = align_offset(chunk2mem(mm));\n      size_t psize = mmsize - offset - MMAP_FOOT_PAD;\n      mchunkptr p = (mchunkptr)(mm + offset);\n      p->prev_foot = offset;\n      p->head = psize;\n      mark_inuse_foot(m, p, psize);\n      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;\n      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;\n\n      if (m->least_addr == 0 || mm < m->least_addr)\n        m->least_addr = mm;\n      if ((m->footprint += mmsize) > m->max_footprint)\n        m->max_footprint = m->footprint;\n      assert(is_aligned(chunk2mem(p)));\n      check_mmapped_chunk(m, p);\n      return chunk2mem(p);\n    }\n  }\n  return 0;\n}\n\n/* Realloc using mmap */\nstatic mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {\n  size_t oldsize = chunksize(oldp);\n  (void)flags; /* placate people compiling -Wunused */\n  if (is_small(nb)) /* Can't shrink mmap regions below small size */\n    return 0;\n  /* Keep old chunk if big enough but not too big */\n  if (oldsize >= nb + SIZE_T_SIZE &&\n      (oldsize - nb) <= (mparams.granularity << 1))\n    return oldp;\n  else {\n    size_t offset = oldp->prev_foot;\n    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;\n    size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);\n    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,\n                                  oldmmsize, newmmsize, flags);\n    if (cp != CMFAIL) {\n      mchunkptr newp = (mchunkptr)(cp + offset);\n      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;\n      newp->head = psize;\n      mark_inuse_foot(m, newp, psize);\n      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;\n      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;\n\n      if (cp < m->least_addr)\n        m->least_addr = cp;\n      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)\n        m->max_footprint = m->footprint;\n      check_mmapped_chunk(m, newp);\n      return newp;\n    }\n  }\n  return 0;\n}\n\n\n/* -------------------------- mspace management -------------------------- */\n\n/* Initialize top chunk and its size */\nstatic void init_top(mstate m, mchunkptr p, size_t psize) {\n  /* Ensure alignment */\n  size_t offset = align_offset(chunk2mem(p));\n  p = (mchunkptr)((char*)p + offset);\n  psize -= offset;\n\n  m->top = p;\n  m->topsize = psize;\n  p->head = psize | PINUSE_BIT;\n  /* set size of fake trailing chunk holding overhead space only once */\n  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;\n  m->trim_check = mparams.trim_threshold; /* reset on each update */\n}\n\n/* Initialize bins for a new mstate that is otherwise zeroed out */\nstatic void init_bins(mstate m) {\n  /* Establish circular links for smallbins */\n  bindex_t i;\n  for (i = 0; i < NSMALLBINS; ++i) {\n    sbinptr bin = smallbin_at(m,i);\n    bin->fd = bin->bk = bin;\n  }\n}\n\n#if PROCEED_ON_ERROR\n\n/* default corruption action */\nstatic void reset_on_error(mstate m) {\n  int i;\n  ++malloc_corruption_error_count;\n  /* Reinitialize fields to forget about all memory */\n  m->smallmap = m->treemap = 0;\n  m->dvsize = m->topsize = 0;\n  m->seg.base = 0;\n  m->seg.size = 0;\n  m->seg.next = 0;\n  m->top = m->dv = 0;\n  for (i = 0; i < NTREEBINS; ++i)\n    *treebin_at(m, i) = 0;\n  init_bins(m);\n}\n#endif /* PROCEED_ON_ERROR */\n\n/* Allocate chunk and prepend remainder with chunk in successor base. */\nstatic void* prepend_alloc(mstate m, char* newbase, char* oldbase,\n                           size_t nb) {\n  mchunkptr p = align_as_chunk(newbase);\n  mchunkptr oldfirst = align_as_chunk(oldbase);\n  size_t psize = (char*)oldfirst - (char*)p;\n  mchunkptr q = chunk_plus_offset(p, nb);\n  size_t qsize = psize - nb;\n  set_size_and_pinuse_of_inuse_chunk(m, p, nb);\n\n  assert((char*)oldfirst > (char*)q);\n  assert(pinuse(oldfirst));\n  assert(qsize >= MIN_CHUNK_SIZE);\n\n  /* consolidate remainder with first chunk of old base */\n  if (oldfirst == m->top) {\n    size_t tsize = m->topsize += qsize;\n    m->top = q;\n    q->head = tsize | PINUSE_BIT;\n    check_top_chunk(m, q);\n  }\n  else if (oldfirst == m->dv) {\n    size_t dsize = m->dvsize += qsize;\n    m->dv = q;\n    set_size_and_pinuse_of_free_chunk(q, dsize);\n  }\n  else {\n    if (!is_inuse(oldfirst)) {\n      size_t nsize = chunksize(oldfirst);\n      unlink_chunk(m, oldfirst, nsize);\n      oldfirst = chunk_plus_offset(oldfirst, nsize);\n      qsize += nsize;\n    }\n    set_free_with_pinuse(q, qsize, oldfirst);\n    insert_chunk(m, q, qsize);\n    check_free_chunk(m, q);\n  }\n\n  check_malloced_chunk(m, chunk2mem(p), nb);\n  return chunk2mem(p);\n}\n\n/* Add a segment to hold a new noncontiguous region */\nstatic void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {\n  /* Determine locations and sizes of segment, fenceposts, old top */\n  char* old_top = (char*)m->top.pload();\n  msegmentptr oldsp = segment_holding(m, old_top);\n  char* old_end = oldsp->base + oldsp->size;\n  size_t ssize = pad_request(sizeof(struct malloc_segment));\n  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);\n  size_t offset = align_offset(chunk2mem(rawsp));\n  char* asp = rawsp + offset;\n  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;\n  mchunkptr sp = (mchunkptr)csp;\n  msegmentptr ss = (msegmentptr)(chunk2mem(sp));\n  mchunkptr tnext = chunk_plus_offset(sp, ssize);\n  mchunkptr p = tnext;\n  int nfences = 0;\n\n  /* reset top to new space */\n  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);\n\n  /* Set up segment record */\n  assert(is_aligned(ss));\n  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);\n  *ss = m->seg; /* Push current record */\n  m->seg.base = tbase;\n  m->seg.size = tsize;\n  m->seg.sflags = mmapped;\n  m->seg.next = ss;\n\n  /* Insert trailing fenceposts */\n  for (;;) {\n    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);\n    p->head = FENCEPOST_HEAD;\n    ++nfences;\n    if ((char*)(&(nextp->head)) < old_end)\n      p = nextp;\n    else\n      break;\n  }\n  assert(nfences >= 2);\n\n  /* Insert the rest of old top into a bin as an ordinary free chunk */\n  if (csp != old_top) {\n    mchunkptr q = (mchunkptr)old_top;\n    size_t psize = csp - old_top;\n    mchunkptr tn = chunk_plus_offset(q, psize);\n    set_free_with_pinuse(q, psize, tn);\n    insert_chunk(m, q, psize);\n  }\n\n  check_top_chunk(m, m->top);\n}\n\n/* -------------------------- System allocation -------------------------- */\n\n/* Get memory from system using MORECORE or MMAP */\nstatic void* sys_alloc(mstate m, size_t nb) {\n  char* tbase = CMFAIL;\n  size_t tsize = 0;\n  flag_t mmap_flag = 0;\n  size_t asize; /* allocation size */\n\n  ensure_initialization();\n\n  /* Directly map large chunks, but only if already initialized */\n  if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize.pload() != 0) {\n    void* mem = mmap_alloc(m, nb);\n    if (mem != 0)\n      return mem;\n  }\n\n  asize = granularity_align(nb + SYS_ALLOC_PADDING);\n  if (asize <= nb)\n    return 0; /* wraparound */\n  if (m->footprint_limit.pload() != 0) {\n    size_t fp = m->footprint + asize;\n    if (fp <= m->footprint || fp > m->footprint_limit)\n      return 0;\n  }\n\n  /*\n    Try getting memory in any of three ways (in most-preferred to\n    least-preferred order):\n    1. A call to MORECORE that can normally contiguously extend memory.\n       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or\n       or main space is mmapped or a previous contiguous call failed)\n    2. A call to MMAP new space (disabled if not HAVE_MMAP).\n       Note that under the default settings, if MORECORE is unable to\n       fulfill a request, and HAVE_MMAP is true, then mmap is\n       used as a noncontiguous system allocator. This is a useful backup\n       strategy for systems with holes in address spaces -- in this case\n       sbrk cannot contiguously expand the heap, but mmap may be able to\n       find space.\n    3. A call to MORECORE that cannot usually contiguously extend memory.\n       (disabled if not HAVE_MORECORE)\n\n   In all cases, we need to request enough bytes from system to ensure\n   we can malloc nb bytes upon success, so pad with enough space for\n   top_foot, plus alignment-pad to make sure we don't lose bytes if\n   not on boundary, and round this up to a granularity unit.\n  */\n\n  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {\n    char* br = CMFAIL;\n    size_t ssize = asize; /* sbrk call size */\n    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top.pload());\n    ACQUIRE_MALLOC_GLOBAL_LOCK();\n\n    if (ss == 0) {  /* First time through or recovery */\n      char* base = (char*)CALL_MORECORE(0);\n      if (base != CMFAIL) {\n        size_t fp;\n        /* Adjust to end on a page boundary */\n        if (!is_page_aligned(base))\n          ssize += (page_align((size_t)base) - (size_t)base);\n        fp = m->footprint + ssize; /* recheck limits */\n        if (ssize > nb && ssize < HALF_MAX_SIZE_T &&\n            (m->footprint_limit.pload() == 0 ||\n             (fp > m->footprint && fp <= m->footprint_limit)) &&\n            (br = (char*)(CALL_MORECORE(ssize))) == base) {\n          tbase = base;\n          tsize = ssize;\n        }\n      }\n    }\n    else {\n      /* Subtract out existing available top space from MORECORE request. */\n      ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);\n      /* Use mem here only if it did continuously extend old space */\n      if (ssize < HALF_MAX_SIZE_T &&\n          (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {\n        tbase = br;\n        tsize = ssize;\n      }\n    }\n\n    if (tbase == CMFAIL) {    /* Cope with partial failure */\n      if (br != CMFAIL) {    /* Try to use/extend the space we did get */\n        if (ssize < HALF_MAX_SIZE_T &&\n            ssize < nb + SYS_ALLOC_PADDING) {\n          size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);\n          if (esize < HALF_MAX_SIZE_T) {\n            char* end = (char*)CALL_MORECORE(esize);\n            if (end != CMFAIL)\n              ssize += esize;\n            else {            /* Can't use; try to release */\n              (void) CALL_MORECORE(-ssize);\n              br = CMFAIL;\n            }\n          }\n        }\n      }\n      if (br != CMFAIL) {    /* Use the space we did get */\n        tbase = br;\n        tsize = ssize;\n      }\n      else\n        disable_contiguous(m); /* Don't try contiguous path in the future */\n    }\n\n    RELEASE_MALLOC_GLOBAL_LOCK();\n  }\n\n  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */\n    char* mp = (char*)(CALL_MMAP(asize));\n    if (mp != CMFAIL) {\n      tbase = mp;\n      tsize = asize;\n      mmap_flag = USE_MMAP_BIT;\n    }\n  }\n\n  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */\n    if (asize < HALF_MAX_SIZE_T) {\n      char* br = CMFAIL;\n      char* end = CMFAIL;\n      ACQUIRE_MALLOC_GLOBAL_LOCK();\n      br = (char*)(CALL_MORECORE(asize));\n      end = (char*)(CALL_MORECORE(0));\n      RELEASE_MALLOC_GLOBAL_LOCK();\n      if (br != CMFAIL && end != CMFAIL && br < end) {\n        size_t ssize = end - br;\n        if (ssize > nb + TOP_FOOT_SIZE) {\n          tbase = br;\n          tsize = ssize;\n        }\n      }\n    }\n  }\n\n  if (tbase != CMFAIL) {\n\n    if ((m->footprint += tsize) > m->max_footprint)\n      m->max_footprint = m->footprint;\n\n    if (!is_initialized(m)) { /* first-time initialization */\n      if (m->least_addr == 0 || tbase < m->least_addr)\n        m->least_addr = tbase;\n      m->seg.base = tbase;\n      m->seg.size = tsize;\n      m->seg.sflags = mmap_flag;\n      m->magic = mparams.magic;\n      m->release_checks = MAX_RELEASE_CHECK_RATE;\n      init_bins(m);\n#if !ONLY_MSPACES\n      if (is_global(m))\n        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);\n      else\n#endif\n      {\n        /* Offset top by embedded malloc_state */\n        mchunkptr mn = next_chunk(mem2chunk(m));\n        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);\n      }\n    }\n\n    else {\n      /* Try to merge with an existing segment */\n      msegmentptr sp = &m->seg;\n      /* Only consider most recent segment if traversal suppressed */\n      while (sp != 0 && tbase != sp->base + sp->size)\n        sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;\n      if (sp != 0 &&\n          !is_extern_segment(sp) &&\n          (sp->sflags & USE_MMAP_BIT) == mmap_flag &&\n          segment_holds(sp, m->top.pload())) { /* append */\n        sp->size += tsize;\n        init_top(m, m->top, m->topsize + tsize);\n      }\n      else {\n        if (tbase < m->least_addr)\n          m->least_addr = tbase;\n        sp = &m->seg;\n        while (sp != 0 && sp->base != tbase + tsize)\n          sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;\n        if (sp != 0 &&\n            !is_extern_segment(sp) &&\n            (sp->sflags & USE_MMAP_BIT) == mmap_flag) {\n          char* oldbase = sp->base;\n          sp->base = tbase;\n          sp->size += tsize;\n          return prepend_alloc(m, tbase, oldbase, nb);\n        }\n        else\n          add_segment(m, tbase, tsize, mmap_flag);\n      }\n    }\n\n    if (nb < m->topsize) { /* Allocate from new or extended top space */\n      size_t rsize = m->topsize -= nb;\n      mchunkptr p = m->top;\n      mchunkptr r = m->top = chunk_plus_offset(p, nb);\n      r->head = rsize | PINUSE_BIT;\n      set_size_and_pinuse_of_inuse_chunk(m, p, nb);\n      check_top_chunk(m, m->top);\n      check_malloced_chunk(m, chunk2mem(p), nb);\n      return chunk2mem(p);\n    }\n  }\n\n  MALLOC_FAILURE_ACTION;\n  return 0;\n}\n\n/* -----------------------  system deallocation -------------------------- */\n\n/* Unmap and unlink any mmapped segments that don't contain used chunks */\nstatic size_t release_unused_segments(mstate m) {\n  size_t released = 0;\n  int nsegs = 0;\n  msegmentptr pred = &m->seg;\n  msegmentptr sp = pred->next;\n  while (sp != 0) {\n    char* base = sp->base;\n    size_t size = sp->size;\n    msegmentptr next = sp->next;\n    ++nsegs;\n    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {\n      mchunkptr p = align_as_chunk(base);\n      size_t psize = chunksize(p);\n      /* Can unmap if first chunk holds entire segment and not pinned */\n      if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {\n        tchunkptr tp = (tchunkptr)p;\n        assert(segment_holds(sp, (char*)sp));\n        if (p == m->dv) {\n          m->dv = 0;\n          m->dvsize = 0;\n        }\n        else {\n          unlink_large_chunk(m, tp);\n        }\n        if (CALL_MUNMAP(base, size) == 0) {\n          released += size;\n          m->footprint -= size;\n          /* unlink obsoleted record */\n          sp = pred;\n          sp->next = next;\n        }\n        else { /* back out if cannot unmap */\n          insert_large_chunk(m, tp, psize);\n        }\n      }\n    }\n    if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */\n      break;\n    pred = sp;\n    sp = next;\n  }\n  /* Reset check counter */\n  m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)?\n                       (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE);\n  return released;\n}\n\nstatic int sys_trim(mstate m, size_t pad) {\n  size_t released = 0;\n  ensure_initialization();\n  if (pad < MAX_REQUEST && is_initialized(m)) {\n    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */\n\n    if (m->topsize > pad) {\n      /* Shrink top space in granularity-size units, keeping at least one */\n      size_t unit = mparams.granularity;\n      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -\n                      SIZE_T_ONE) * unit;\n      msegmentptr sp = segment_holding(m, (char*)m->top.pload());\n\n      if (!is_extern_segment(sp)) {\n        if (is_mmapped_segment(sp)) {\n          if (HAVE_MMAP &&\n              sp->size >= extra &&\n              !has_segment_link(m, sp)) { /* can't shrink if pinned */\n            size_t newsize = sp->size - extra;\n            (void)newsize; /* placate people compiling -Wunused-variable */\n            /* Prefer mremap, fall back to munmap */\n            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||\n                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {\n              released = extra;\n            }\n          }\n        }\n        else if (HAVE_MORECORE) {\n          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */\n            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;\n          ACQUIRE_MALLOC_GLOBAL_LOCK();\n          {\n            /* Make sure end of memory is where we last set it. */\n            char* old_br = (char*)(CALL_MORECORE(0));\n            if (old_br == sp->base + sp->size) {\n              char* rel_br = (char*)(CALL_MORECORE(-extra));\n              char* new_br = (char*)(CALL_MORECORE(0));\n              if (rel_br != CMFAIL && new_br < old_br)\n                released = old_br - new_br;\n            }\n          }\n          RELEASE_MALLOC_GLOBAL_LOCK();\n        }\n      }\n\n      if (released != 0) {\n        sp->size -= released;\n        m->footprint -= released;\n        init_top(m, m->top, m->topsize - released);\n        check_top_chunk(m, m->top);\n      }\n    }\n\n    /* Unmap any unused mmapped segments */\n    if (HAVE_MMAP)\n      released += release_unused_segments(m);\n\n    /* On failure, disable autotrim to avoid repeated failed future calls */\n    if (released == 0 && m->topsize > m->trim_check)\n      m->trim_check = MAX_SIZE_T;\n  }\n\n  return (released != 0)? 1 : 0;\n}\n\n/* Consolidate and bin a chunk. Differs from exported versions\n   of free mainly in that the chunk need not be marked as inuse.\n*/\nstatic void dispose_chunk(mstate m, mchunkptr p, size_t psize) {\n  mchunkptr next = chunk_plus_offset(p, psize);\n  if (!pinuse(p)) {\n    mchunkptr prev;\n    size_t prevsize = p->prev_foot;\n    if (is_mmapped(p)) {\n      psize += prevsize + MMAP_FOOT_PAD;\n      if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)\n        m->footprint -= psize;\n      return;\n    }\n    prev = chunk_minus_offset(p, prevsize);\n    psize += prevsize;\n    p = prev;\n    if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */\n      if (p != m->dv) {\n        unlink_chunk(m, p, prevsize);\n      }\n      else if ((next->head & INUSE_BITS) == INUSE_BITS) {\n        m->dvsize = psize;\n        set_free_with_pinuse(p, psize, next);\n        return;\n      }\n    }\n    else {\n      CORRUPTION_ERROR_ACTION(m);\n      return;\n    }\n  }\n  if (RTCHECK(ok_address(m, next))) {\n    if (!cinuse(next)) {  /* consolidate forward */\n      if (next == m->top) {\n        size_t tsize = m->topsize += psize;\n        m->top = p;\n        p->head = tsize | PINUSE_BIT;\n        if (p == m->dv) {\n          m->dv = 0;\n          m->dvsize = 0;\n        }\n        return;\n      }\n      else if (next == m->dv) {\n        size_t dsize = m->dvsize += psize;\n        m->dv = p;\n        set_size_and_pinuse_of_free_chunk(p, dsize);\n        return;\n      }\n      else {\n        size_t nsize = chunksize(next);\n        psize += nsize;\n        unlink_chunk(m, next, nsize);\n        set_size_and_pinuse_of_free_chunk(p, psize);\n        if (p == m->dv) {\n          m->dvsize = psize;\n          return;\n        }\n      }\n    }\n    else {\n      set_free_with_pinuse(p, psize, next);\n    }\n    insert_chunk(m, p, psize);\n  }\n  else {\n    CORRUPTION_ERROR_ACTION(m);\n  }\n}\n\n/* ---------------------------- malloc --------------------------- */\n\n/* allocate a large request from the best fitting chunk in a treebin */\nstatic void* tmalloc_large(mstate m, size_t nb) {\n  tchunkptr v = 0;\n  size_t rsize = -nb; /* Unsigned negation */\n  tchunkptr t;\n  bindex_t idx;\n  compute_tree_index(nb, idx);\n  if ((t = *treebin_at(m, idx)) != 0) {\n    /* Traverse tree for this bin looking for node with size == nb */\n    size_t sizebits = nb << leftshift_for_tree_index(idx);\n    tchunkptr rst = 0;  /* The deepest untaken right subtree */\n    for (;;) {\n      tchunkptr rt;\n      size_t trem = chunksize(t) - nb;\n      if (trem < rsize) {\n        v = t;\n        if ((rsize = trem) == 0)\n          break;\n      }\n      rt = t->child[1];\n      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];\n      if (rt != 0 && rt != t)\n        rst = rt;\n      if (t == 0) {\n        t = rst; /* set t to least subtree holding sizes > nb */\n        break;\n      }\n      sizebits <<= 1;\n    }\n  }\n  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */\n    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;\n    if (leftbits != 0) {\n      bindex_t i;\n      binmap_t leastbit = least_bit(leftbits);\n      compute_bit2idx(leastbit, i);\n      t = *treebin_at(m, i);\n    }\n  }\n\n  while (t != 0) { /* find smallest of tree or subtree */\n    size_t trem = chunksize(t) - nb;\n    if (trem < rsize) {\n      rsize = trem;\n      v = t;\n    }\n    t = leftmost_child(t);\n  }\n\n  /*  If dv is a better fit, return 0 so malloc will use it */\n  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {\n    if (RTCHECK(ok_address(m, v))) { /* split */\n      mchunkptr r = chunk_plus_offset(v, nb);\n      assert(chunksize(v) == rsize + nb);\n      if (RTCHECK(ok_next(v, r))) {\n        unlink_large_chunk(m, v);\n        if (rsize < MIN_CHUNK_SIZE)\n          set_inuse_and_pinuse(m, v, (rsize + nb));\n        else {\n          set_size_and_pinuse_of_inuse_chunk(m, v, nb);\n          set_size_and_pinuse_of_free_chunk(r, rsize);\n          insert_chunk(m, r, rsize);\n        }\n        return chunk2mem(v);\n      }\n    }\n    CORRUPTION_ERROR_ACTION(m);\n  }\n  return 0;\n}\n\n/* allocate a small request from the best fitting chunk in a treebin */\nstatic void* tmalloc_small(mstate m, size_t nb) {\n  tchunkptr t, v;\n  size_t rsize;\n  bindex_t i;\n  binmap_t leastbit = least_bit(m->treemap);\n  compute_bit2idx(leastbit, i);\n  v = t = *treebin_at(m, i);\n  rsize = chunksize(t) - nb;\n\n  while ((t = leftmost_child(t)) != 0) {\n    size_t trem = chunksize(t) - nb;\n    if (trem < rsize) {\n      rsize = trem;\n      v = t;\n    }\n  }\n\n  if (RTCHECK(ok_address(m, v))) {\n    mchunkptr r = chunk_plus_offset(v, nb);\n    assert(chunksize(v) == rsize + nb);\n    if (RTCHECK(ok_next(v, r))) {\n      unlink_large_chunk(m, v);\n      if (rsize < MIN_CHUNK_SIZE)\n        set_inuse_and_pinuse(m, v, (rsize + nb));\n      else {\n        set_size_and_pinuse_of_inuse_chunk(m, v, nb);\n        set_size_and_pinuse_of_free_chunk(r, rsize);\n        replace_dv(m, r, rsize);\n      }\n      return chunk2mem(v);\n    }\n  }\n\n  CORRUPTION_ERROR_ACTION(m);\n  return 0;\n}\n\n#if !ONLY_MSPACES\n\nvoid* dlmalloc(size_t bytes) {\n  /*\n     Basic algorithm:\n     If a small request (< 256 bytes minus per-chunk overhead):\n       1. If one exists, use a remainderless chunk in associated smallbin.\n          (Remainderless means that there are too few excess bytes to\n          represent as a chunk.)\n       2. If it is big enough, use the dv chunk, which is normally the\n          chunk adjacent to the one used for the most recent small request.\n       3. If one exists, split the smallest available chunk in a bin,\n          saving remainder in dv.\n       4. If it is big enough, use the top chunk.\n       5. If available, get memory from system and use it\n     Otherwise, for a large request:\n       1. Find the smallest available binned chunk that fits, and use it\n          if it is better fitting than dv chunk, splitting if necessary.\n       2. If better fitting than any binned chunk, use the dv chunk.\n       3. If it is big enough, use the top chunk.\n       4. If request size >= mmap threshold, try to directly mmap this chunk.\n       5. If available, get memory from system and use it\n\n     The ugly goto's here ensure that postaction occurs along all paths.\n  */\n\n#if USE_LOCKS\n  ensure_initialization(); /* initialize in sys_alloc if not using locks */\n#endif\n\n  if (!PREACTION(gm)) {\n    void* mem;\n    size_t nb;\n    if (bytes <= MAX_SMALL_REQUEST) {\n      bindex_t idx;\n      binmap_t smallbits;\n      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);\n      idx = small_index(nb);\n      smallbits = gm->smallmap >> idx;\n\n      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */\n        mchunkptr b, p;\n        idx += ~smallbits & 1;       /* Uses next bin if idx empty */\n        b = smallbin_at(gm, idx);\n        p = b->fd;\n        assert(chunksize(p) == small_index2size(idx));\n        unlink_first_small_chunk(gm, b, p, idx);\n        set_inuse_and_pinuse(gm, p, small_index2size(idx));\n        mem = chunk2mem(p);\n        check_malloced_chunk(gm, mem, nb);\n        goto postaction;\n      }\n\n      else if (nb > gm->dvsize) {\n        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */\n          mchunkptr b, p, r;\n          size_t rsize;\n          bindex_t i;\n          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));\n          binmap_t leastbit = least_bit(leftbits);\n          compute_bit2idx(leastbit, i);\n          b = smallbin_at(gm, i);\n          p = b->fd;\n          assert(chunksize(p) == small_index2size(i));\n          unlink_first_small_chunk(gm, b, p, i);\n          rsize = small_index2size(i) - nb;\n          /* Fit here cannot be remainderless if 4byte sizes */\n          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)\n            set_inuse_and_pinuse(gm, p, small_index2size(i));\n          else {\n            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);\n            r = chunk_plus_offset(p, nb);\n            set_size_and_pinuse_of_free_chunk(r, rsize);\n            replace_dv(gm, r, rsize);\n          }\n          mem = chunk2mem(p);\n          check_malloced_chunk(gm, mem, nb);\n          goto postaction;\n        }\n\n        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {\n          check_malloced_chunk(gm, mem, nb);\n          goto postaction;\n        }\n      }\n    }\n    else if (bytes >= MAX_REQUEST)\n      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */\n    else {\n      nb = pad_request(bytes);\n      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {\n        check_malloced_chunk(gm, mem, nb);\n        goto postaction;\n      }\n    }\n\n    if (nb <= gm->dvsize) {\n      size_t rsize = gm->dvsize - nb;\n      mchunkptr p = gm->dv;\n      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */\n        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);\n        gm->dvsize = rsize;\n        set_size_and_pinuse_of_free_chunk(r, rsize);\n        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);\n      }\n      else { /* exhaust dv */\n        size_t dvs = gm->dvsize;\n        gm->dvsize = 0;\n        gm->dv = 0;\n        set_inuse_and_pinuse(gm, p, dvs);\n      }\n      mem = chunk2mem(p);\n      check_malloced_chunk(gm, mem, nb);\n      goto postaction;\n    }\n\n    else if (nb < gm->topsize) { /* Split top */\n      size_t rsize = gm->topsize -= nb;\n      mchunkptr p = gm->top;\n      mchunkptr r = gm->top = chunk_plus_offset(p, nb);\n      r->head = rsize | PINUSE_BIT;\n      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);\n      mem = chunk2mem(p);\n      check_top_chunk(gm, gm->top);\n      check_malloced_chunk(gm, mem, nb);\n      goto postaction;\n    }\n\n    mem = sys_alloc(gm, nb);\n\n  postaction:\n    POSTACTION(gm);\n    return mem;\n  }\n\n  return 0;\n}\n\n/* ---------------------------- free --------------------------- */\n\nvoid dlfree(void* mem) {\n  /*\n     Consolidate freed chunks with preceeding or succeeding bordering\n     free chunks, if they exist, and then place in a bin.  Intermixed\n     with special cases for top, dv, mmapped chunks, and usage errors.\n  */\n\n  if (mem != 0) {\n    mchunkptr p  = mem2chunk(mem);\n#if FOOTERS\n    mstate fm = get_mstate_for(p);\n    if (!ok_magic(fm)) {\n      USAGE_ERROR_ACTION(fm, p);\n      return;\n    }\n#else /* FOOTERS */\n#define fm gm\n#endif /* FOOTERS */\n    if (!PREACTION(fm)) {\n      check_inuse_chunk(fm, p);\n      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {\n        size_t psize = chunksize(p);\n        mchunkptr next = chunk_plus_offset(p, psize);\n        if (!pinuse(p)) {\n          size_t prevsize = p->prev_foot;\n          if (is_mmapped(p)) {\n            psize += prevsize + MMAP_FOOT_PAD;\n            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)\n              fm->footprint -= psize;\n            goto postaction;\n          }\n          else {\n            mchunkptr prev = chunk_minus_offset(p, prevsize);\n            psize += prevsize;\n            p = prev;\n            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */\n              if (p != fm->dv) {\n                unlink_chunk(fm, p, prevsize);\n              }\n              else if ((next->head & INUSE_BITS) == INUSE_BITS) {\n                fm->dvsize = psize;\n                set_free_with_pinuse(p, psize, next);\n                goto postaction;\n              }\n            }\n            else\n              goto erroraction;\n          }\n        }\n\n        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {\n          if (!cinuse(next)) {  /* consolidate forward */\n            if (next == fm->top) {\n              size_t tsize = fm->topsize += psize;\n              fm->top = p;\n              p->head = tsize | PINUSE_BIT;\n              if (p == fm->dv) {\n                fm->dv = 0;\n                fm->dvsize = 0;\n              }\n              if (should_trim(fm, tsize))\n                sys_trim(fm, 0);\n              goto postaction;\n            }\n            else if (next == fm->dv) {\n              size_t dsize = fm->dvsize += psize;\n              fm->dv = p;\n              set_size_and_pinuse_of_free_chunk(p, dsize);\n              goto postaction;\n            }\n            else {\n              size_t nsize = chunksize(next);\n              psize += nsize;\n              unlink_chunk(fm, next, nsize);\n              set_size_and_pinuse_of_free_chunk(p, psize);\n              if (p == fm->dv) {\n                fm->dvsize = psize;\n                goto postaction;\n              }\n            }\n          }\n          else\n            set_free_with_pinuse(p, psize, next);\n\n          if (is_small(psize)) {\n            insert_small_chunk(fm, p, psize);\n            check_free_chunk(fm, p);\n          }\n          else {\n            tchunkptr tp = (tchunkptr)p;\n            insert_large_chunk(fm, tp, psize);\n            check_free_chunk(fm, p);\n            if (--fm->release_checks == 0)\n              release_unused_segments(fm);\n          }\n          goto postaction;\n        }\n      }\n    erroraction:\n      USAGE_ERROR_ACTION(fm, p);\n    postaction:\n      POSTACTION(fm);\n    }\n  }\n#if !FOOTERS\n#undef fm\n#endif /* FOOTERS */\n}\n\nvoid* dlcalloc(size_t n_elements, size_t elem_size) {\n  void* mem;\n  size_t req = 0;\n  if (n_elements != 0) {\n    req = n_elements * elem_size;\n    if (((n_elements | elem_size) & ~(size_t)0xffff) &&\n        (req / n_elements != elem_size))\n      req = MAX_SIZE_T; /* force downstream failure on overflow */\n  }\n  mem = dlmalloc(req);\n  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))\n    memset(mem, 0, req);\n  return mem;\n}\n\n#endif /* !ONLY_MSPACES */\n\n/* ------------ Internal support for realloc, memalign, etc -------------- */\n\n/* Try to realloc; only in-place unless can_move true */\nstatic mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,\n                                   int can_move) {\n  mchunkptr newp = 0;\n  size_t oldsize = chunksize(p);\n  mchunkptr next = chunk_plus_offset(p, oldsize);\n  if (RTCHECK(ok_address(m, p) && ok_inuse(p) &&\n              ok_next(p, next) && ok_pinuse(next))) {\n    if (is_mmapped(p)) {\n      newp = mmap_resize(m, p, nb, can_move);\n    }\n    else if (oldsize >= nb) {             /* already big enough */\n      size_t rsize = oldsize - nb;\n      if (rsize >= MIN_CHUNK_SIZE) {      /* split off remainder */\n        mchunkptr r = chunk_plus_offset(p, nb);\n        set_inuse(m, p, nb);\n        set_inuse(m, r, rsize);\n        dispose_chunk(m, r, rsize);\n      }\n      newp = p;\n    }\n    else if (next == m->top) {  /* extend into top */\n      if (oldsize + m->topsize > nb) {\n        size_t newsize = oldsize + m->topsize;\n        size_t newtopsize = newsize - nb;\n        mchunkptr newtop = chunk_plus_offset(p, nb);\n        set_inuse(m, p, nb);\n        newtop->head = newtopsize |PINUSE_BIT;\n        m->top = newtop;\n        m->topsize = newtopsize;\n        newp = p;\n      }\n    }\n    else if (next == m->dv) { /* extend into dv */\n      size_t dvs = m->dvsize;\n      if (oldsize + dvs >= nb) {\n        size_t dsize = oldsize + dvs - nb;\n        if (dsize >= MIN_CHUNK_SIZE) {\n          mchunkptr r = chunk_plus_offset(p, nb);\n          mchunkptr n = chunk_plus_offset(r, dsize);\n          set_inuse(m, p, nb);\n          set_size_and_pinuse_of_free_chunk(r, dsize);\n          clear_pinuse(n);\n          m->dvsize = dsize;\n          m->dv = r;\n        }\n        else { /* exhaust dv */\n          size_t newsize = oldsize + dvs;\n          set_inuse(m, p, newsize);\n          m->dvsize = 0;\n          m->dv = 0;\n        }\n        newp = p;\n      }\n    }\n    else if (!cinuse(next)) { /* extend into next free chunk */\n      size_t nextsize = chunksize(next);\n      if (oldsize + nextsize >= nb) {\n        size_t rsize = oldsize + nextsize - nb;\n        unlink_chunk(m, next, nextsize);\n        if (rsize < MIN_CHUNK_SIZE) {\n          size_t newsize = oldsize + nextsize;\n          set_inuse(m, p, newsize);\n        }\n        else {\n          mchunkptr r = chunk_plus_offset(p, nb);\n          set_inuse(m, p, nb);\n          set_inuse(m, r, rsize);\n          dispose_chunk(m, r, rsize);\n        }\n        newp = p;\n      }\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(m, chunk2mem(p));\n  }\n  return newp;\n}\n\nstatic void* internal_memalign(mstate m, size_t alignment, size_t bytes) {\n  void* mem = 0;\n  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */\n    alignment = MIN_CHUNK_SIZE;\n  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */\n    size_t a = MALLOC_ALIGNMENT << 1;\n    while (a < alignment) a <<= 1;\n    alignment = a;\n  }\n  if (bytes >= MAX_REQUEST - alignment) {\n    if (m != 0)  { /* Test isn't needed but avoids compiler warning */\n      MALLOC_FAILURE_ACTION;\n    }\n  }\n  else {\n    size_t nb = request2size(bytes);\n    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;\n    mem = internal_malloc(m, req);\n    if (mem != 0) {\n      mchunkptr p = mem2chunk(mem);\n      if (PREACTION(m))\n        return 0;\n      if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */\n        /*\n          Find an aligned spot inside chunk.  Since we need to give\n          back leading space in a chunk of at least MIN_CHUNK_SIZE, if\n          the first calculation places us at a spot with less than\n          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.\n          We've allocated enough total room so that this is always\n          possible.\n        */\n        char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment -\n                                                       SIZE_T_ONE)) &\n                                             -alignment));\n        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?\n          br : br+alignment;\n        mchunkptr newp = (mchunkptr)pos;\n        size_t leadsize = pos - (char*)(p);\n        size_t newsize = chunksize(p) - leadsize;\n\n        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */\n          newp->prev_foot = p->prev_foot + leadsize;\n          newp->head = newsize;\n        }\n        else { /* Otherwise, give back leader, use the rest */\n          set_inuse(m, newp, newsize);\n          set_inuse(m, p, leadsize);\n          dispose_chunk(m, p, leadsize);\n        }\n        p = newp;\n      }\n\n      /* Give back spare room at the end */\n      if (!is_mmapped(p)) {\n        size_t size = chunksize(p);\n        if (size > nb + MIN_CHUNK_SIZE) {\n          size_t remainder_size = size - nb;\n          mchunkptr remainder = chunk_plus_offset(p, nb);\n          set_inuse(m, p, nb);\n          set_inuse(m, remainder, remainder_size);\n          dispose_chunk(m, remainder, remainder_size);\n        }\n      }\n\n      mem = chunk2mem(p);\n      assert (chunksize(p) >= nb);\n      assert(((size_t)mem & (alignment - 1)) == 0);\n      check_inuse_chunk(m, p);\n      POSTACTION(m);\n    }\n  }\n  return mem;\n}\n\n/*\n  Common support for independent_X routines, handling\n    all of the combinations that can result.\n  The opts arg has:\n    bit 0 set if all elements are same size (using sizes[0])\n    bit 1 set if elements should be zeroed\n*/\nstatic void** ialloc(mstate m,\n                     size_t n_elements,\n                     size_t* sizes,\n                     int opts,\n                     void* chunks[]) {\n\n  size_t    element_size;   /* chunksize of each element, if all same */\n  size_t    contents_size;  /* total size of elements */\n  size_t    array_size;     /* request size of pointer array */\n  void*     mem;            /* malloced aggregate space */\n  mchunkptr p;              /* corresponding chunk */\n  size_t    remainder_size; /* remaining bytes while splitting */\n  void**    marray;         /* either \"chunks\" or malloced ptr array */\n  mchunkptr array_chunk;    /* chunk for malloced ptr array */\n  flag_t    was_enabled;    /* to disable mmap */\n  size_t    size;\n  size_t    i;\n\n  ensure_initialization();\n  /* compute array length, if needed */\n  if (chunks != 0) {\n    if (n_elements == 0)\n      return chunks; /* nothing to do */\n    marray = chunks;\n    array_size = 0;\n  }\n  else {\n    /* if empty req, must still return chunk representing empty array */\n    if (n_elements == 0)\n      return (void**)internal_malloc(m, 0);\n    marray = 0;\n    array_size = request2size(n_elements * (sizeof(void*)));\n  }\n\n  /* compute total element size */\n  if (opts & 0x1) { /* all-same-size */\n    element_size = request2size(*sizes);\n    contents_size = n_elements * element_size;\n  }\n  else { /* add up all the sizes */\n    element_size = 0;\n    contents_size = 0;\n    for (i = 0; i != n_elements; ++i)\n      contents_size += request2size(sizes[i]);\n  }\n\n  size = contents_size + array_size;\n\n  /*\n     Allocate the aggregate chunk.  First disable direct-mmapping so\n     malloc won't use it, since we would not be able to later\n     free/realloc space internal to a segregated mmap region.\n  */\n  was_enabled = use_mmap(m);\n  disable_mmap(m);\n  mem = internal_malloc(m, size - CHUNK_OVERHEAD);\n  if (was_enabled)\n    enable_mmap(m);\n  if (mem == 0)\n    return 0;\n\n  if (PREACTION(m)) return 0;\n  p = mem2chunk(mem);\n  remainder_size = chunksize(p);\n\n  assert(!is_mmapped(p));\n\n  if (opts & 0x2) {       /* optionally clear the elements */\n    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);\n  }\n\n  /* If not provided, allocate the pointer array as final part of chunk */\n  if (marray == 0) {\n    size_t  array_chunk_size;\n    array_chunk = chunk_plus_offset(p, contents_size);\n    array_chunk_size = remainder_size - contents_size;\n    marray = (void**) (chunk2mem(array_chunk));\n    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);\n    remainder_size = contents_size;\n  }\n\n  /* split out elements */\n  for (i = 0; ; ++i) {\n    marray[i] = chunk2mem(p);\n    if (i != n_elements-1) {\n      if (element_size != 0)\n        size = element_size;\n      else\n        size = request2size(sizes[i]);\n      remainder_size -= size;\n      set_size_and_pinuse_of_inuse_chunk(m, p, size);\n      p = chunk_plus_offset(p, size);\n    }\n    else { /* the final element absorbs any overallocation slop */\n      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);\n      break;\n    }\n  }\n\n#if DEBUG\n  if (marray != chunks) {\n    /* final element must have exactly exhausted chunk */\n    if (element_size != 0) {\n      assert(remainder_size == element_size);\n    }\n    else {\n      assert(remainder_size == request2size(sizes[i]));\n    }\n    check_inuse_chunk(m, mem2chunk(marray));\n  }\n  for (i = 0; i != n_elements; ++i)\n    check_inuse_chunk(m, mem2chunk(marray[i]));\n\n#endif /* DEBUG */\n\n  POSTACTION(m);\n  return marray;\n}\n\n/* Try to free all pointers in the given array.\n   Note: this could be made faster, by delaying consolidation,\n   at the price of disabling some user integrity checks, We\n   still optimize some consolidations by combining adjacent\n   chunks before freeing, which will occur often if allocated\n   with ialloc or the array is sorted.\n*/\nstatic size_t internal_bulk_free(mstate m, void* array[], size_t nelem) {\n  size_t unfreed = 0;\n  if (!PREACTION(m)) {\n    persist<void*>* a;\n    persist<void*>* fence = (persist<void*>*)&(array[nelem]);\n    for (a = (persist<void*>*)array; a != fence; ++a) {\n      void* mem = *a;\n      if (mem != 0) {\n        mchunkptr p = mem2chunk(mem);\n        size_t psize = chunksize(p);\n#if FOOTERS\n        if (get_mstate_for(p) != m) {\n          ++unfreed;\n          continue;\n        }\n#endif\n        check_inuse_chunk(m, p);\n        *a = 0;\n        if (RTCHECK(ok_address(m, p) && ok_inuse(p))) {\n          persist<void *>* b = a + 1; /* try to merge with next chunk */\n          mchunkptr next = next_chunk(p);\n          if (b != fence && *b == chunk2mem(next)) {\n            size_t newsize = chunksize(next) + psize;\n            set_inuse(m, p, newsize);\n            *b = chunk2mem(p);\n          }\n          else\n            dispose_chunk(m, p, psize);\n        }\n        else {\n          CORRUPTION_ERROR_ACTION(m);\n          break;\n        }\n      }\n    }\n    if (should_trim(m, m->topsize))\n      sys_trim(m, 0);\n    POSTACTION(m);\n  }\n  return unfreed;\n}\n\n/* Traversal */\n#if MALLOC_INSPECT_ALL\nstatic void internal_inspect_all(mstate m,\n                                 void(*handler)(void *start,\n                                                void *end,\n                                                size_t used_bytes,\n                                                void* callback_arg),\n                                 void* arg) {\n  if (is_initialized(m)) {\n    mchunkptr top = m->top;\n    msegmentptr s;\n    for (s = &m->seg; s != 0; s = s->next) {\n      mchunkptr q = align_as_chunk(s->base);\n      while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) {\n        mchunkptr next = next_chunk(q);\n        size_t sz = chunksize(q);\n        size_t used;\n        void* start;\n        if (is_inuse(q)) {\n          used = sz - CHUNK_OVERHEAD; /* must not be mmapped */\n          start = chunk2mem(q);\n        }\n        else {\n          used = 0;\n          if (is_small(sz)) {     /* offset by possible bookkeeping */\n            start = (void*)((char*)q + sizeof(struct malloc_chunk));\n          }\n          else {\n            start = (void*)((char*)q + sizeof(struct malloc_tree_chunk));\n          }\n        }\n        if (start < (void*)next)  /* skip if all space is bookkeeping */\n          handler(start, next, used, arg);\n        if (q == top)\n          break;\n        q = next;\n      }\n    }\n  }\n}\n#endif /* MALLOC_INSPECT_ALL */\n\n/* ------------------ Exported realloc, memalign, etc -------------------- */\n\n#if !ONLY_MSPACES\n\nvoid* dlrealloc(void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem == 0) {\n    mem = dlmalloc(bytes);\n  }\n  else if (bytes >= MAX_REQUEST) {\n    MALLOC_FAILURE_ACTION;\n  }\n#ifdef REALLOC_ZERO_BYTES_FREES\n  else if (bytes == 0) {\n    dlfree(oldmem);\n  }\n#endif /* REALLOC_ZERO_BYTES_FREES */\n  else {\n    size_t nb = request2size(bytes);\n    mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n    mstate m = gm;\n#else /* FOOTERS */\n    mstate m = get_mstate_for(oldp);\n    if (!ok_magic(m)) {\n      USAGE_ERROR_ACTION(m, oldmem);\n      return 0;\n    }\n#endif /* FOOTERS */\n    if (!PREACTION(m)) {\n      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);\n      POSTACTION(m);\n      if (newp != 0) {\n        check_inuse_chunk(m, newp);\n        mem = chunk2mem(newp);\n      }\n      else {\n        mem = internal_malloc(m, bytes);\n        if (mem != 0) {\n          size_t oc = chunksize(oldp) - overhead_for(oldp);\n          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);\n          internal_free(m, oldmem);\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* dlrealloc_in_place(void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem != 0) {\n    if (bytes >= MAX_REQUEST) {\n      MALLOC_FAILURE_ACTION;\n    }\n    else {\n      size_t nb = request2size(bytes);\n      mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n      mstate m = gm;\n#else /* FOOTERS */\n      mstate m = get_mstate_for(oldp);\n      if (!ok_magic(m)) {\n        USAGE_ERROR_ACTION(m, oldmem);\n        return 0;\n      }\n#endif /* FOOTERS */\n      if (!PREACTION(m)) {\n        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);\n        POSTACTION(m);\n        if (newp == oldp) {\n          check_inuse_chunk(m, newp);\n          mem = oldmem;\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* dlmemalign(size_t alignment, size_t bytes) {\n  if (alignment <= MALLOC_ALIGNMENT) {\n    return dlmalloc(bytes);\n  }\n  return internal_memalign(gm, alignment, bytes);\n}\n\nint dlposix_memalign(void** pp, size_t alignment, size_t bytes) {\n  void* mem = 0;\n  if (alignment == MALLOC_ALIGNMENT)\n    mem = dlmalloc(bytes);\n  else {\n    size_t d = alignment / sizeof(void*);\n    size_t r = alignment % sizeof(void*);\n    if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0)\n      return EINVAL;\n    else if (bytes <= MAX_REQUEST - alignment) {\n      if (alignment <  MIN_CHUNK_SIZE)\n        alignment = MIN_CHUNK_SIZE;\n      mem = internal_memalign(gm, alignment, bytes);\n    }\n  }\n  if (mem == 0)\n    return ENOMEM;\n  else {\n    *pp = mem;\n    return 0;\n  }\n}\n\nvoid* dlvalloc(size_t bytes) {\n  size_t pagesz;\n  ensure_initialization();\n  pagesz = mparams.page_size;\n  return dlmemalign(pagesz, bytes);\n}\n\nvoid* dlpvalloc(size_t bytes) {\n  size_t pagesz;\n  ensure_initialization();\n  pagesz = mparams.page_size;\n  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));\n}\n\nvoid** dlindependent_calloc(size_t n_elements, size_t elem_size,\n                            void* chunks[]) {\n  size_t sz = elem_size; /* serves as 1-element array */\n  return ialloc(gm, n_elements, &sz, 3, chunks);\n}\n\nvoid** dlindependent_comalloc(size_t n_elements, size_t sizes[],\n                              void* chunks[]) {\n  return ialloc(gm, n_elements, sizes, 0, chunks);\n}\n\nsize_t dlbulk_free(void* array[], size_t nelem) {\n  return internal_bulk_free(gm, array, nelem);\n}\n\n#if MALLOC_INSPECT_ALL\nvoid dlmalloc_inspect_all(void(*handler)(void *start,\n                                         void *end,\n                                         size_t used_bytes,\n                                         void* callback_arg),\n                          void* arg) {\n  ensure_initialization();\n  if (!PREACTION(gm)) {\n    internal_inspect_all(gm, handler, arg);\n    POSTACTION(gm);\n  }\n}\n#endif /* MALLOC_INSPECT_ALL */\n\nint dlmalloc_trim(size_t pad) {\n  int result = 0;\n  ensure_initialization();\n  if (!PREACTION(gm)) {\n    result = sys_trim(gm, pad);\n    POSTACTION(gm);\n  }\n  return result;\n}\n\nsize_t dlmalloc_footprint(void) {\n  return gm->footprint;\n}\n\nsize_t dlmalloc_max_footprint(void) {\n  return gm->max_footprint;\n}\n\nsize_t dlmalloc_footprint_limit(void) {\n  size_t maf = gm->footprint_limit;\n  return maf == 0 ? MAX_SIZE_T : maf;\n}\n\nsize_t dlmalloc_set_footprint_limit(size_t bytes) {\n  size_t result;  /* invert sense of 0 */\n  if (bytes == 0)\n    result = granularity_align(1); /* Use minimal size */\n  if (bytes == MAX_SIZE_T)\n    result = 0;                    /* disable */\n  else\n    result = granularity_align(bytes);\n  return gm->footprint_limit = result;\n}\n\n#if !NO_MALLINFO\nstruct mallinfo dlmallinfo(void) {\n  return internal_mallinfo(gm);\n}\n#endif /* NO_MALLINFO */\n\n#if !NO_MALLOC_STATS\nvoid dlmalloc_stats() {\n  internal_malloc_stats(gm);\n}\n#endif /* NO_MALLOC_STATS */\n\nint dlmallopt(int param_number, int value) {\n  return change_mparam(param_number, value);\n}\n\nsize_t dlmalloc_usable_size(void* mem) {\n  if (mem != 0) {\n    mchunkptr p = mem2chunk(mem);\n    if (is_inuse(p))\n      return chunksize(p) - overhead_for(p);\n  }\n  return 0;\n}\n\n#endif /* !ONLY_MSPACES */\n\n/* ----------------------------- user mspaces ---------------------------- */\n\n#if MSPACES\n\nstatic mstate init_user_mstate(char* tbase, size_t tsize) {\n  size_t msize = pad_request(sizeof(struct malloc_state));\n  mchunkptr mn;\n  mchunkptr msp = align_as_chunk(tbase);\n  mstate m = (mstate)(chunk2mem(msp));\n  memset(m, 0, msize);\n  (void)INITIAL_LOCK(&m->mutex);\n  msp->head = (msize|INUSE_BITS);\n  m->seg.base = m->least_addr = tbase;\n  m->seg.size = m->footprint = m->max_footprint = tsize;\n  m->magic = mparams.magic;\n  m->release_checks = MAX_RELEASE_CHECK_RATE;\n  m->mflags = mparams.default_mflags;\n  m->extp = 0;\n  m->exts = 0;\n  disable_contiguous(m);\n  init_bins(m);\n  mn = next_chunk(mem2chunk(m));\n  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);\n  check_top_chunk(m, m->top);\n  return m;\n}\n\nmspace create_mspace(size_t capacity, int locked) {\n  mstate m = 0;\n  size_t msize;\n  ensure_initialization();\n  msize = pad_request(sizeof(struct malloc_state));\n  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {\n    size_t rs = ((capacity == 0)? mparams.granularity :\n                 (capacity + TOP_FOOT_SIZE + msize));\n    size_t tsize = granularity_align(rs);\n    char* tbase = (char*)(CALL_MMAP(tsize));\n    if (tbase != CMFAIL) {\n      m = init_user_mstate(tbase, tsize);\n      m->seg.sflags = USE_MMAP_BIT;\n      set_lock(m, locked);\n    }\n  }\n  return (mspace)m;\n}\n\nmspace create_mspace_with_base(void* base, size_t capacity, int locked) {\n  mstate m = 0;\n  size_t msize;\n  ensure_initialization();\n  msize = pad_request(sizeof(struct malloc_state));\n  if (capacity > msize + TOP_FOOT_SIZE &&\n      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {\n    m = init_user_mstate((char*)base, capacity);\n    m->seg.sflags = EXTERN_BIT;\n    set_lock(m, locked);\n  }\n  return (mspace)m;\n}\n\nint mspace_track_large_chunks(mspace msp, int enable) {\n  int ret = 0;\n  mstate ms = (mstate)msp;\n  if (!PREACTION(ms)) {\n    if (!use_mmap(ms)) {\n      ret = 1;\n    }\n    if (!enable) {\n      enable_mmap(ms);\n    } else {\n      disable_mmap(ms);\n    }\n    POSTACTION(ms);\n  }\n  return ret;\n}\n\nsize_t destroy_mspace(mspace msp) {\n  size_t freed = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    msegmentptr sp = &ms->seg;\n    (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */\n    while (sp != 0) {\n      char* base = sp->base;\n      size_t size = sp->size;\n      flag_t flag = sp->sflags;\n      (void)base; /* placate people compiling -Wunused-variable */\n      sp = sp->next;\n      if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&\n          CALL_MUNMAP(base, size) == 0)\n        freed += size;\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return freed;\n}\n\n/*\n  mspace versions of routines are near-clones of the global\n  versions. This is not so nice but better than the alternatives.\n*/\n\nvoid* mspace_malloc(mspace msp, size_t bytes) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  if (!PREACTION(ms)) {\n    void* mem;\n    size_t nb;\n    if (bytes <= MAX_SMALL_REQUEST) {\n      bindex_t idx;\n      binmap_t smallbits;\n      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);\n      idx = small_index(nb);\n      smallbits = ms->smallmap >> idx;\n\n      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */\n        mchunkptr b, p;\n        idx += ~smallbits & 1;       /* Uses next bin if idx empty */\n        b = smallbin_at(ms, idx);\n        p = b->fd;\n        assert(chunksize(p) == small_index2size(idx));\n        unlink_first_small_chunk(ms, b, p, idx);\n        set_inuse_and_pinuse(ms, p, small_index2size(idx));\n        mem = chunk2mem(p);\n        check_malloced_chunk(ms, mem, nb);\n        goto postaction;\n      }\n\n      else if (nb > ms->dvsize) {\n        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */\n          mchunkptr b, p, r;\n          size_t rsize;\n          bindex_t i;\n          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));\n          binmap_t leastbit = least_bit(leftbits);\n          compute_bit2idx(leastbit, i);\n          b = smallbin_at(ms, i);\n          p = b->fd;\n          assert(chunksize(p) == small_index2size(i));\n          unlink_first_small_chunk(ms, b, p, i);\n          rsize = small_index2size(i) - nb;\n          /* Fit here cannot be remainderless if 4byte sizes */\n          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)\n            set_inuse_and_pinuse(ms, p, small_index2size(i));\n          else {\n            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);\n            r = chunk_plus_offset(p, nb);\n            set_size_and_pinuse_of_free_chunk(r, rsize);\n            replace_dv(ms, r, rsize);\n          }\n          mem = chunk2mem(p);\n          check_malloced_chunk(ms, mem, nb);\n          goto postaction;\n        }\n\n        else if (ms->treemap.pload() != 0 && (mem = tmalloc_small(ms, nb)) != 0) {\n          check_malloced_chunk(ms, mem, nb);\n          goto postaction;\n        }\n      }\n    }\n    else if (bytes >= MAX_REQUEST)\n      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */\n    else {\n      nb = pad_request(bytes);\n      if (ms->treemap.pload() != 0 && (mem = tmalloc_large(ms, nb)) != 0) {\n        check_malloced_chunk(ms, mem, nb);\n        goto postaction;\n      }\n    }\n\n    if (nb <= ms->dvsize) {\n      size_t rsize = ms->dvsize - nb;\n      mchunkptr p = ms->dv;\n      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */\n        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);\n        ms->dvsize = rsize;\n        set_size_and_pinuse_of_free_chunk(r, rsize);\n        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);\n      }\n      else { /* exhaust dv */\n        size_t dvs = ms->dvsize;\n        ms->dvsize = 0;\n        ms->dv = 0;\n        set_inuse_and_pinuse(ms, p, dvs);\n      }\n      mem = chunk2mem(p);\n      check_malloced_chunk(ms, mem, nb);\n      goto postaction;\n    }\n\n    else if (nb < ms->topsize) { /* Split top */\n      size_t rsize = ms->topsize -= nb;\n      mchunkptr p = ms->top;\n      mchunkptr r = ms->top = chunk_plus_offset(p, nb);\n      r->head = rsize | PINUSE_BIT;\n      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);\n      mem = chunk2mem(p);\n      check_top_chunk(ms, ms->top);\n      check_malloced_chunk(ms, mem, nb);\n      goto postaction;\n    }\n    mem = 0;\n    //mem = sys_alloc(ms, nb);\n\n  postaction:\n    POSTACTION(ms);\n    return mem;\n  }\n\n  return 0;\n}\n\nvoid mspace_free(mspace msp, void* mem) {\n  if (mem != 0) {\n    mchunkptr p  = mem2chunk(mem);\n#if FOOTERS\n    mstate fm = get_mstate_for(p);\n    (void)msp; /* placate people compiling -Wunused */\n#else /* FOOTERS */\n    mstate fm = (mstate)msp;\n#endif /* FOOTERS */\n    if (!ok_magic(fm)) {\n      USAGE_ERROR_ACTION(fm, p);\n      return;\n    }\n    if (!PREACTION(fm)) {\n      check_inuse_chunk(fm, p);\n      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {\n        size_t psize = chunksize(p);\n        mchunkptr next = chunk_plus_offset(p, psize);\n        if (!pinuse(p)) {\n          size_t prevsize = p->prev_foot;\n          if (is_mmapped(p)) {\n            psize += prevsize + MMAP_FOOT_PAD;\n            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)\n              fm->footprint -= psize;\n            goto postaction;\n          }\n          else {\n            mchunkptr prev = chunk_minus_offset(p, prevsize);\n            psize += prevsize;\n            p = prev;\n            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */\n              if (p != fm->dv) {\n                unlink_chunk(fm, p, prevsize);\n              }\n              else if ((next->head & INUSE_BITS) == INUSE_BITS) {\n                fm->dvsize = psize;\n                set_free_with_pinuse(p, psize, next);\n                goto postaction;\n              }\n            }\n            else\n              goto erroraction;\n          }\n        }\n\n        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {\n          if (!cinuse(next)) {  /* consolidate forward */\n            if (next == fm->top) {\n              size_t tsize = fm->topsize += psize;\n              fm->top = p;\n              p->head = tsize | PINUSE_BIT;\n              if (p == fm->dv) {\n                fm->dv = 0;\n                fm->dvsize = 0;\n              }\n              if (should_trim(fm, tsize))\n                sys_trim(fm, 0);\n              goto postaction;\n            }\n            else if (next == fm->dv) {\n              size_t dsize = fm->dvsize += psize;\n              fm->dv = p;\n              set_size_and_pinuse_of_free_chunk(p, dsize);\n              goto postaction;\n            }\n            else {\n              size_t nsize = chunksize(next);\n              psize += nsize;\n              unlink_chunk(fm, next, nsize);\n              set_size_and_pinuse_of_free_chunk(p, psize);\n              if (p == fm->dv) {\n                fm->dvsize = psize;\n                goto postaction;\n              }\n            }\n          }\n          else\n            set_free_with_pinuse(p, psize, next);\n\n          if (is_small(psize)) {\n            insert_small_chunk(fm, p, psize);\n            check_free_chunk(fm, p);\n          }\n          else {\n            tchunkptr tp = (tchunkptr)p;\n            insert_large_chunk(fm, tp, psize);\n            check_free_chunk(fm, p);\n            fm->release_checks.pstore(fm->release_checks.pload()-1);\n            if (fm->release_checks.pload()== 0)\n              release_unused_segments(fm);\n          }\n          goto postaction;\n        }\n      }\n    erroraction:\n      USAGE_ERROR_ACTION(fm, p);\n    postaction:\n      POSTACTION(fm);\n    }\n  }\n}\n\nvoid* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {\n  void* mem;\n  size_t req = 0;\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  if (n_elements != 0) {\n    req = n_elements * elem_size;\n    if (((n_elements | elem_size) & ~(size_t)0xffff) &&\n        (req / n_elements != elem_size))\n      req = MAX_SIZE_T; /* force downstream failure on overflow */\n  }\n  mem = internal_malloc(ms, req);\n  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))\n    memset(mem, 0, req);\n  return mem;\n}\n\nvoid* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem == 0) {\n    mem = mspace_malloc(msp, bytes);\n  }\n  else if (bytes >= MAX_REQUEST) {\n    MALLOC_FAILURE_ACTION;\n  }\n#ifdef REALLOC_ZERO_BYTES_FREES\n  else if (bytes == 0) {\n    mspace_free(msp, oldmem);\n  }\n#endif /* REALLOC_ZERO_BYTES_FREES */\n  else {\n    size_t nb = request2size(bytes);\n    mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n    mstate m = (mstate)msp;\n#else /* FOOTERS */\n    mstate m = get_mstate_for(oldp);\n    if (!ok_magic(m)) {\n      USAGE_ERROR_ACTION(m, oldmem);\n      return 0;\n    }\n#endif /* FOOTERS */\n    if (!PREACTION(m)) {\n      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);\n      POSTACTION(m);\n      if (newp != 0) {\n        check_inuse_chunk(m, newp);\n        mem = chunk2mem(newp);\n      }\n      else {\n        mem = mspace_malloc(m, bytes);\n        if (mem != 0) {\n          size_t oc = chunksize(oldp) - overhead_for(oldp);\n          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);\n          mspace_free(m, oldmem);\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem != 0) {\n    if (bytes >= MAX_REQUEST) {\n      MALLOC_FAILURE_ACTION;\n    }\n    else {\n      size_t nb = request2size(bytes);\n      mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n      mstate m = (mstate)msp;\n#else /* FOOTERS */\n      mstate m = get_mstate_for(oldp);\n      (void)msp; /* placate people compiling -Wunused */\n      if (!ok_magic(m)) {\n        USAGE_ERROR_ACTION(m, oldmem);\n        return 0;\n      }\n#endif /* FOOTERS */\n      if (!PREACTION(m)) {\n        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);\n        POSTACTION(m);\n        if (newp == oldp) {\n          check_inuse_chunk(m, newp);\n          mem = oldmem;\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  if (alignment <= MALLOC_ALIGNMENT)\n    return mspace_malloc(msp, bytes);\n  return internal_memalign(ms, alignment, bytes);\n}\n\nvoid** mspace_independent_calloc(mspace msp, size_t n_elements,\n                                 size_t elem_size, void* chunks[]) {\n  size_t sz = elem_size; /* serves as 1-element array */\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  return ialloc(ms, n_elements, &sz, 3, chunks);\n}\n\nvoid** mspace_independent_comalloc(mspace msp, size_t n_elements,\n                                   size_t sizes[], void* chunks[]) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  return ialloc(ms, n_elements, sizes, 0, chunks);\n}\n\nsize_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) {\n  return internal_bulk_free((mstate)msp, array, nelem);\n}\n\n#if MALLOC_INSPECT_ALL\nvoid mspace_inspect_all(mspace msp,\n                        void(*handler)(void *start,\n                                       void *end,\n                                       size_t used_bytes,\n                                       void* callback_arg),\n                        void* arg) {\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    if (!PREACTION(ms)) {\n      internal_inspect_all(ms, handler, arg);\n      POSTACTION(ms);\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n}\n#endif /* MALLOC_INSPECT_ALL */\n\nint mspace_trim(mspace msp, size_t pad) {\n  int result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    if (!PREACTION(ms)) {\n      result = sys_trim(ms, pad);\n      POSTACTION(ms);\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\n#if !NO_MALLOC_STATS\nvoid mspace_malloc_stats(mspace msp) {\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    internal_malloc_stats(ms);\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n}\n#endif /* NO_MALLOC_STATS */\n\nsize_t mspace_footprint(mspace msp) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    result = ms->footprint;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\nsize_t mspace_max_footprint(mspace msp) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    result = ms->max_footprint;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\nsize_t mspace_footprint_limit(mspace msp) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    size_t maf = ms->footprint_limit;\n    result = (maf == 0) ? MAX_SIZE_T : maf;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\nsize_t mspace_set_footprint_limit(mspace msp, size_t bytes) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    if (bytes == 0)\n      result = granularity_align(1); /* Use minimal size */\n    if (bytes == MAX_SIZE_T)\n      result = 0;                    /* disable */\n    else\n      result = granularity_align(bytes);\n    ms->footprint_limit = result;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\n#if !NO_MALLINFO\nstruct mallinfo mspace_mallinfo(mspace msp) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return internal_mallinfo(ms);\n}\n#endif /* NO_MALLINFO */\n\nsize_t mspace_usable_size(const void* mem) {\n  if (mem != 0) {\n    mchunkptr p = mem2chunk(mem);\n    if (is_inuse(p))\n      return chunksize(p) - overhead_for(p);\n  }\n  return 0;\n}\n\nint mspace_mallopt(int param_number, int value) {\n  return change_mparam(param_number, value);\n}\n\n#endif /* MSPACES */\n\n\n/* -------------------- Alternative MORECORE functions ------------------- */\n\n/*\n  Guidelines for creating a custom version of MORECORE:\n\n  * For best performance, MORECORE should allocate in multiples of pagesize.\n  * MORECORE may allocate more memory than requested. (Or even less,\n      but this will usually result in a malloc failure.)\n  * MORECORE must not allocate memory when given argument zero, but\n      instead return one past the end address of memory from previous\n      nonzero call.\n  * For best performance, consecutive calls to MORECORE with positive\n      arguments should return increasing addresses, indicating that\n      space has been contiguously extended.\n  * Even though consecutive calls to MORECORE need not return contiguous\n      addresses, it must be OK for malloc'ed chunks to span multiple\n      regions in those cases where they do happen to be contiguous.\n  * MORECORE need not handle negative arguments -- it may instead\n      just return MFAIL when given negative arguments.\n      Negative arguments are always multiples of pagesize. MORECORE\n      must not misinterpret negative args as large positive unsigned\n      args. You can suppress all such calls from even occurring by defining\n      MORECORE_CANNOT_TRIM,\n\n  As an example alternative MORECORE, here is a custom allocator\n  kindly contributed for pre-OSX macOS.  It uses virtually but not\n  necessarily physically contiguous non-paged memory (locked in,\n  present and won't get swapped out).  You can use it by uncommenting\n  this section, adding some #includes, and setting up the appropriate\n  defines above:\n\n      #define MORECORE osMoreCore\n\n  There is also a shutdown routine that should somehow be called for\n  cleanup upon program exit.\n\n  #define MAX_POOL_ENTRIES 100\n  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)\n  static int next_os_pool;\n  void *our_os_pools[MAX_POOL_ENTRIES];\n\n  void *osMoreCore(int size)\n  {\n    void *ptr = 0;\n    static void *sbrk_top = 0;\n\n    if (size > 0)\n    {\n      if (size < MINIMUM_MORECORE_SIZE)\n         size = MINIMUM_MORECORE_SIZE;\n      if (CurrentExecutionLevel() == kTaskLevel)\n         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);\n      if (ptr == 0)\n      {\n        return (void *) MFAIL;\n      }\n      // save ptrs so they can be freed during cleanup\n      our_os_pools[next_os_pool] = ptr;\n      next_os_pool++;\n      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);\n      sbrk_top = (char *) ptr + size;\n      return ptr;\n    }\n    else if (size < 0)\n    {\n      // we don't currently support shrink behavior\n      return (void *) MFAIL;\n    }\n    else\n    {\n      return sbrk_top;\n    }\n  }\n\n  // cleanup any allocated memory pools\n  // called as last thing before shutting down driver\n\n  void osCleanupMem(void)\n  {\n    void **ptr;\n\n    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)\n      if (*ptr)\n      {\n         PoolDeallocate(*ptr);\n         *ptr = 0;\n      }\n  }\n\n*/\n\n\n/* -----------------------------------------------------------------------\nHistory:\n    v2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea\n      * fix bad comparison in dlposix_memalign\n      * don't reuse adjusted asize in sys_alloc\n      * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion\n      * reduce compiler warnings -- thanks to all who reported/suggested these\n\n    v2.8.5 Sun May 22 10:26:02 2011  Doug Lea  (dl at gee)\n      * Always perform unlink checks unless INSECURE\n      * Add posix_memalign.\n      * Improve realloc to expand in more cases; expose realloc_in_place.\n        Thanks to Peter Buhr for the suggestion.\n      * Add footprint_limit, inspect_all, bulk_free. Thanks\n        to Barry Hayes and others for the suggestions.\n      * Internal refactorings to avoid calls while holding locks\n      * Use non-reentrant locks by default. Thanks to Roland McGrath\n        for the suggestion.\n      * Small fixes to mspace_destroy, reset_on_error.\n      * Various configuration extensions/changes. Thanks\n         to all who contributed these.\n\n    V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu)\n      * Update Creative Commons URL\n\n    V2.8.4 Wed May 27 09:56:23 2009  Doug Lea  (dl at gee)\n      * Use zeros instead of prev foot for is_mmapped\n      * Add mspace_track_large_chunks; thanks to Jean Brouwers\n      * Fix set_inuse in internal_realloc; thanks to Jean Brouwers\n      * Fix insufficient sys_alloc padding when using 16byte alignment\n      * Fix bad error check in mspace_footprint\n      * Adaptations for ptmalloc; thanks to Wolfram Gloger.\n      * Reentrant spin locks; thanks to Earl Chew and others\n      * Win32 improvements; thanks to Niall Douglas and Earl Chew\n      * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options\n      * Extension hook in malloc_state\n      * Various small adjustments to reduce warnings on some compilers\n      * Various configuration extensions/changes for more platforms. Thanks\n         to all who contributed these.\n\n    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)\n      * Add max_footprint functions\n      * Ensure all appropriate literals are size_t\n      * Fix conditional compilation problem for some #define settings\n      * Avoid concatenating segments with the one provided\n        in create_mspace_with_base\n      * Rename some variables to avoid compiler shadowing warnings\n      * Use explicit lock initialization.\n      * Better handling of sbrk interference.\n      * Simplify and fix segment insertion, trimming and mspace_destroy\n      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x\n      * Thanks especially to Dennis Flanagan for help on these.\n\n    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)\n      * Fix memalign brace error.\n\n    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)\n      * Fix improper #endif nesting in C++\n      * Add explicit casts needed for C++\n\n    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)\n      * Use trees for large bins\n      * Support mspaces\n      * Use segments to unify sbrk-based and mmap-based system allocation,\n        removing need for emulation on most platforms without sbrk.\n      * Default safety checks\n      * Optional footer checks. Thanks to William Robertson for the idea.\n      * Internal code refactoring\n      * Incorporate suggestions and platform-specific changes.\n        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,\n        Aaron Bachmann,  Emery Berger, and others.\n      * Speed up non-fastbin processing enough to remove fastbins.\n      * Remove useless cfree() to avoid conflicts with other apps.\n      * Remove internal memcpy, memset. Compilers handle builtins better.\n      * Remove some options that no one ever used and rename others.\n\n    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)\n      * Fix malloc_state bitmap array misdeclaration\n\n    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)\n      * Allow tuning of FIRST_SORTED_BIN_SIZE\n      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.\n      * Better detection and support for non-contiguousness of MORECORE.\n        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger\n      * Bypass most of malloc if no frees. Thanks To Emery Berger.\n      * Fix freeing of old top non-contiguous chunk im sysmalloc.\n      * Raised default trim and map thresholds to 256K.\n      * Fix mmap-related #defines. Thanks to Lubos Lunak.\n      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.\n      * Branch-free bin calculation\n      * Default trim and mmap thresholds now 256K.\n\n    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)\n      * Introduce independent_comalloc and independent_calloc.\n        Thanks to Michael Pachos for motivation and help.\n      * Make optional .h file available\n      * Allow > 2GB requests on 32bit systems.\n      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.\n        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,\n        and Anonymous.\n      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for\n        helping test this.)\n      * memalign: check alignment arg\n      * realloc: don't try to shift chunks backwards, since this\n        leads to  more fragmentation in some programs and doesn't\n        seem to help in any others.\n      * Collect all cases in malloc requiring system memory into sysmalloc\n      * Use mmap as backup to sbrk\n      * Place all internal state in malloc_state\n      * Introduce fastbins (although similar to 2.5.1)\n      * Many minor tunings and cosmetic improvements\n      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK\n      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS\n        Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.\n      * Include errno.h to support default failure action.\n\n    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)\n      * return null for negative arguments\n      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>\n         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'\n          (e.g. WIN32 platforms)\n         * Cleanup header file inclusion for WIN32 platforms\n         * Cleanup code to avoid Microsoft Visual C++ compiler complaints\n         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing\n           memory allocation routines\n         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)\n         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to\n           usage of 'assert' in non-WIN32 code\n         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to\n           avoid infinite loop\n      * Always call 'fREe()' rather than 'free()'\n\n    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)\n      * Fixed ordering problem with boundary-stamping\n\n    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)\n      * Added pvalloc, as recommended by H.J. Liu\n      * Added 64bit pointer support mainly from Wolfram Gloger\n      * Added anonymously donated WIN32 sbrk emulation\n      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen\n      * malloc_extend_top: fix mask error that caused wastage after\n        foreign sbrks\n      * Add linux mremap support code from HJ Liu\n\n    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)\n      * Integrated most documentation with the code.\n      * Add support for mmap, with help from\n        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).\n      * Use last_remainder in more cases.\n      * Pack bins using idea from  colin@nyx10.cs.du.edu\n      * Use ordered bins instead of best-fit threshhold\n      * Eliminate block-local decls to simplify tracing and debugging.\n      * Support another case of realloc via move into top\n      * Fix error occuring when initial sbrk_base not word-aligned.\n      * Rely on page size for units instead of SBRK_UNIT to\n        avoid surprises about sbrk alignment conventions.\n      * Add mallinfo, mallopt. Thanks to Raymond Nijssen\n        (raymond@es.ele.tue.nl) for the suggestion.\n      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.\n      * More precautions for cases where other routines call sbrk,\n        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).\n      * Added macros etc., allowing use in linux libc from\n        H.J. Lu (hjl@gnu.ai.mit.edu)\n      * Inverted this history list\n\n    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)\n      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.\n      * Removed all preallocation code since under current scheme\n        the work required to undo bad preallocations exceeds\n        the work saved in good cases for most test programs.\n      * No longer use return list or unconsolidated bins since\n        no scheme using them consistently outperforms those that don't\n        given above changes.\n      * Use best fit for very large chunks to prevent some worst-cases.\n      * Added some support for debugging\n\n    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)\n      * Removed footers when chunks are in use. Thanks to\n        Paul Wilson (wilson@cs.texas.edu) for the suggestion.\n\n    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)\n      * Added malloc_trim, with help from Wolfram Gloger\n        (wmglo@Dent.MED.Uni-Muenchen.DE).\n\n    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)\n\n    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)\n      * realloc: try to expand in both directions\n      * malloc: swap order of clean-bin strategy;\n      * realloc: only conditionally expand backwards\n      * Try not to scavenge used bins\n      * Use bin counts as a guide to preallocation\n      * Occasionally bin return list chunks in first scan\n      * Add a few optimizations from colin@nyx10.cs.du.edu\n\n    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)\n      * faster bin computation & slightly different binning\n      * merged all consolidations to one part of malloc proper\n         (eliminating old malloc_find_space & malloc_clean_bin)\n      * Scan 2 returns chunks (not just 1)\n      * Propagate failure in realloc if malloc returns 0\n      * Add stuff to allow compilation on non-ANSI compilers\n          from kpv@research.att.com\n\n    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)\n      * removed potential for odd address access in prev_chunk\n      * removed dependency on getpagesize.h\n      * misc cosmetics and a bit more internal documentation\n      * anticosmetics: mangled names in macros to evade debugger strangeness\n      * tested on sparc, hp-700, dec-mips, rs6000\n          with gcc & native cc (hp, dec only) allowing\n          Detlefs & Zorn comparison study (in SIGPLAN Notices.)\n\n    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)\n      * Based loosely on libg++-1.2X malloc. (It retains some of the overall\n         structure of old version,  but most details differ.)\n\n*/\n}\n"
  },
  {
    "path": "ptms/romuluslr/RomulusLR.cpp",
    "content": "\n#include \"RomulusLR.hpp\"\n\n\nnamespace romuluslr{\n    /*\n     * <h1> RomulusLR </h1>\n     * TODO: explain this...\n     *\n     */\n\n// Global with the 'main' size. Used by pload()\nuint64_t g_main_size = 0;\n// Global with the 'main' addr. Used by pload()\nuint8_t* g_main_addr = 0;\n\nuint8_t* g_main_addr_end;\n\nalignas(128) bool g_right = false;\n\nthread_local int tl_lrromulus = 0;\n// Counter of nested write transactions\nthread_local int64_t tl_nested_write_trans = 0;\n// Counter of nested read-only transactions\nthread_local int64_t tl_nested_read_trans = 0;\n\nRomulusLR gRomLR {};\nRomulusLR* romlr = nullptr;\n\n}\n"
  },
  {
    "path": "ptms/romuluslr/RomulusLR.hpp",
    "content": "/*\n * Copyright 2017-2018\n *   Andreia Correia <andreia.veiga@unine.ch>\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Pedro Ramalhete <pramalhe@gmail.com>\n *\n * This work is published under the MIT license. See LICENSE.TXT\n */\n#ifndef _ROMULUS_LR_H_\n#define _ROMULUS_LR_H_\n\n#include <atomic>\n#include <cstdint>\n#include <cassert>\n#include <string>\n#include <cstring>      // std::memcpy()\n#include <sys/mman.h>   // Needed if we use mmap()\n#include <sys/types.h>  // Needed by open() and close()\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>     // Needed by close()\n#include <stdio.h>\n#include <iostream>\n#include <algorithm>\n#include <vector>\n#include <functional>\n#include <thread>\n\n#include \"../common/pfences.h\"\n#include \"../common/ThreadRegistry.hpp\"\n\n/* <h1> Romulus using Left-Right plus flat-combining </h1>\n *\n * Romulus using Left-Right plus flat-combining.\n * It provides wait-free (population oblivious) progress for readers and blocking (starvationg-free) for writers.\n *\n * Because we wanted the user to just include this header, we have put everything in the header,\n * which isn't pretty, but it makes life easier for application developers.\n *\n * Left-Right paper: https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/left-right-2014.pdf\n * Flat Combining paper:  http://dl.acm.org/citation.cfm?id=1810540\n * A post about Left-Right with Flat Combining: http://concurrencyfreaks.com/2017/07/left-right-and-c-rw-wp-with-flat.html\n *\n * We have the following classes in this file:\n * RIStaticPerThread -> A ReadIndicator to be used in the URCU inside Left-Right\n * RomulusLR         -> Romulus using Left-Right and Flat-Combining for Writers\n * persist<T>        -> Annotation for persistent types T\n *\n * How to use RomulusLR:\n * persist<UserObject> obj;\n * gLRTM.write_transaction([&obj] () {obj.mutative_method()} );\n * gLRTM.read_transaction([&obj] () {obj.non_mutative_method()} );\n *\n * DO NOT modify global variables or thread-locals inside a write_transaction()\n * because they will be modified twice.\n * DO NOT pass by reference stuff to the lambda and then modify it inside the\n * lambda because the lambda is executed twice.\n */\nnamespace romuluslr {\n\nextern uint64_t g_main_size;\nextern uint8_t* g_main_addr;\nextern uint8_t* g_main_addr_end;\nextern bool g_right;\n\nclass RIStaticPerThread {\nprivate:\n    static const uint64_t NOT_READING = 0;\n    static const uint64_t READING = 1;\n    static const int CLPAD = 128/sizeof(uint64_t);\n\n    const int maxThreads;\n    alignas(128) std::atomic<uint64_t>* states;\n\npublic:\n    RIStaticPerThread(int maxThreads) : maxThreads{maxThreads} {\n        states = new std::atomic<uint64_t>[maxThreads*CLPAD];\n        for (int tid = 0; tid < maxThreads; tid++) {\n            states[tid*CLPAD].store(NOT_READING, std::memory_order_relaxed);\n        }\n    }\n\n    ~RIStaticPerThread() {\n        delete[] states;\n    }\n\n    inline void arrive(const int tid) noexcept {\n        states[tid*CLPAD].store(READING);\n    }\n\n    inline void depart(const int tid) noexcept {\n        states[tid*CLPAD].store(NOT_READING, std::memory_order_release);\n    }\n\n    inline bool isEmpty() noexcept {\n        for (int tid = 0; tid < ThreadRegistry::getMaxThreads(); tid++) {\n            if (states[tid*CLPAD].load() != NOT_READING) return false;\n        }\n        return true;\n    }\n};\n\n\n// Forward declaration for global instance of RomulusLR\nclass RomulusLR;\nextern RomulusLR gRomLR;\n// Instance with current ongoing transaction\nextern RomulusLR* romlr;\n// Counter of nested write transactions\nextern thread_local int64_t tl_nested_write_trans;\n// Counter of nested read-only transactions\nextern thread_local int64_t tl_nested_read_trans;\n\n\n// Possible values for 'leftRight' and tl_lrromulus variable\nstatic const int TRAVERSE_LEFT = 0;\nstatic const int TRAVERSE_RIGHT = 1;\n// This variable indicates which of the instances to be used by the ongoing transaction\nextern thread_local int tl_lrromulus;\n\n// Doug Lea's allocator declarations\ntypedef void* mspace;\nextern void* mspace_malloc(mspace msp, size_t bytes);\nextern void mspace_free(mspace msp, void* mem);\nextern mspace create_mspace_with_base(void* base, size_t capacity, int locked);\n\n\nclass RomulusLR {\n    // Id for sanity check of Romulus\n    static const uint64_t MAGIC_ID = 0x1337BAB5;\n\n    // Possible values for \"state\"\n    static const int IDLE = 0;\n    static const int MUTATING = 1;\n    static const int COPYING = 2;\n\n    // Number of log entries in a chunk of the log\n    static const int CHUNK_SIZE = 1024;\n\n    // Filename for the mapping file\n    const char* MMAP_FILENAME = \"/dev/shm/romuluslr_shared\";\n\n    // Member variables\n    bool dommap;\n    int fd = -1;\n    uint8_t* base_addr;\n    uint64_t max_size;\n    uint8_t* main_addr;\n    uint8_t* back_addr;\n\n    // Each log entry is two words (8+8 = 16 bytes)\n    struct LogEntry {\n        size_t    offset;  // Pointer offset in bytes, relative to main_addr\n        uint64_t  length;  // Range length of data at pointer offset\n    };\n\n    struct LogChunk {\n        LogEntry  entries[CHUNK_SIZE];\n        uint64_t  num_entries { 0 };\n        LogChunk* next        { nullptr };\n    };\n\n    // There is always at least one (empty) chunk in the log, it's the head\n    LogChunk* log_head = new LogChunk;\n    LogChunk* log_tail = log_head;\n\n    // One instance of this is at the start of base_addr, in persistent memory\n    struct PersistentHeader {\n        uint64_t         id {0};          // Validates intialization\n        std::atomic<int> state {IDLE}; // Current state of consistency\n        void**           objects {};      // Objects directory\n        mspace           ms {};           // Pointer to allocator's metadata\n        uint64_t         used_size {0};   // It has to be the last, to calculate the used_size\n    };\n\n    PersistentHeader* per {nullptr};      // Volatile pointer to start of persistent memory\n    uint64_t log_size = 0;\n    bool logEnabled = true;\n\nprivate:\n    static const int CLPAD = 128/sizeof(uintptr_t);\n    static const int LOCKED = 1;\n    static const int UNLOCKED = 0;\n    const int maxThreads;\n    // Stuff use by the Flat Combining mechanism\n    alignas(128) std::atomic< std::function<void()>* >* fc; // array of atomic pointers to functions\n    // Stuff used by the Left-Right mechanism\n    alignas(128) std::atomic<int> writersMutex { UNLOCKED };\n    alignas(128) std::atomic<int> leftRight { TRAVERSE_LEFT };\n    alignas(128) std::atomic<int> versionIndex { 0 };\n    RIStaticPerThread ri[2] { REGISTRY_MAX_THREADS, REGISTRY_MAX_THREADS };\n\n\n    //\n    // Private methods\n    //\n    // Flush touched cache lines\n    inline void flush_range(uint8_t* addr, size_t length) {\n        const int cache_line_size = 64;\n        uint8_t* ptr = addr;\n        uint8_t* last = addr + length;\n        for (; ptr < last; ptr += cache_line_size) PWB(ptr);\n    }\n    void copyMainToBack() {\n        // Copy the data from 'main' to 'back'\n        uint64_t size = std::min(per->used_size, g_main_size);\n        std::memcpy(back_addr, main_addr, size);\n        flush_range(back_addr, size);\n    }\n\n    void copyBackToMain() {\n        // Copy the data from 'back' to 'main'\n        uint64_t size = std::min(per->used_size, g_main_size);\n        std::memcpy(main_addr, back_addr, size);\n        flush_range(main_addr, size);\n    }\n\n\n    bool compareMainAndBack() {\n        if (std::memcmp(main_addr, back_addr, g_main_size) != 0) {\n            void* firstaddr = nullptr;\n            int sumdiff = 0;\n            for (size_t idx = 0; idx < g_main_size-sizeof(size_t); idx++) {\n                if (*(main_addr+idx) != *(back_addr+idx)) {\n                    printf(\"Difference at %p  main=%ld  back=%ld\\n\", main_addr+idx, *(int64_t*)(main_addr+idx), *(int64_t*)(back_addr+idx));\n                    sumdiff++;\n                    if (firstaddr == nullptr) firstaddr = main_addr+idx;\n                }\n            }\n            if (sumdiff != 0) {\n                printf(\"sumdiff=%d bytes\\n\", sumdiff);\n                printf(\"\\nThere seems to be a missing persist<T> in your code.\\n\");\n                printf(\"Rerun with gdb and set a watchpoint using the command\\nwatch * %p\\n\\n\", firstaddr);\n            }\n            assert(sumdiff == 0);\n        }\n        return true;\n    }\n\n    /*\n     * Called at the end of a transaction to replicate the mutations on \"back\",\n     * or when abort_transaction() is called by the user, to rollback the\n     * mutations on \"main\".\n     * Deletes the log as it is being applied.\n     */\n    inline void apply_pwb(uint8_t* from_addr) {\n        // Apply the log to the instance on 'to_addr', copying data from the instance at 'from_addr'\n        LogChunk* chunk = log_head;\n        while (chunk != nullptr) {\n            for (int i = 0; i < chunk->num_entries; i++) {\n                LogEntry& e = chunk->entries[i];\n                //std::memcpy(to_addr + e.offset, from_addr + e.offset, e.length);\n                flush_range(from_addr + e.offset, e.length);\n            }\n            chunk = chunk->next;\n        }\n    }\n\n    /*\n     * Called at the end of a transaction to replicate the mutations on \"back\",\n     * or when abort_transaction() is called by the user, to rollback the\n     * mutations on \"main\".\n     * Deletes the log as it is being applied.\n     */\n    inline void apply_log(uint8_t* from_addr, uint8_t* to_addr) {\n        // Apply the log to the instance on 'to_addr', copying data from the instance at 'from_addr'\n        LogChunk* chunk = log_head;\n        while (chunk != nullptr) {\n            for (int i = 0; i < chunk->num_entries; i++) {\n                LogEntry& e = chunk->entries[i];\n                std::memcpy(to_addr + e.offset, from_addr + e.offset, e.length);\n                //flush_range(to_addr + e.offset, e.length);\n            }\n            //LogChunk* next = chunk->next;\n            //if (chunk != log_head) delete chunk;\n            chunk = chunk->next;\n        }\n        // Clear the log, leaving one chunk for next transaction, with zero'ed entries\n        /*\n        log_tail = log_head;\n        log_head->num_entries = 0;\n        log_head->next = nullptr;*/\n    }\n\n    inline void clear_log() {\n        LogChunk* chunk = log_head->next;\n        while (chunk != nullptr) {\n            LogChunk* next = chunk->next;\n            delete chunk;\n            chunk = next;\n        }\n        // Clear the log, leaving one chunk for next transaction, with zero'ed entries\n        log_tail = log_head;\n        log_head->num_entries = 0;\n        log_head->next = nullptr;\n    }\n\n    inline void toggleVersionAndWait() {\n        const int localVI = versionIndex.load();\n        const int prevVI = localVI & 0x1;\n        const int nextVI = (localVI+1) & 0x1;\n        // Wait for Readers from next version\n        while (!ri[nextVI].isEmpty()) {} // spin\n        // Toggle the versionIndex variable\n        versionIndex.store(nextVI);\n        // Wait for Readers from previous version\n        while (!ri[prevVI].isEmpty()) {} // spin\n    }\n\n\npublic:\n    /*\n     * Adds to the log the current contents of the memory location starting at\n     * 'addr' with a certain 'length' in bytes\n     */\n    inline void add_to_log(void* addr, int length) noexcept {\n\n        if (!logEnabled) return;\n        // If the log has more than 1/4 of the entire size then skip the log\n        // and copy the used size of the main region.\n        if (log_size > per->used_size/4) {\n            logEnabled = false;\n            return;\n        }\n        size_t addrCL = ((size_t)addr)>>6;\n        // Get the current chunk of log and if it is already full then create a new chunk and add the entry there.\n        LogChunk* chunk = log_tail;\n        bool sameCL = false;\n\n        if(addrCL == (size_t)((uint8_t*)addr+length)>>6){\n        \tsameCL = true;\n        \tint size = chunk->num_entries;\n        \tfor(int i=size-1;i>=0 && i>size-16;i--){\n\t\t\t\tLogEntry& e1 = chunk->entries[i];\n\n\t\t\t\tsize_t offCL = (size_t)(e1.offset+main_addr)>>6;\n\t\t\t\tif(e1.length==64 && (size_t)(offCL<<6) == (size_t)(e1.offset+main_addr)){\n\t\t\t\t\tif(offCL == addrCL) return;\n\t\t\t\t}\n        \t}\n        }\n        if (chunk->num_entries == CHUNK_SIZE) {\n            chunk = new LogChunk();\n            log_tail->next = chunk;\n            log_tail = chunk;\n        }\n        LogEntry& e = chunk->entries[chunk->num_entries];\n\n        if(sameCL){\n        \tsize_t cl =addrCL<<6;\n            e.offset = (uint8_t*)cl - main_addr;\n        \te.length = 64;\n        }else {\n        \te.offset = (uint8_t*)addr - main_addr;\n        \te.length = length;\n        }\n        log_size+=length;\n        chunk->num_entries++;\n    }\n\n    RomulusLR() : dommap{true},maxThreads{128}{\n\n        fc = new std::atomic< std::function<void()>* >[maxThreads*CLPAD];\n        for (int i = 0; i < maxThreads; i++) {\n            fc[i*CLPAD].store(nullptr, std::memory_order_relaxed);\n        }\n        romlr = this;\n        /*if (dommap) {\n\n        }*/\n        ns_init();\n    }\n\n\n    ~RomulusLR() {\n        delete[] fc;\n        // Must do munmap() if we did mmap()\n        if (dommap) {\n            //destroy_mspace(ms);\n            munmap(base_addr, max_size);\n            close(fd);\n        }\n    }\n\n    void ns_init(){\n    \tbase_addr = (uint8_t*)0x7fdd80000000;\n\t\tmax_size = 400*1024*1024; // 400 Mb => 200 Mb for the user\n\t\t// Check if the file already exists or not\n\t\tstruct stat buf;\n\t\tif (stat(MMAP_FILENAME, &buf) == 0) {\n\t\t\t// File exists\n\t\t\t//std::cout << \"Re-using memory region\\n\";\n\t\t\tfd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0755);\n\t\t\tassert(fd >= 0);\n\t\t\t// mmap() memory range\n\t\t\tuint8_t* got_addr = (uint8_t *)mmap(base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);\n\t\t\tif (got_addr == MAP_FAILED) {\n\t\t\t\tprintf(\"got_addr = %p  %p\\n\", got_addr, MAP_FAILED);\n\t\t\t\tperror(\"ERROR: mmap() is not working !!! \");\n\t\t\t\tassert(false);\n\t\t\t}\n\t\t\tper = reinterpret_cast<PersistentHeader*>(base_addr);\n\t\t\tif (per->id != MAGIC_ID) createFile();\n\t\t\tg_main_size = (max_size - sizeof(PersistentHeader))/2;\n\t\t\tmain_addr = base_addr + sizeof(PersistentHeader);\n\t\t\tback_addr = main_addr + g_main_size;\n\t\t\tg_main_addr = main_addr;\n\t\t\tg_main_addr_end = main_addr + g_main_size;\n\t\t\tg_right = false;\n\t\t\trecover();\n\t\t} else {\n\t\t\tcreateFile();\n\t\t}\n    }\n\n    void createFile(){\n        // File doesn't exist\n        fd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0755);\n        assert(fd >= 0);\n        if (lseek(fd, max_size-1, SEEK_SET) == -1) {\n            perror(\"lseek() error\");\n        }\n        if (write(fd, \"\", 1) == -1) {\n            perror(\"write() error\");\n        }\n        // mmap() memory range\n        uint8_t* got_addr = (uint8_t *)mmap(base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);\n        if (got_addr == MAP_FAILED) {\n            printf(\"got_addr = %p  %p\\n\", got_addr, MAP_FAILED);\n            perror(\"ERROR: mmap() is not working !!! \");\n            assert(false);\n        }\n        // No data in persistent memory, initialize\n        per = new (base_addr) PersistentHeader;\n        g_main_size = (max_size - sizeof(PersistentHeader))/2;\n        main_addr = base_addr + sizeof(PersistentHeader);\n        back_addr = main_addr + g_main_size;\n        g_main_addr = main_addr;\n        g_main_addr_end = main_addr + g_main_size;\n\n        // We need to call create_mspace_with_base() from within a transaction so that\n        // the modifications on 'main' get replicated on 'back'. This means we temporarily\n        // need to set the 'used_size' to 'main_size' to make sure everything is copied.\n        g_right = false;\n        begin_transaction();\n\n        // Just to force the copy of the whole main region\n        per->used_size = g_main_size;\n        per->ms = create_mspace_with_base(main_addr, g_main_size, false);\n        per->objects = (void**)mspace_malloc(per->ms, sizeof(void*)*100);\n        for (int i = 0; i < 100; i++) {\n            per->objects[i] = nullptr;\n            add_to_log(&per->objects[i],sizeof(void*));\n            PWB(&per->objects[i]);\n        }\n        end_transaction();\n\n        // The used bytes in the main region\n        per->used_size = (uint8_t*)(&per->used_size) - ((uint8_t*)base_addr+sizeof(PersistentHeader))+128;\n        flush_range((uint8_t*)per,sizeof(PersistentHeader));\n        PFENCE();\n        // Finally, set the id to confirm that the whole initialization process has completed\n        per->id = MAGIC_ID;\n        PWB(&per->id);\n        PSYNC();\n\n    }\n\n    static std::string className() { return \"RomulusLR\"; }\n\n    template <typename T>\n    static inline T* get_object(int idx) {\n        if (tl_lrromulus == TRAVERSE_LEFT) {\n            return static_cast<T*>(gRomLR.per->objects[idx]);\n        } else {\n            return reinterpret_cast<T*>( *(size_t*)((uint8_t*)&(gRomLR.per->objects[idx]) + g_main_size) );\n        }\n    }\n\n    template <typename T>\n    static inline void put_object(int idx, T* obj) {\n        gRomLR.per->objects[idx] = obj;\n        gRomLR.add_to_log(&(gRomLR.per->objects[idx]), sizeof(void*));\n        PWB(&(gRomLR.per->objects[idx]));\n    }\n\n    /*\n     * Must be called at the beginning of each (write) transaction.\n     */\n    inline void begin_transaction() {\n        // Check for nested transaction\n    \ttl_nested_write_trans++;\n        if (tl_nested_write_trans >1) return;\n\n        per->state.store(MUTATING, std::memory_order_relaxed);\n        PWB(&per->state);\n        // One PFENCE() is enough for all user modifications because no ordering is needed between them.\n        PFENCE();\n    }\n\n\n    /*\n     * Must be called at the end of each (write) transaction.\n     */\n    inline void end_transaction() {\n        // Check for nested transaction\n    \t--tl_nested_write_trans;\n        if (tl_nested_write_trans >0) return;\n        // Do a PFENCE() to make persistent the stores done in 'main' and on the Romulus persistent\n        // data (due to memory allocation).\n        // We only care about ordering here, not about durability, therefore, no need to block.\n        PFENCE();\n        per->state.store(COPYING, std::memory_order_relaxed);        /* str_rel */\n        PWB(&per->state);\n        PWB(&per->used_size);\n        // PSYNC() here to have ACID Durability on the mutations done to \"main\" and make the change of state visible\n        PSYNC();\n        // Apply log, copying data from 'main' to 'back'\n        if (logEnabled) {\n            apply_log(main_addr, back_addr);\n        } else {\n            copyMainToBack();\n            clear_log();\n            logEnabled = true;\n        }\n        log_size = 0;\n        PFENCE();\n        per->state.store(IDLE, std::memory_order_relaxed);\n    }\n\n\n\n    /*\n     * Recovers from an incomplete transaction if needed\n     */\n    inline void recover() {\n        int lstate = per->state.load(std::memory_order_relaxed);\n        if (lstate == IDLE) {\n            return;\n        } else if (lstate == COPYING) {\n            printf(\"RomulusLR: Recovery from COPYING...\\n\");\n            copyMainToBack();\n        } else if (lstate == MUTATING) {\n            printf(\"RomulusLR: Recovery from MUTATING...\\n\");\n            copyBackToMain();\n        } else {\n            assert(false);\n            // ERROR: corrupted state\n        }\n        PFENCE();\n        per->state.store(IDLE, std::memory_order_relaxed);\n        return;\n    }\n\n\n    /*\n     * Same as begin/end transaction, but with a lambda.\n     * Calling abort_transaction() from within the lambda is not allowed.\n     */\n    template<typename R, class F>\n    R transaction(F&& func) {\n        begin_transaction();\n        R retval = func();\n        end_transaction();\n        return retval;\n    }\n\n    template<class F>\n    static void transaction(F&& func) {\n        gRomLR.begin_transaction();\n        func();\n        gRomLR.end_transaction();\n    }\n\n\n    /*\n     * Non static, thread-safe\n     * Progress: Blocking (starvation-free)\n     */\n    template<typename Func>\n    void ns_write_transaction(Func&& mutativeFunc) {\n        if (tl_nested_write_trans > 0) {\n            mutativeFunc();\n            return;\n        }\n        std::function<void()> myfunc = mutativeFunc;\n        int tid = ThreadRegistry::getTID();\n        // Add our mutation to the array of flat combining\n        fc[tid*CLPAD].store(&myfunc, std::memory_order_release);\n\n        // Lock writersMutex\n        while (true) {\n            int unlocked = UNLOCKED;\n            if (writersMutex.load() == UNLOCKED &&\n                writersMutex.compare_exchange_strong(unlocked, LOCKED)) break;\n            // Check if another thread executed my mutation\n            if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) return;\n            std::this_thread::yield();\n        }\n\n        bool somethingToDo = false;\n        const int maxTid = ThreadRegistry::getMaxThreads();\n        // Save a local copy of the flat combining array\n        std::function<void()>* lfc[maxTid];\n        for (int i = 0; i < maxTid; i++) {\n            lfc[i] = fc[i*CLPAD].load(std::memory_order_acquire);\n            if (lfc[i] != nullptr) somethingToDo = true;\n        }\n        // Check if there is at least one operation to apply\n        if (!somethingToDo) {\n            writersMutex.store(UNLOCKED, std::memory_order_release);\n            return;\n        }\n        ++tl_nested_write_trans;\n        per->state.store(MUTATING, std::memory_order_relaxed);\n        PWB(&per->state);\n        // One PFENCE() is enough for all user modifications because no ordering is needed between them.\n        PFENCE();\n        g_right = true;\n        // Readers can only see the changes after making sure they are persisted\n        leftRight.store(TRAVERSE_RIGHT);\n        tl_lrromulus = TRAVERSE_LEFT;\n        toggleVersionAndWait();  // This is a synchronize_rcu()\n        // Apply all mutativeFunc\n        for (int i = 0; i < maxTid; i++) {\n            if (lfc[i] == nullptr) continue;\n            (*lfc[i])();\n        }\n        apply_pwb(main_addr);\n        PFENCE();\n        per->state.store(COPYING, std::memory_order_relaxed);\n        PWB(&per->state);\n        // PSYNC() here to have ACID Durability on the mutations done to 'main' and make the change of state visible\n        PSYNC();\n        // Readers can only see the changes after making sure they are persisted\n        leftRight.store(TRAVERSE_LEFT);\n        toggleVersionAndWait();  // This is a synchronize_rcu()\n        g_right = false;\n        // After changing state to COPYING all applied mutativeFunc are visible and persisted\n        for (int i = 0; i < maxTid; i++) {\n            if (lfc[i] == nullptr) continue;\n            fc[i*CLPAD].store(nullptr, std::memory_order_release);\n        }\n        // Apply log, copying data from 'main' to 'back'\n        if (logEnabled) {\n            apply_log(main_addr, back_addr);\n            apply_pwb(back_addr);\n        } else {\n            copyMainToBack();\n\n            logEnabled = true;\n        }\n        clear_log();\n        log_size = 0;\n\n        PFENCE();\n        per->state.store(IDLE, std::memory_order_relaxed);\n        // unlock()\n        writersMutex.store(UNLOCKED, std::memory_order_release);\n        --tl_nested_write_trans;\n        //consistency_check();\n    }\n\n\n    /*\n     * Non-static\n     * Progress: Wait-Free Population Oblivious\n     */\n    template<typename Func>\n    void ns_read_transaction(Func&& readFunc) {\n        if (tl_nested_read_trans > 0) {\n            readFunc();\n            return;\n        }\n        int tid = ThreadRegistry::getTID();\n        const int localVI = versionIndex.load();\n        ++tl_nested_read_trans;\n        ri[localVI].arrive(tid);  // This is an rcu_read_lock()\n        int lr = leftRight.load();\n        if(lr!=tl_lrromulus) tl_lrromulus = lr;\n\n        readFunc();\n        ri[localVI].depart(tid);  // This is an rcu_read_unlock()\n        --tl_nested_read_trans;\n    }\n\n\n    template <typename T, typename... Args>\n    static T* alloc(Args&&... args) {\n        const RomulusLR& r = gRomLR;\n        void* addr = mspace_malloc(r.per->ms, sizeof(T));\n        assert(addr != 0);\n        T* ptr = new (addr) T(std::forward<Args>(args)...); // placement new\n        if (r.per->used_size < (uint8_t*)addr - r.main_addr + sizeof(T) + 128) {\n            r.per->used_size = (uint8_t*)addr - r.main_addr + sizeof(T) + 128;\n            PWB(&r.per->used_size);\n        }\n        return ptr;\n    }\n\n    template <typename T, typename... Args>\n    static T* tmNew(Args&&... args) {\n        const RomulusLR& r = gRomLR;\n        void* addr = mspace_malloc(r.per->ms, sizeof(T));\n        assert(addr != 0);\n        T* ptr = new (addr) T(std::forward<Args>(args)...); // placement new\n        if (r.per->used_size < (uint8_t*)addr - r.main_addr + sizeof(T) + 128) {\n            r.per->used_size = (uint8_t*)addr - r.main_addr + sizeof(T) + 128;\n            PWB(&r.per->used_size);\n        }\n        return ptr;\n    }\n\n    /*\n     * De-allocator\n     * Calls destructor of T and then reclaims the memory using Doug Lea's free\n     */\n    template<typename T>\n    static void free(T* obj) {\n        if (obj == nullptr) return;\n        obj->~T();\n        mspace_free(gRomLR.per->ms,obj);\n    }\n\n    template<typename T>\n    static void tmDelete(T* obj) {\n        if (obj == nullptr) return;\n        obj->~T();\n        mspace_free(gRomLR.per->ms,obj);\n    }\n\n    /* Allocator for C methods (like memcached) */\n    static void* pmalloc(size_t size) {\n        const RomulusLR& r = gRomLR;\n        void* addr = mspace_malloc(r.per->ms, size);\n        assert (addr != 0);\n        if (r.per->used_size < (uint8_t*)addr - r.main_addr + size + 128) {\n            r.per->used_size = (uint8_t*)addr - r.main_addr + size + 128;\n            PWB(&r.per->used_size);\n        }\n        return addr;\n    }\n\n    /* De-allocator for C methods (like memcached) */\n    static void pfree(void* ptr) {\n        return mspace_free(gRomLR.per->ms, ptr);\n    }\n\n    static void init() {\n    \tgRomLR.ns_init();\n    }\n\n    template<class F>\n    static void read_transaction(F&& func) {\n        gRomLR.ns_read_transaction(func);\n    }\n\n    template<class F>\n    static void write_transaction(F&& func) {\n        gRomLR.ns_write_transaction(func);\n    }\n\n    template<class F>\n    inline static void readTx(F&& func) {\n        gRomLR.ns_read_transaction(func);\n    }\n\n    template<class F>\n    inline static void updateTx(F&& func) {\n        gRomLR.ns_write_transaction(func);\n    }\n    \n    // TODO: Remove these two once we make CX have void transactions\n    template<typename R,class F>\n    inline static R readTx(F&& func) {\n        gRomLR.ns_read_transaction([&]() {func();});\n        return R{};\n    }\n    template<typename R,class F>\n    inline static R updateTx(F&& func) {\n        gRomLR.ns_write_transaction([&]() {func();});\n        return R{};\n    }\n    \n\n    /*\n     * Thread-safe. Compares the contents of 'main' and 'back'.\n     * This method MUST be called outside a transaction.\n     */\n    static bool consistency_check(void) {\n        if (tl_nested_write_trans > 0) {\n            printf(\"Warning: don't call consistency_check() inside a transaction\\n\");\n        } else {\n            while (true) {\n                int unlocked = UNLOCKED;\n                if (gRomLR.writersMutex.load() == UNLOCKED &&\n                    gRomLR.writersMutex.compare_exchange_strong(unlocked, LOCKED)) break;\n                std::this_thread::yield();\n            }\n            gRomLR.compareMainAndBack();\n            gRomLR.writersMutex.store(UNLOCKED, std::memory_order_release);\n        }\n        return true;\n    }\n};\n\n\n/*\n * Definition of persist<> type\n * In RomulusLR we interpose the loads and the stores\n */\ntemplate<typename T>\nstruct persist {\n    // Stores the actual value (left instance)\n    T val {};\n\n    persist() { }\n\n    persist(T initVal) {\n        pstore(initVal);\n    }\n\n    // Casting operator\n    operator T() {\n        return pload();\n    }\n\n    // Prefix increment operator: ++x\n    void operator++ () {\n        pstore(pload()+1);\n    }\n\n    // Prefix decrement operator: --x\n    void operator-- () {\n        pstore(pload()-1);\n    }\n\n    void operator++ (int) {\n        pstore(pload()+1);\n    }\n\n    void operator-- (int) {\n        pstore(pload()-1);\n    }\n\n    // Equals operator: first downcast to T and then compare\n    bool operator == (const T& otherval) const {\n        return pload() == otherval;\n    }\n\n    // Difference operator: first downcast to T and then compare\n    bool operator != (const T& otherval) const {\n        return pload() != otherval;\n    }\n\n    // Relational operators\n    bool operator < (const T& rhs) {\n        return pload() < rhs;\n    }\n    bool operator > (const T& rhs) {\n        return pload() > rhs;\n    }\n    bool operator <= (const T& rhs) {\n        return pload() <= rhs;\n    }\n    bool operator >= (const T& rhs) {\n        return pload() >= rhs;\n    }\n\n    T operator % (const T& rhs) {\n        return pload() % rhs;\n    }\n\n    // Operator arrow ->\n    T operator->() {\n        return pload();\n    }\n\n    // Operator &. See pload()\n    T* operator&() {\n\n       \tif(!g_right){\n\t\t\treturn &val;\n       \t}\n        if (tl_lrromulus == TRAVERSE_LEFT) return &val;\n        const uint8_t* valaddr = (uint8_t*)&val;\n        if(valaddr > g_main_addr && valaddr < g_main_addr_end) return reinterpret_cast<T*>( (uint8_t*)&val + g_main_size );\n        return &val;\n    }\n\n    // Copy constructor\n    persist<T>(const persist<T>& other) {\n        pstore(other.pload());\n    }\n\n    // Assignment operator from another persist<> instance\n    persist<T>& operator=(const persist<T>& other) {\n        pstore(other.pload());\n        return *this;\n    }\n\n    // Assignment operator from a value\n    persist<T>& operator=(T value) {\n        pstore(value);\n        return *this;\n    }\n\n    persist<T>& operator&=(T value) {\n        pstore(pload() & value);\n        return *this;\n    }\n\n    persist<T>& operator|=(T value) {\n        pstore(pload() | value);\n        return *this;\n    }\n    persist<T>& operator+=(T value) {\n        pstore(pload() + value);\n        return *this;\n    }\n    persist<T>& operator-=(T value) {\n        pstore(pload() - value);\n        return *this;\n    }\n\n    // Only modifies the left instance\n    inline void pstore(T newVal) {\n        val = newVal;\n        const uint8_t* valaddr = (uint8_t*)&val;\n        if (valaddr >= g_main_addr && valaddr < g_main_addr_end) {\n            //PWB(&val);\n            gRomLR.add_to_log(&val,sizeof(T));\n        }\n    }\n\n    // Muuuuahahahah!\n    // This is the most evil method in the entire repository\n    inline T pload() const {\n    \tif (!g_right || tl_lrromulus == TRAVERSE_LEFT) return val;\n        const uint8_t* valaddr = (uint8_t*)&val;\n        if (valaddr > g_main_addr && valaddr < g_main_addr_end) return *reinterpret_cast<T*>( (uint8_t*)&val + g_main_size );\n        return val;\n    }\n};\n\n\n} // end of namespace lrtm\n\n#endif /* _ROMULUS_LR_H_ */\n"
  },
  {
    "path": "ptms/romuluslr/malloc.cpp",
    "content": "/*\n  This is a version (aka dlmalloc) of malloc/free/realloc written by\n  Doug Lea and released to the public domain, as explained at\n  http://creativecommons.org/publicdomain/zero/1.0/ Send questions,\n  comments, complaints, performance data, etc to dl@cs.oswego.edu\n\n* Version 2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea\n   Note: There may be an updated version of this malloc obtainable at\n           ftp://gee.cs.oswego.edu/pub/misc/malloc.c\n         Check before installing!\n\n* Quickstart\n\n  This library is all in one file to simplify the most common usage:\n  ftp it, compile it (-O3), and link it into another program. All of\n  the compile-time options default to reasonable values for use on\n  most platforms.  You might later want to step through various\n  compile-time and dynamic tuning options.\n\n  For convenience, an include file for code using this malloc is at:\n     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h\n  You don't really need this .h file unless you call functions not\n  defined in your system include files.  The .h file contains only the\n  excerpts from this file needed for using this malloc on ANSI C/C++\n  systems, so long as you haven't changed compile-time options about\n  naming and tuning parameters.  If you do, then you can create your\n  own malloc.h that does include all settings by cutting at the point\n  indicated below. Note that you may already by default be using a C\n  library containing a malloc that is based on some version of this\n  malloc (for example in linux). You might still want to use the one\n  in this file to customize settings or to avoid overheads associated\n  with library versions.\n\n* Vital statistics:\n\n  Supported pointer/size_t representation:       4 or 8 bytes\n       size_t MUST be an unsigned type of the same width as\n       pointers. (If you are using an ancient system that declares\n       size_t as a signed type, or need it to be a different width\n       than pointers, you can use a previous release of this malloc\n       (e.g. 2.7.2) supporting these.)\n\n  Alignment:                                     8 bytes (minimum)\n       This suffices for nearly all current machines and C compilers.\n       However, you can define MALLOC_ALIGNMENT to be wider than this\n       if necessary (up to 128bytes), at the expense of using more space.\n\n  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)\n                                          8 or 16 bytes (if 8byte sizes)\n       Each malloced chunk has a hidden word of overhead holding size\n       and status information, and additional cross-check word\n       if FOOTERS is defined.\n\n  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)\n                          8-byte ptrs:  32 bytes    (including overhead)\n\n       Even a request for zero bytes (i.e., malloc(0)) returns a\n       pointer to something of the minimum allocatable size.\n       The maximum overhead wastage (i.e., number of extra bytes\n       allocated than were requested in malloc) is less than or equal\n       to the minimum size, except for requests >= mmap_threshold that\n       are serviced via mmap(), where the worst case wastage is about\n       32 bytes plus the remainder from a system page (the minimal\n       mmap unit); typically 4096 or 8192 bytes.\n\n  Security: static-safe; optionally more or less\n       The \"security\" of malloc refers to the ability of malicious\n       code to accentuate the effects of errors (for example, freeing\n       space that is not currently malloc'ed or overwriting past the\n       ends of chunks) in code that calls malloc.  This malloc\n       guarantees not to modify any memory locations below the base of\n       heap, i.e., static variables, even in the presence of usage\n       errors.  The routines additionally detect most improper frees\n       and reallocs.  All this holds as long as the static bookkeeping\n       for malloc itself is not corrupted by some other means.  This\n       is only one aspect of security -- these checks do not, and\n       cannot, detect all possible programming errors.\n\n       If FOOTERS is defined nonzero, then each allocated chunk\n       carries an additional check word to verify that it was malloced\n       from its space.  These check words are the same within each\n       execution of a program using malloc, but differ across\n       executions, so externally crafted fake chunks cannot be\n       freed. This improves security by rejecting frees/reallocs that\n       could corrupt heap memory, in addition to the checks preventing\n       writes to statics that are always on.  This may further improve\n       security at the expense of time and space overhead.  (Note that\n       FOOTERS may also be worth using with MSPACES.)\n\n       By default detected errors cause the program to abort (calling\n       \"abort()\"). You can override this to instead proceed past\n       errors by defining PROCEED_ON_ERROR.  In this case, a bad free\n       has no effect, and a malloc that encounters a bad address\n       caused by user overwrites will ignore the bad address by\n       dropping pointers and indices to all known memory. This may\n       be appropriate for programs that should continue if at all\n       possible in the face of programming errors, although they may\n       run out of memory because dropped memory is never reclaimed.\n\n       If you don't like either of these options, you can define\n       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything\n       else. And if if you are sure that your program using malloc has\n       no errors or vulnerabilities, you can define INSECURE to 1,\n       which might (or might not) provide a small performance improvement.\n\n       It is also possible to limit the maximum total allocatable\n       space, using malloc_set_footprint_limit. This is not\n       designed as a security feature in itself (calls to set limits\n       are not screened or privileged), but may be useful as one\n       aspect of a secure implementation.\n\n  Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero\n       When USE_LOCKS is defined, each public call to malloc, free,\n       etc is surrounded with a lock. By default, this uses a plain\n       pthread mutex, win32 critical section, or a spin-lock if if\n       available for the platform and not disabled by setting\n       USE_SPIN_LOCKS=0.  However, if USE_RECURSIVE_LOCKS is defined,\n       recursive versions are used instead (which are not required for\n       base functionality but may be needed in layered extensions).\n       Using a global lock is not especially fast, and can be a major\n       bottleneck.  It is designed only to provide minimal protection\n       in concurrent environments, and to provide a basis for\n       extensions.  If you are using malloc in a concurrent program,\n       consider instead using nedmalloc\n       (http://www.nedprod.com/programs/portable/nedmalloc/) or\n       ptmalloc (See http://www.malloc.de), which are derived from\n       versions of this malloc.\n\n  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP\n       This malloc can use unix sbrk or any emulation (invoked using\n       the CALL_MORECORE macro) and/or mmap/munmap or any emulation\n       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system\n       memory.  On most unix systems, it tends to work best if both\n       MORECORE and MMAP are enabled.  On Win32, it uses emulations\n       based on VirtualAlloc. It also uses common C library functions\n       like memset.\n\n  Compliance: I believe it is compliant with the Single Unix Specification\n       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably\n       others as well.\n\n* Overview of algorithms\n\n  This is not the fastest, most space-conserving, most portable, or\n  most tunable malloc ever written. However it is among the fastest\n  while also being among the most space-conserving, portable and\n  tunable.  Consistent balance across these factors results in a good\n  general-purpose allocator for malloc-intensive programs.\n\n  In most ways, this malloc is a best-fit allocator. Generally, it\n  chooses the best-fitting existing chunk for a request, with ties\n  broken in approximately least-recently-used order. (This strategy\n  normally maintains low fragmentation.) However, for requests less\n  than 256bytes, it deviates from best-fit when there is not an\n  exactly fitting available chunk by preferring to use space adjacent\n  to that used for the previous small request, as well as by breaking\n  ties in approximately most-recently-used order. (These enhance\n  locality of series of small allocations.)  And for very large requests\n  (>= 256Kb by default), it relies on system memory mapping\n  facilities, if supported.  (This helps avoid carrying around and\n  possibly fragmenting memory used only for large chunks.)\n\n  All operations (except malloc_stats and mallinfo) have execution\n  times that are bounded by a constant factor of the number of bits in\n  a size_t, not counting any clearing in calloc or copying in realloc,\n  or actions surrounding MORECORE and MMAP that have times\n  proportional to the number of non-contiguous regions returned by\n  system allocation routines, which is often just 1. In real-time\n  applications, you can optionally suppress segment traversals using\n  NO_SEGMENT_TRAVERSAL, which assures bounded execution even when\n  system allocators return non-contiguous spaces, at the typical\n  expense of carrying around more memory and increased fragmentation.\n\n  The implementation is not very modular and seriously overuses\n  macros. Perhaps someday all C compilers will do as good a job\n  inlining modular code as can now be done by brute-force expansion,\n  but now, enough of them seem not to.\n\n  Some compilers issue a lot of warnings about code that is\n  dead/unreachable only on some platforms, and also about intentional\n  uses of negation on unsigned types. All known cases of each can be\n  ignored.\n\n  For a longer but out of date high-level description, see\n     http://gee.cs.oswego.edu/dl/html/malloc.html\n\n* MSPACES\n  If MSPACES is defined, then in addition to malloc, free, etc.,\n  this file also defines mspace_malloc, mspace_free, etc. These\n  are versions of malloc routines that take an \"mspace\" argument\n  obtained using create_mspace, to control all internal bookkeeping.\n  If ONLY_MSPACES is defined, only these versions are compiled.\n  So if you would like to use this allocator for only some allocations,\n  and your system malloc for others, you can compile with\n  ONLY_MSPACES and then do something like...\n    static mspace mymspace = create_mspace(0,0); // for example\n    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)\n\n  (Note: If you only need one instance of an mspace, you can instead\n  use \"USE_DL_PREFIX\" to relabel the global malloc.)\n\n  You can similarly create thread-local allocators by storing\n  mspaces as thread-locals. For example:\n    static __thread mspace tlms = 0;\n    void*  tlmalloc(size_t bytes) {\n      if (tlms == 0) tlms = create_mspace(0, 0);\n      return mspace_malloc(tlms, bytes);\n    }\n    void  tlfree(void* mem) { mspace_free(tlms, mem); }\n\n  Unless FOOTERS is defined, each mspace is completely independent.\n  You cannot allocate from one and free to another (although\n  conformance is only weakly checked, so usage errors are not always\n  caught). If FOOTERS is defined, then each chunk carries around a tag\n  indicating its originating mspace, and frees are directed to their\n  originating spaces. Normally, this requires use of locks.\n\n -------------------------  Compile-time options ---------------------------\n\nBe careful in setting #define values for numerical constants of type\nsize_t. On some systems, literal values are not automatically extended\nto size_t precision unless they are explicitly casted. You can also\nuse the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.\n\nWIN32                    default: defined if _WIN32 defined\n  Defining WIN32 sets up defaults for MS environment and compilers.\n  Otherwise defaults are for unix. Beware that there seem to be some\n  cases where this malloc might not be a pure drop-in replacement for\n  Win32 malloc: Random-looking failures from Win32 GDI API's (eg;\n  SetDIBits()) may be due to bugs in some video driver implementations\n  when pixel buffers are malloc()ed, and the region spans more than\n  one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)\n  default granularity, pixel buffers may straddle virtual allocation\n  regions more often than when using the Microsoft allocator.  You can\n  avoid this by using VirtualAlloc() and VirtualFree() for all pixel\n  buffers rather than using malloc().  If this is not possible,\n  recompile this malloc with a larger DEFAULT_GRANULARITY. Note:\n  in cases where MSC and gcc (cygwin) are known to differ on WIN32,\n  conditions use _MSC_VER to distinguish them.\n\nDLMALLOC_EXPORT       default: extern\n  Defines how public APIs are declared. If you want to export via a\n  Windows DLL, you might define this as\n    #define DLMALLOC_EXPORT extern  __declspec(dllexport)\n  If you want a POSIX ELF shared object, you might use\n    #define DLMALLOC_EXPORT extern __attribute__((visibility(\"default\")))\n\nMALLOC_ALIGNMENT         default: (size_t)(2 * sizeof(void *))\n  Controls the minimum alignment for malloc'ed chunks.  It must be a\n  power of two and at least 8, even on machines for which smaller\n  alignments would suffice. It may be defined as larger than this\n  though. Note however that code and data structures are optimized for\n  the case of 8-byte alignment.\n\nMSPACES                  default: 0 (false)\n  If true, compile in support for independent allocation spaces.\n  This is only supported if HAVE_MMAP is true.\n\nONLY_MSPACES             default: 0 (false)\n  If true, only compile in mspace versions, not regular versions.\n\nUSE_LOCKS                default: 0 (false)\n  Causes each call to each public routine to be surrounded with\n  pthread or WIN32 mutex lock/unlock. (If set true, this can be\n  overridden on a per-mspace basis for mspace versions.) If set to a\n  non-zero value other than 1, locks are used, but their\n  implementation is left out, so lock functions must be supplied manually,\n  as described below.\n\nUSE_SPIN_LOCKS           default: 1 iff USE_LOCKS and spin locks available\n  If true, uses custom spin locks for locking. This is currently\n  supported only gcc >= 4.1, older gccs on x86 platforms, and recent\n  MS compilers.  Otherwise, posix locks or win32 critical sections are\n  used.\n\nUSE_RECURSIVE_LOCKS      default: not defined\n  If defined nonzero, uses recursive (aka reentrant) locks, otherwise\n  uses plain mutexes. This is not required for malloc proper, but may\n  be needed for layered allocators such as nedmalloc.\n\nLOCK_AT_FORK            default: not defined\n  If defined nonzero, performs pthread_atfork upon initialization\n  to initialize child lock while holding parent lock. The implementation\n  assumes that pthread locks (not custom locks) are being used. In other\n  cases, you may need to customize the implementation.\n\nFOOTERS                  default: 0\n  If true, provide extra checking and dispatching by placing\n  information in the footers of allocated chunks. This adds\n  space and time overhead.\n\nINSECURE                 default: 0\n  If true, omit checks for usage errors and heap space overwrites.\n\nUSE_DL_PREFIX            default: NOT defined\n  Causes compiler to prefix all public routines with the string 'dl'.\n  This can be useful when you only want to use this malloc in one part\n  of a program, using your regular system malloc elsewhere.\n\nMALLOC_INSPECT_ALL       default: NOT defined\n  If defined, compiles malloc_inspect_all and mspace_inspect_all, that\n  perform traversal of all heap space.  Unless access to these\n  functions is otherwise restricted, you probably do not want to\n  include them in secure implementations.\n\nABORT                    default: defined as abort()\n  Defines how to abort on failed checks.  On most systems, a failed\n  check cannot die with an \"assert\" or even print an informative\n  message, because the underlying print routines in turn call malloc,\n  which will fail again.  Generally, the best policy is to simply call\n  abort(). It's not very useful to do more than this because many\n  errors due to overwriting will show up as address faults (null, odd\n  addresses etc) rather than malloc-triggered checks, so will also\n  abort.  Also, most compilers know that abort() does not return, so\n  can better optimize code conditionally calling it.\n\nPROCEED_ON_ERROR           default: defined as 0 (false)\n  Controls whether detected bad addresses cause them to bypassed\n  rather than aborting. If set, detected bad arguments to free and\n  realloc are ignored. And all bookkeeping information is zeroed out\n  upon a detected overwrite of freed heap space, thus losing the\n  ability to ever return it from malloc again, but enabling the\n  application to proceed. If PROCEED_ON_ERROR is defined, the\n  static variable malloc_corruption_error_count is compiled in\n  and can be examined to see if errors have occurred. This option\n  generates slower code than the default abort policy.\n\nDEBUG                    default: NOT defined\n  The DEBUG setting is mainly intended for people trying to modify\n  this code or diagnose problems when porting to new platforms.\n  However, it may also be able to better isolate user errors than just\n  using runtime checks.  The assertions in the check routines spell\n  out in more detail the assumptions and invariants underlying the\n  algorithms.  The checking is fairly extensive, and will slow down\n  execution noticeably. Calling malloc_stats or mallinfo with DEBUG\n  set will attempt to check every non-mmapped allocated and free chunk\n  in the course of computing the summaries.\n\nABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)\n  Debugging assertion failures can be nearly impossible if your\n  version of the assert macro causes malloc to be called, which will\n  lead to a cascade of further failures, blowing the runtime stack.\n  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),\n  which will usually make debugging easier.\n\nMALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32\n  The action to take before \"return 0\" when malloc fails to be able to\n  return memory because there is none available.\n\nHAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES\n  True if this system supports sbrk or an emulation of it.\n\nMORECORE                  default: sbrk\n  The name of the sbrk-style system routine to call to obtain more\n  memory.  See below for guidance on writing custom MORECORE\n  functions. The type of the argument to sbrk/MORECORE varies across\n  systems.  It cannot be size_t, because it supports negative\n  arguments, so it is normally the signed type of the same width as\n  size_t (sometimes declared as \"intptr_t\").  It doesn't much matter\n  though. Internally, we only call it with arguments less than half\n  the max value of a size_t, which should work across all reasonable\n  possibilities, although sometimes generating compiler warnings.\n\nMORECORE_CONTIGUOUS       default: 1 (true) if HAVE_MORECORE\n  If true, take advantage of fact that consecutive calls to MORECORE\n  with positive arguments always return contiguous increasing\n  addresses.  This is true of unix sbrk. It does not hurt too much to\n  set it true anyway, since malloc copes with non-contiguities.\n  Setting it false when definitely non-contiguous saves time\n  and possibly wasted space it would take to discover this though.\n\nMORECORE_CANNOT_TRIM      default: NOT defined\n  True if MORECORE cannot release space back to the system when given\n  negative arguments. This is generally necessary only if you are\n  using a hand-crafted MORECORE function that cannot handle negative\n  arguments.\n\nNO_SEGMENT_TRAVERSAL       default: 0\n  If non-zero, suppresses traversals of memory segments\n  returned by either MORECORE or CALL_MMAP. This disables\n  merging of segments that are contiguous, and selectively\n  releasing them to the OS if unused, but bounds execution times.\n\nHAVE_MMAP                 default: 1 (true)\n  True if this system supports mmap or an emulation of it.  If so, and\n  HAVE_MORECORE is not true, MMAP is used for all system\n  allocation. If set and HAVE_MORECORE is true as well, MMAP is\n  primarily used to directly allocate very large blocks. It is also\n  used as a backup strategy in cases where MORECORE fails to provide\n  space from system. Note: A single call to MUNMAP is assumed to be\n  able to unmap memory that may have be allocated using multiple calls\n  to MMAP, so long as they are adjacent.\n\nHAVE_MREMAP               default: 1 on linux, else 0\n  If true realloc() uses mremap() to re-allocate large blocks and\n  extend or shrink allocation spaces.\n\nMMAP_CLEARS               default: 1 except on WINCE.\n  True if mmap clears memory so calloc doesn't need to. This is true\n  for standard unix mmap using /dev/zero and on WIN32 except for WINCE.\n\nUSE_BUILTIN_FFS            default: 0 (i.e., not used)\n  Causes malloc to use the builtin ffs() function to compute indices.\n  Some compilers may recognize and intrinsify ffs to be faster than the\n  supplied C version. Also, the case of x86 using gcc is special-cased\n  to an asm instruction, so is already as fast as it can be, and so\n  this setting has no effect. Similarly for Win32 under recent MS compilers.\n  (On most x86s, the asm version is only slightly faster than the C version.)\n\nmalloc_getpagesize         default: derive from system includes, or 4096.\n  The system page size. To the extent possible, this malloc manages\n  memory from the system in page-size units.  This may be (and\n  usually is) a function rather than a constant. This is ignored\n  if WIN32, where page size is determined using getSystemInfo during\n  initialization.\n\nUSE_DEV_RANDOM             default: 0 (i.e., not used)\n  Causes malloc to use /dev/random to initialize secure magic seed for\n  stamping footers. Otherwise, the current time is used.\n\nNO_MALLINFO                default: 0\n  If defined, don't compile \"mallinfo\". This can be a simple way\n  of dealing with mismatches between system declarations and\n  those in this file.\n\nMALLINFO_FIELD_TYPE        default: size_t\n  The type of the fields in the mallinfo struct. This was originally\n  defined as \"int\" in SVID etc, but is more usefully defined as\n  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set\n\nNO_MALLOC_STATS            default: 0\n  If defined, don't compile \"malloc_stats\". This avoids calls to\n  fprintf and bringing in stdio dependencies you might not want.\n\nREALLOC_ZERO_BYTES_FREES    default: not defined\n  This should be set if a call to realloc with zero bytes should\n  be the same as a call to free. Some people think it should. Otherwise,\n  since this malloc returns a unique pointer for malloc(0), so does\n  realloc(p, 0).\n\nLACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H\nLACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H\nLACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H  default: NOT defined unless on WIN32\n  Define these if your system does not have these header files.\n  You might need to manually insert some of the declarations they provide.\n\nDEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,\n                                system_info.dwAllocationGranularity in WIN32,\n                                otherwise 64K.\n      Also settable using mallopt(M_GRANULARITY, x)\n  The unit for allocating and deallocating memory from the system.  On\n  most systems with contiguous MORECORE, there is no reason to\n  make this more than a page. However, systems with MMAP tend to\n  either require or encourage larger granularities.  You can increase\n  this value to prevent system allocation functions to be called so\n  often, especially if they are slow.  The value must be at least one\n  page and must be a power of two.  Setting to 0 causes initialization\n  to either page size or win32 region size.  (Note: In previous\n  versions of malloc, the equivalent of this option was called\n  \"TOP_PAD\")\n\nDEFAULT_TRIM_THRESHOLD    default: 2MB\n      Also settable using mallopt(M_TRIM_THRESHOLD, x)\n  The maximum amount of unused top-most memory to keep before\n  releasing via malloc_trim in free().  Automatic trimming is mainly\n  useful in long-lived programs using contiguous MORECORE.  Because\n  trimming via sbrk can be slow on some systems, and can sometimes be\n  wasteful (in cases where programs immediately afterward allocate\n  more large chunks) the value should be high enough so that your\n  overall system performance would improve by releasing this much\n  memory.  As a rough guide, you might set to a value close to the\n  average size of a process (program) running on your system.\n  Releasing this much memory would allow such a process to run in\n  memory.  Generally, it is worth tuning trim thresholds when a\n  program undergoes phases where several large chunks are allocated\n  and released in ways that can reuse each other's storage, perhaps\n  mixed with phases where there are no such chunks at all. The trim\n  value must be greater than page size to have any useful effect.  To\n  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick\n  some people use of mallocing a huge space and then freeing it at\n  program startup, in an attempt to reserve system memory, doesn't\n  have the intended effect under automatic trimming, since that memory\n  will immediately be returned to the system.\n\nDEFAULT_MMAP_THRESHOLD       default: 256K\n      Also settable using mallopt(M_MMAP_THRESHOLD, x)\n  The request size threshold for using MMAP to directly service a\n  request. Requests of at least this size that cannot be allocated\n  using already-existing space will be serviced via mmap.  (If enough\n  normal freed space already exists it is used instead.)  Using mmap\n  segregates relatively large chunks of memory so that they can be\n  individually obtained and released from the host system. A request\n  serviced through mmap is never reused by any other request (at least\n  not directly; the system may just so happen to remap successive\n  requests to the same locations).  Segregating space in this way has\n  the benefits that: Mmapped space can always be individually released\n  back to the system, which helps keep the system level memory demands\n  of a long-lived program low.  Also, mapped memory doesn't become\n  `locked' between other chunks, as can happen with normally allocated\n  chunks, which means that even trimming via malloc_trim would not\n  release them.  However, it has the disadvantage that the space\n  cannot be reclaimed, consolidated, and then used to service later\n  requests, as happens with normal chunks.  The advantages of mmap\n  nearly always outweigh disadvantages for \"large\" chunks, but the\n  value of \"large\" may vary across systems.  The default is an\n  empirically derived value that works well in most systems. You can\n  disable mmap by setting to MAX_SIZE_T.\n\nMAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP\n  The number of consolidated frees between checks to release\n  unused segments when freeing. When using non-contiguous segments,\n  especially with multiple mspaces, checking only for topmost space\n  doesn't always suffice to trigger trimming. To compensate for this,\n  free() will, with a period of MAX_RELEASE_CHECK_RATE (or the\n  current number of segments, if greater) try to release unused\n  segments to the OS when freeing chunks that result in\n  consolidation. The best value for this parameter is a compromise\n  between slowing down frees with relatively costly checks that\n  rarely trigger versus holding on to unused memory. To effectively\n  disable, set to MAX_SIZE_T. This may lead to a very slight speed\n  improvement at the expense of carrying around more memory.\n*/\n#include \"RomulusLR.hpp\"\n//modification by Andreia\n#define ONLY_MSPACES 1\n\n/* Version identifier to allow people to support multiple versions */\n#ifndef DLMALLOC_VERSION\n#define DLMALLOC_VERSION 20806\n#endif /* DLMALLOC_VERSION */\n\n#ifndef DLMALLOC_EXPORT\n#define DLMALLOC_EXPORT extern\n#endif\n\n#ifndef WIN32\n#ifdef _WIN32\n#define WIN32 1\n#endif  /* _WIN32 */\n#ifdef _WIN32_WCE\n#define LACKS_FCNTL_H\n#define WIN32 1\n#endif /* _WIN32_WCE */\n#endif  /* WIN32 */\n#ifdef WIN32\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <tchar.h>\n#define HAVE_MMAP 1\n#define HAVE_MORECORE 0\n#define LACKS_UNISTD_H\n#define LACKS_SYS_PARAM_H\n#define LACKS_SYS_MMAN_H\n#define LACKS_STRING_H\n#define LACKS_STRINGS_H\n#define LACKS_SYS_TYPES_H\n#define LACKS_ERRNO_H\n#define LACKS_SCHED_H\n#ifndef MALLOC_FAILURE_ACTION\n#define MALLOC_FAILURE_ACTION\n#endif /* MALLOC_FAILURE_ACTION */\n#ifndef MMAP_CLEARS\n#ifdef _WIN32_WCE /* WINCE reportedly does not clear */\n#define MMAP_CLEARS 0\n#else\n#define MMAP_CLEARS 1\n#endif /* _WIN32_WCE */\n#endif /*MMAP_CLEARS */\n#endif  /* WIN32 */\n\n#if defined(DARWIN) || defined(_DARWIN)\n/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */\n#ifndef HAVE_MORECORE\n#define HAVE_MORECORE 0\n#define HAVE_MMAP 1\n/* OSX allocators provide 16 byte alignment */\n#ifndef MALLOC_ALIGNMENT\n#define MALLOC_ALIGNMENT ((size_t)16U)\n#endif\n#endif  /* HAVE_MORECORE */\n#endif  /* DARWIN */\n\n#ifndef LACKS_SYS_TYPES_H\n#include <sys/types.h>  /* For size_t */\n#endif  /* LACKS_SYS_TYPES_H */\n\n/* The maximum possible size_t value has all bits set */\n#define MAX_SIZE_T           (~(size_t)0)\n\n#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */\n#define USE_LOCKS  ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \\\n                    (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0))\n#endif /* USE_LOCKS */\n\n#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */\n#if ((defined(__GNUC__) &&                                              \\\n      ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) ||      \\\n       defined(__i386__) || defined(__x86_64__))) ||                    \\\n     (defined(_MSC_VER) && _MSC_VER>=1310))\n#ifndef USE_SPIN_LOCKS\n#define USE_SPIN_LOCKS 1\n#endif /* USE_SPIN_LOCKS */\n#elif USE_SPIN_LOCKS\n#error \"USE_SPIN_LOCKS defined without implementation\"\n#endif /* ... locks available... */\n#elif !defined(USE_SPIN_LOCKS)\n#define USE_SPIN_LOCKS 0\n#endif /* USE_LOCKS */\n\n#ifndef ONLY_MSPACES\n#define ONLY_MSPACES 0\n#endif  /* ONLY_MSPACES */\n#ifndef MSPACES\n#if ONLY_MSPACES\n#define MSPACES 1\n#else   /* ONLY_MSPACES */\n#define MSPACES 0\n#endif  /* ONLY_MSPACES */\n#endif  /* MSPACES */\n#ifndef MALLOC_ALIGNMENT\n#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))\n#endif  /* MALLOC_ALIGNMENT */\n#ifndef FOOTERS\n#define FOOTERS 0\n#endif  /* FOOTERS */\n#ifndef ABORT\n#define ABORT  abort()\n#endif  /* ABORT */\n#ifndef ABORT_ON_ASSERT_FAILURE\n#define ABORT_ON_ASSERT_FAILURE 1\n#endif  /* ABORT_ON_ASSERT_FAILURE */\n#ifndef PROCEED_ON_ERROR\n#define PROCEED_ON_ERROR 0\n#endif  /* PROCEED_ON_ERROR */\n\n#ifndef INSECURE\n#define INSECURE 0\n#endif  /* INSECURE */\n#ifndef MALLOC_INSPECT_ALL\n#define MALLOC_INSPECT_ALL 0\n#endif  /* MALLOC_INSPECT_ALL */\n#ifndef HAVE_MMAP\n#define HAVE_MMAP 1\n#endif  /* HAVE_MMAP */\n#ifndef MMAP_CLEARS\n#define MMAP_CLEARS 1\n#endif  /* MMAP_CLEARS */\n#ifndef HAVE_MREMAP\n#ifdef linux\n#define HAVE_MREMAP 1\n#define _GNU_SOURCE /* Turns on mremap() definition */\n#else   /* linux */\n#define HAVE_MREMAP 0\n#endif  /* linux */\n#endif  /* HAVE_MREMAP */\n#ifndef MALLOC_FAILURE_ACTION\n#define MALLOC_FAILURE_ACTION  errno = ENOMEM;\n#endif  /* MALLOC_FAILURE_ACTION */\n#ifndef HAVE_MORECORE\n#if ONLY_MSPACES\n#define HAVE_MORECORE 0\n#else   /* ONLY_MSPACES */\n#define HAVE_MORECORE 1\n#endif  /* ONLY_MSPACES */\n#endif  /* HAVE_MORECORE */\n#if !HAVE_MORECORE\n#define MORECORE_CONTIGUOUS 0\n#else   /* !HAVE_MORECORE */\n#define MORECORE_DEFAULT sbrk\n#ifndef MORECORE_CONTIGUOUS\n#define MORECORE_CONTIGUOUS 1\n#endif  /* MORECORE_CONTIGUOUS */\n#endif  /* HAVE_MORECORE */\n#ifndef DEFAULT_GRANULARITY\n#if (MORECORE_CONTIGUOUS || defined(WIN32))\n#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */\n#else   /* MORECORE_CONTIGUOUS */\n#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)\n#endif  /* MORECORE_CONTIGUOUS */\n#endif  /* DEFAULT_GRANULARITY */\n#ifndef DEFAULT_TRIM_THRESHOLD\n#ifndef MORECORE_CANNOT_TRIM\n#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)\n#else   /* MORECORE_CANNOT_TRIM */\n#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T\n#endif  /* MORECORE_CANNOT_TRIM */\n#endif  /* DEFAULT_TRIM_THRESHOLD */\n#ifndef DEFAULT_MMAP_THRESHOLD\n#if HAVE_MMAP\n#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)\n#else   /* HAVE_MMAP */\n#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T\n#endif  /* HAVE_MMAP */\n#endif  /* DEFAULT_MMAP_THRESHOLD */\n#ifndef MAX_RELEASE_CHECK_RATE\n#if HAVE_MMAP\n#define MAX_RELEASE_CHECK_RATE 4095\n#else\n#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T\n#endif /* HAVE_MMAP */\n#endif /* MAX_RELEASE_CHECK_RATE */\n#ifndef USE_BUILTIN_FFS\n#define USE_BUILTIN_FFS 0\n#endif  /* USE_BUILTIN_FFS */\n#ifndef USE_DEV_RANDOM\n#define USE_DEV_RANDOM 0\n#endif  /* USE_DEV_RANDOM */\n#ifndef NO_MALLINFO\n#define NO_MALLINFO 0\n#endif  /* NO_MALLINFO */\n#ifndef MALLINFO_FIELD_TYPE\n#define MALLINFO_FIELD_TYPE size_t\n#endif  /* MALLINFO_FIELD_TYPE */\n#ifndef NO_MALLOC_STATS\n#define NO_MALLOC_STATS 0\n#endif  /* NO_MALLOC_STATS */\n#ifndef NO_SEGMENT_TRAVERSAL\n#define NO_SEGMENT_TRAVERSAL 0\n#endif /* NO_SEGMENT_TRAVERSAL */\n\n/*\n  mallopt tuning options.  SVID/XPG defines four standard parameter\n  numbers for mallopt, normally defined in malloc.h.  None of these\n  are used in this malloc, so setting them has no effect. But this\n  malloc does support the following options.\n*/\n\n#define M_TRIM_THRESHOLD     (-1)\n#define M_GRANULARITY        (-2)\n#define M_MMAP_THRESHOLD     (-3)\n\n/* ------------------------ Mallinfo declarations ------------------------ */\n\n#if !NO_MALLINFO\n/*\n  This version of malloc supports the standard SVID/XPG mallinfo\n  routine that returns a struct containing usage properties and\n  statistics. It should work on any system that has a\n  /usr/include/malloc.h defining struct mallinfo.  The main\n  declaration needed is the mallinfo struct that is returned (by-copy)\n  by mallinfo().  The malloinfo struct contains a bunch of fields that\n  are not even meaningful in this version of malloc.  These fields are\n  are instead filled by mallinfo() with other numbers that might be of\n  interest.\n\n  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a\n  /usr/include/malloc.h file that includes a declaration of struct\n  mallinfo.  If so, it is included; else a compliant version is\n  declared below.  These must be precisely the same for mallinfo() to\n  work.  The original SVID version of this struct, defined on most\n  systems with mallinfo, declares all fields as ints. But some others\n  define as unsigned long. If your system defines the fields using a\n  type of different width than listed here, you MUST #include your\n  system version and #define HAVE_USR_INCLUDE_MALLOC_H.\n*/\n\n/* #define HAVE_USR_INCLUDE_MALLOC_H */\n\n#ifdef HAVE_USR_INCLUDE_MALLOC_H\n#include \"/usr/include/malloc.h\"\n#else /* HAVE_USR_INCLUDE_MALLOC_H */\n#ifndef STRUCT_MALLINFO_DECLARED\n/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */\n#define _STRUCT_MALLINFO\n#define STRUCT_MALLINFO_DECLARED 1\nstruct mallinfo {\n  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */\n  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */\n  MALLINFO_FIELD_TYPE smblks;   /* always 0 */\n  MALLINFO_FIELD_TYPE hblks;    /* always 0 */\n  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */\n  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */\n  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */\n  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */\n  MALLINFO_FIELD_TYPE fordblks; /* total free space */\n  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */\n};\n#endif /* STRUCT_MALLINFO_DECLARED */\n#endif /* HAVE_USR_INCLUDE_MALLOC_H */\n#endif /* NO_MALLINFO */\n\n/*\n  Try to persuade compilers to inline. The most critical functions for\n  inlining are defined as macros, so these aren't used for them.\n*/\n\n#ifndef FORCEINLINE\n  #if defined(__GNUC__)\n#define FORCEINLINE __inline __attribute__ ((always_inline))\n  #elif defined(_MSC_VER)\n    #define FORCEINLINE __forceinline\n  #endif\n#endif\n#ifndef NOINLINE\n  #if defined(__GNUC__)\n    #define NOINLINE __attribute__ ((noinline))\n  #elif defined(_MSC_VER)\n    #define NOINLINE __declspec(noinline)\n  #else\n    #define NOINLINE\n  #endif\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#ifndef FORCEINLINE\n #define FORCEINLINE inline\n#endif\n#endif /* __cplusplus */\n#ifndef FORCEINLINE\n #define FORCEINLINE\n#endif\n\n#if !ONLY_MSPACES\n\n/* ------------------- Declarations of public routines ------------------- */\n\n#ifndef USE_DL_PREFIX\n#define dlcalloc               calloc\n#define dlfree                 free\n#define dlmalloc               malloc\n#define dlmemalign             memalign\n#define dlposix_memalign       posix_memalign\n#define dlrealloc              realloc\n#define dlrealloc_in_place     realloc_in_place\n#define dlvalloc               valloc\n#define dlpvalloc              pvalloc\n#define dlmallinfo             mallinfo\n#define dlmallopt              mallopt\n#define dlmalloc_trim          malloc_trim\n#define dlmalloc_stats         malloc_stats\n#define dlmalloc_usable_size   malloc_usable_size\n#define dlmalloc_footprint     malloc_footprint\n#define dlmalloc_max_footprint malloc_max_footprint\n#define dlmalloc_footprint_limit malloc_footprint_limit\n#define dlmalloc_set_footprint_limit malloc_set_footprint_limit\n#define dlmalloc_inspect_all   malloc_inspect_all\n#define dlindependent_calloc   independent_calloc\n#define dlindependent_comalloc independent_comalloc\n#define dlbulk_free            bulk_free\n#endif /* USE_DL_PREFIX */\n/*\n  malloc(size_t n)\n  Returns a pointer to a newly allocated chunk of at least n bytes, or\n  null if no space is available, in which case errno is set to ENOMEM\n  on ANSI C systems.\n\n  If n is zero, malloc returns a minimum-sized chunk. (The minimum\n  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit\n  systems.)  Note that size_t is an unsigned type, so calls with\n  arguments that would be negative if signed are interpreted as\n  requests for huge amounts of space, which will often fail. The\n  maximum supported value of n differs across systems, but is in all\n  cases less than the maximum representable value of a size_t.\n*/\nDLMALLOC_EXPORT void* dlmalloc(size_t);\n\n/*\n  free(void* p)\n  Releases the chunk of memory pointed to by p, that had been previously\n  allocated using malloc or a related routine such as realloc.\n  It has no effect if p is null. If p was not malloced or already\n  freed, free(p) will by default cause the current program to abort.\n*/\nDLMALLOC_EXPORT void  dlfree(void*);\n\n/*\n  calloc(size_t n_elements, size_t element_size);\n  Returns a pointer to n_elements * element_size bytes, with all locations\n  set to zero.\n*/\nDLMALLOC_EXPORT void* dlcalloc(size_t, size_t);\n\n/*\n  realloc(void* p, size_t n)\n  Returns a pointer to a chunk of size n that contains the same data\n  as does chunk p up to the minimum of (n, p's size) bytes, or null\n  if no space is available.\n\n  The returned pointer may or may not be the same as p. The algorithm\n  prefers extending p in most cases when possible, otherwise it\n  employs the equivalent of a malloc-copy-free sequence.\n\n  If p is null, realloc is equivalent to malloc.\n\n  If space is not available, realloc returns null, errno is set (if on\n  ANSI) and p is NOT freed.\n\n  if n is for fewer bytes than already held by p, the newly unused\n  space is lopped off and freed if possible.  realloc with a size\n  argument of zero (re)allocates a minimum-sized chunk.\n\n  The old unix realloc convention of allowing the last-free'd chunk\n  to be used as an argument to realloc is not supported.\n*/\nDLMALLOC_EXPORT void* dlrealloc(void*, size_t);\n\n/*\n  realloc_in_place(void* p, size_t n)\n  Resizes the space allocated for p to size n, only if this can be\n  done without moving p (i.e., only if there is adjacent space\n  available if n is greater than p's current allocated size, or n is\n  less than or equal to p's size). This may be used instead of plain\n  realloc if an alternative allocation strategy is needed upon failure\n  to expand space; for example, reallocation of a buffer that must be\n  memory-aligned or cleared. You can use realloc_in_place to trigger\n  these alternatives only when needed.\n\n  Returns p if successful; otherwise null.\n*/\nDLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);\n\n/*\n  memalign(size_t alignment, size_t n);\n  Returns a pointer to a newly allocated chunk of n bytes, aligned\n  in accord with the alignment argument.\n\n  The alignment argument should be a power of two. If the argument is\n  not a power of two, the nearest greater power is used.\n  8-byte alignment is guaranteed by normal malloc calls, so don't\n  bother calling memalign with an argument of 8 or less.\n\n  Overreliance on memalign is a sure way to fragment space.\n*/\nDLMALLOC_EXPORT void* dlmemalign(size_t, size_t);\n\n/*\n  int posix_memalign(void** pp, size_t alignment, size_t n);\n  Allocates a chunk of n bytes, aligned in accord with the alignment\n  argument. Differs from memalign only in that it (1) assigns the\n  allocated memory to *pp rather than returning it, (2) fails and\n  returns EINVAL if the alignment is not a power of two (3) fails and\n  returns ENOMEM if memory cannot be allocated.\n*/\nDLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);\n\n/*\n  valloc(size_t n);\n  Equivalent to memalign(pagesize, n), where pagesize is the page\n  size of the system. If the pagesize is unknown, 4096 is used.\n*/\nDLMALLOC_EXPORT void* dlvalloc(size_t);\n\n/*\n  mallopt(int parameter_number, int parameter_value)\n  Sets tunable parameters The format is to provide a\n  (parameter-number, parameter-value) pair.  mallopt then sets the\n  corresponding parameter to the argument value if it can (i.e., so\n  long as the value is meaningful), and returns 1 if successful else\n  0.  To workaround the fact that mallopt is specified to use int,\n  not size_t parameters, the value -1 is specially treated as the\n  maximum unsigned size_t value.\n\n  SVID/XPG/ANSI defines four standard param numbers for mallopt,\n  normally defined in malloc.h.  None of these are use in this malloc,\n  so setting them has no effect. But this malloc also supports other\n  options in mallopt. See below for details.  Briefly, supported\n  parameters are as follows (listed defaults are for \"typical\"\n  configurations).\n\n  Symbol            param #  default    allowed param values\n  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1 disables)\n  M_GRANULARITY        -2     page size   any power of 2 >= page size\n  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)\n*/\nDLMALLOC_EXPORT int dlmallopt(int, int);\n\n/*\n  malloc_footprint();\n  Returns the number of bytes obtained from the system.  The total\n  number of bytes allocated by malloc, realloc etc., is less than this\n  value. Unlike mallinfo, this function returns only a precomputed\n  result, so can be called frequently to monitor memory consumption.\n  Even if locks are otherwise defined, this function does not use them,\n  so results might not be up to date.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_footprint(void);\n\n/*\n  malloc_max_footprint();\n  Returns the maximum number of bytes obtained from the system. This\n  value will be greater than current footprint if deallocated space\n  has been reclaimed by the system. The peak number of bytes allocated\n  by malloc, realloc etc., is less than this value. Unlike mallinfo,\n  this function returns only a precomputed result, so can be called\n  frequently to monitor memory consumption.  Even if locks are\n  otherwise defined, this function does not use them, so results might\n  not be up to date.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);\n\n/*\n  malloc_footprint_limit();\n  Returns the number of bytes that the heap is allowed to obtain from\n  the system, returning the last value returned by\n  malloc_set_footprint_limit, or the maximum size_t value if\n  never set. The returned value reflects a permission. There is no\n  guarantee that this number of bytes can actually be obtained from\n  the system.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_footprint_limit();\n\n/*\n  malloc_set_footprint_limit();\n  Sets the maximum number of bytes to obtain from the system, causing\n  failure returns from malloc and related functions upon attempts to\n  exceed this value. The argument value may be subject to page\n  rounding to an enforceable limit; this actual value is returned.\n  Using an argument of the maximum possible size_t effectively\n  disables checks. If the argument is less than or equal to the\n  current malloc_footprint, then all future allocations that require\n  additional system memory will fail. However, invocation cannot\n  retroactively deallocate existing used memory.\n*/\nDLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);\n\n#if MALLOC_INSPECT_ALL\n/*\n  malloc_inspect_all(void(*handler)(void *start,\n                                    void *end,\n                                    size_t used_bytes,\n                                    void* callback_arg),\n                      void* arg);\n  Traverses the heap and calls the given handler for each managed\n  region, skipping all bytes that are (or may be) used for bookkeeping\n  purposes.  Traversal does not include include chunks that have been\n  directly memory mapped. Each reported region begins at the start\n  address, and continues up to but not including the end address.  The\n  first used_bytes of the region contain allocated data. If\n  used_bytes is zero, the region is unallocated. The handler is\n  invoked with the given callback argument. If locks are defined, they\n  are held during the entire traversal. It is a bad idea to invoke\n  other malloc functions from within the handler.\n\n  For example, to count the number of in-use chunks with size greater\n  than 1000, you could write:\n  static int count = 0;\n  void count_chunks(void* start, void* end, size_t used, void* arg) {\n    if (used >= 1000) ++count;\n  }\n  then:\n    malloc_inspect_all(count_chunks, NULL);\n\n  malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.\n*/\nDLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),\n                           void* arg);\n\n#endif /* MALLOC_INSPECT_ALL */\n\n#if !NO_MALLINFO\n/*\n  mallinfo()\n  Returns (by copy) a struct containing various summary statistics:\n\n  arena:     current total non-mmapped bytes allocated from system\n  ordblks:   the number of free chunks\n  smblks:    always zero.\n  hblks:     current number of mmapped regions\n  hblkhd:    total bytes held in mmapped regions\n  usmblks:   the maximum total allocated space. This will be greater\n                than current total if trimming has occurred.\n  fsmblks:   always zero\n  uordblks:  current total allocated space (normal or mmapped)\n  fordblks:  total free space\n  keepcost:  the maximum number of bytes that could ideally be released\n               back to system via malloc_trim. (\"ideally\" means that\n               it ignores page restrictions etc.)\n\n  Because these fields are ints, but internal bookkeeping may\n  be kept as longs, the reported values may wrap around zero and\n  thus be inaccurate.\n*/\nDLMALLOC_EXPORT struct mallinfo dlmallinfo(void);\n#endif /* NO_MALLINFO */\n\n/*\n  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);\n\n  independent_calloc is similar to calloc, but instead of returning a\n  single cleared space, it returns an array of pointers to n_elements\n  independent elements that can hold contents of size elem_size, each\n  of which starts out cleared, and can be independently freed,\n  realloc'ed etc. The elements are guaranteed to be adjacently\n  allocated (this is not guaranteed to occur with multiple callocs or\n  mallocs), which may also improve cache locality in some\n  applications.\n\n  The \"chunks\" argument is optional (i.e., may be null, which is\n  probably the most typical usage). If it is null, the returned array\n  is itself dynamically allocated and should also be freed when it is\n  no longer needed. Otherwise, the chunks array must be of at least\n  n_elements in length. It is filled in with the pointers to the\n  chunks.\n\n  In either case, independent_calloc returns this pointer array, or\n  null if the allocation failed.  If n_elements is zero and \"chunks\"\n  is null, it returns a chunk representing an array with zero elements\n  (which should be freed if not wanted).\n\n  Each element must be freed when it is no longer needed. This can be\n  done all at once using bulk_free.\n\n  independent_calloc simplifies and speeds up implementations of many\n  kinds of pools.  It may also be useful when constructing large data\n  structures that initially have a fixed number of fixed-sized nodes,\n  but the number is not known at compile time, and some of the nodes\n  may later need to be freed. For example:\n\n  struct Node { int item; struct Node* next; };\n\n  struct Node* build_list() {\n    struct Node** pool;\n    int n = read_number_of_nodes_needed();\n    if (n <= 0) return 0;\n    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);\n    if (pool == 0) die();\n    // organize into a linked list...\n    struct Node* first = pool[0];\n    for (i = 0; i < n-1; ++i)\n      pool[i]->next = pool[i+1];\n    free(pool);     // Can now free the array (or not, if it is needed later)\n    return first;\n  }\n*/\nDLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);\n\n/*\n  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);\n\n  independent_comalloc allocates, all at once, a set of n_elements\n  chunks with sizes indicated in the \"sizes\" array.    It returns\n  an array of pointers to these elements, each of which can be\n  independently freed, realloc'ed etc. The elements are guaranteed to\n  be adjacently allocated (this is not guaranteed to occur with\n  multiple callocs or mallocs), which may also improve cache locality\n  in some applications.\n\n  The \"chunks\" argument is optional (i.e., may be null). If it is null\n  the returned array is itself dynamically allocated and should also\n  be freed when it is no longer needed. Otherwise, the chunks array\n  must be of at least n_elements in length. It is filled in with the\n  pointers to the chunks.\n\n  In either case, independent_comalloc returns this pointer array, or\n  null if the allocation failed.  If n_elements is zero and chunks is\n  null, it returns a chunk representing an array with zero elements\n  (which should be freed if not wanted).\n\n  Each element must be freed when it is no longer needed. This can be\n  done all at once using bulk_free.\n\n  independent_comallac differs from independent_calloc in that each\n  element may have a different size, and also that it does not\n  automatically clear elements.\n\n  independent_comalloc can be used to speed up allocation in cases\n  where several structs or objects must always be allocated at the\n  same time.  For example:\n\n  struct Head { ... }\n  struct Foot { ... }\n\n  void send_message(char* msg) {\n    int msglen = strlen(msg);\n    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };\n    void* chunks[3];\n    if (independent_comalloc(3, sizes, chunks) == 0)\n      die();\n    struct Head* head = (struct Head*)(chunks[0]);\n    char*        body = (char*)(chunks[1]);\n    struct Foot* foot = (struct Foot*)(chunks[2]);\n    // ...\n  }\n\n  In general though, independent_comalloc is worth using only for\n  larger values of n_elements. For small values, you probably won't\n  detect enough difference from series of malloc calls to bother.\n\n  Overuse of independent_comalloc can increase overall memory usage,\n  since it cannot reuse existing noncontiguous small chunks that\n  might be available for some of the elements.\n*/\nDLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);\n\n/*\n  bulk_free(void* array[], size_t n_elements)\n  Frees and clears (sets to null) each non-null pointer in the given\n  array.  This is likely to be faster than freeing them one-by-one.\n  If footers are used, pointers that have been allocated in different\n  mspaces are not freed or cleared, and the count of all such pointers\n  is returned.  For large arrays of pointers with poor locality, it\n  may be worthwhile to sort this array before calling bulk_free.\n*/\nDLMALLOC_EXPORT size_t  dlbulk_free(void**, size_t n_elements);\n\n/*\n  pvalloc(size_t n);\n  Equivalent to valloc(minimum-page-that-holds(n)), that is,\n  round up n to nearest pagesize.\n */\nDLMALLOC_EXPORT void*  dlpvalloc(size_t);\n\n/*\n  malloc_trim(size_t pad);\n\n  If possible, gives memory back to the system (via negative arguments\n  to sbrk) if there is unused memory at the `high' end of the malloc\n  pool or in unused MMAP segments. You can call this after freeing\n  large blocks of memory to potentially reduce the system-level memory\n  requirements of a program. However, it cannot guarantee to reduce\n  memory. Under some allocation patterns, some large free blocks of\n  memory will be locked between two used chunks, so they cannot be\n  given back to the system.\n\n  The `pad' argument to malloc_trim represents the amount of free\n  trailing space to leave untrimmed. If this argument is zero, only\n  the minimum amount of memory to maintain internal data structures\n  will be left. Non-zero arguments can be supplied to maintain enough\n  trailing space to service future expected allocations without having\n  to re-obtain memory from the system.\n\n  Malloc_trim returns 1 if it actually released any memory, else 0.\n*/\nDLMALLOC_EXPORT int  dlmalloc_trim(size_t);\n\n/*\n  malloc_stats();\n  Prints on stderr the amount of space obtained from the system (both\n  via sbrk and mmap), the maximum amount (which may be more than\n  current if malloc_trim and/or munmap got called), and the current\n  number of bytes allocated via malloc (or realloc, etc) but not yet\n  freed. Note that this is the number of bytes allocated, not the\n  number requested. It will be larger than the number requested\n  because of alignment and bookkeeping overhead. Because it includes\n  alignment wastage as being in use, this figure may be greater than\n  zero even when no user-level chunks are allocated.\n\n  The reported current and maximum system memory can be inaccurate if\n  a program makes other calls to system memory allocation functions\n  (normally sbrk) outside of malloc.\n\n  malloc_stats prints only the most commonly interesting statistics.\n  More information can be obtained by calling mallinfo.\n*/\nDLMALLOC_EXPORT void  dlmalloc_stats(void);\n\n/*\n  malloc_usable_size(void* p);\n\n  Returns the number of bytes you can actually use in\n  an allocated chunk, which may be more than you requested (although\n  often not) due to alignment and minimum size constraints.\n  You can use this many bytes without worrying about\n  overwriting other allocated objects. This is not a particularly great\n  programming practice. malloc_usable_size can be more useful in\n  debugging and assertions, for example:\n\n  p = malloc(n);\n  assert(malloc_usable_size(p) >= 256);\n*/\nsize_t dlmalloc_usable_size(void*);\n\n#endif /* ONLY_MSPACES */\n\n#if MSPACES\n\n/*\n  mspace is an opaque type representing an independent\n  region of space that supports mspace_malloc, etc.\n*/\ntypedef void* mspace;\n\n/*\n  create_mspace creates and returns a new independent space with the\n  given initial capacity, or, if 0, the default granularity size.  It\n  returns null if there is no system memory available to create the\n  space.  If argument locked is non-zero, the space uses a separate\n  lock to control access. The capacity of the space will grow\n  dynamically as needed to service mspace_malloc requests.  You can\n  control the sizes of incremental increases of this space by\n  compiling with a different DEFAULT_GRANULARITY or dynamically\n  setting with mallopt(M_GRANULARITY, value).\n*/\nDLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);\n\n/*\n  destroy_mspace destroys the given space, and attempts to return all\n  of its memory back to the system, returning the total number of\n  bytes freed. After destruction, the results of access to all memory\n  used by the space become undefined.\n*/\nDLMALLOC_EXPORT size_t destroy_mspace(mspace msp);\n\n/*\n  create_mspace_with_base uses the memory supplied as the initial base\n  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this\n  space is used for bookkeeping, so the capacity must be at least this\n  large. (Otherwise 0 is returned.) When this initial space is\n  exhausted, additional memory will be obtained from the system.\n  Destroying this space will deallocate all additionally allocated\n  space (if possible) but not the initial base.\n*/\nDLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);\n\n/*\n  mspace_track_large_chunks controls whether requests for large chunks\n  are allocated in their own untracked mmapped regions, separate from\n  others in this mspace. By default large chunks are not tracked,\n  which reduces fragmentation. However, such chunks are not\n  necessarily released to the system upon destroy_mspace.  Enabling\n  tracking by setting to true may increase fragmentation, but avoids\n  leakage when relying on destroy_mspace to release all memory\n  allocated using this space.  The function returns the previous\n  setting.\n*/\nDLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);\n\n\n/*\n  mspace_malloc behaves as malloc, but operates within\n  the given space.\n*/\nDLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);\n\n/*\n  mspace_free behaves as free, but operates within\n  the given space.\n\n  If compiled with FOOTERS==1, mspace_free is not actually needed.\n  free may be called instead of mspace_free because freed chunks from\n  any space are handled by their originating spaces.\n*/\nDLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);\n\n/*\n  mspace_realloc behaves as realloc, but operates within\n  the given space.\n\n  If compiled with FOOTERS==1, mspace_realloc is not actually\n  needed.  realloc may be called instead of mspace_realloc because\n  realloced chunks from any space are handled by their originating\n  spaces.\n*/\nDLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);\n\n/*\n  mspace_calloc behaves as calloc, but operates within\n  the given space.\n*/\nDLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);\n\n/*\n  mspace_memalign behaves as memalign, but operates within\n  the given space.\n*/\nDLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);\n\n/*\n  mspace_independent_calloc behaves as independent_calloc, but\n  operates within the given space.\n*/\nDLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,\n                                 size_t elem_size, void* chunks[]);\n\n/*\n  mspace_independent_comalloc behaves as independent_comalloc, but\n  operates within the given space.\n*/\nDLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,\n                                   size_t sizes[], void* chunks[]);\n\n/*\n  mspace_footprint() returns the number of bytes obtained from the\n  system for this space.\n*/\nDLMALLOC_EXPORT size_t mspace_footprint(mspace msp);\n\n/*\n  mspace_max_footprint() returns the peak number of bytes obtained from the\n  system for this space.\n*/\nDLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);\n\n\n#if !NO_MALLINFO\n/*\n  mspace_mallinfo behaves as mallinfo, but reports properties of\n  the given space.\n*/\nDLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);\n#endif /* NO_MALLINFO */\n\n/*\n  malloc_usable_size(void* p) behaves the same as malloc_usable_size;\n*/\nDLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);\n\n/*\n  mspace_malloc_stats behaves as malloc_stats, but reports\n  properties of the given space.\n*/\nDLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);\n\n/*\n  mspace_trim behaves as malloc_trim, but\n  operates within the given space.\n*/\nDLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);\n\n/*\n  An alias for mallopt.\n*/\nDLMALLOC_EXPORT int mspace_mallopt(int, int);\n\n#endif /* MSPACES */\n\n#ifdef __cplusplus\n}  /* end of extern \"C\" */\n#endif /* __cplusplus */\n\n/*\n  ========================================================================\n  To make a fully customizable malloc.h header file, cut everything\n  above this line, put into file malloc.h, edit to suit, and #include it\n  on the next line, as well as in programs that use this malloc.\n  ========================================================================\n*/\n\n/* #include \"malloc.h\" */\n\n/*------------------------------ internal #includes ---------------------- */\n\n#ifdef _MSC_VER\n#pragma warning( disable : 4146 ) /* no \"unsigned\" warnings */\n#endif /* _MSC_VER */\n#if !NO_MALLOC_STATS\n#include <stdio.h>       /* for printing in malloc_stats */\n#endif /* NO_MALLOC_STATS */\n#ifndef LACKS_ERRNO_H\n#include <errno.h>       /* for MALLOC_FAILURE_ACTION */\n#endif /* LACKS_ERRNO_H */\n#ifdef DEBUG\n#if ABORT_ON_ASSERT_FAILURE\n#undef assert\n#define assert(x) if(!(x)) ABORT\n#else /* ABORT_ON_ASSERT_FAILURE */\n#include <assert.h>\n#endif /* ABORT_ON_ASSERT_FAILURE */\n#else  /* DEBUG */\n#ifndef assert\n#define assert(x)\n#endif\n#define DEBUG 0\n#endif /* DEBUG */\n#if !defined(WIN32) && !defined(LACKS_TIME_H)\n#include <time.h>        /* for magic initialization */\n#endif /* WIN32 */\n#ifndef LACKS_STDLIB_H\n#include <stdlib.h>      /* for abort() */\n#endif /* LACKS_STDLIB_H */\n#ifndef LACKS_STRING_H\n#include <string.h>      /* for memset etc */\n#endif  /* LACKS_STRING_H */\n#if USE_BUILTIN_FFS\n#ifndef LACKS_STRINGS_H\n#include <strings.h>     /* for ffs */\n#endif /* LACKS_STRINGS_H */\n#endif /* USE_BUILTIN_FFS */\n#if HAVE_MMAP\n#ifndef LACKS_SYS_MMAN_H\n/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */\n#if (defined(linux) && !defined(__USE_GNU))\n#define __USE_GNU 1\n#include <sys/mman.h>    /* for mmap */\n#undef __USE_GNU\n#else\n#include <sys/mman.h>    /* for mmap */\n#endif /* linux */\n#endif /* LACKS_SYS_MMAN_H */\n#ifndef LACKS_FCNTL_H\n#include <fcntl.h>\n#endif /* LACKS_FCNTL_H */\n#endif /* HAVE_MMAP */\n#ifndef LACKS_UNISTD_H\n#include <unistd.h>     /* for sbrk, sysconf */\n#else /* LACKS_UNISTD_H */\n#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)\nextern void*     sbrk(ptrdiff_t);\n#endif /* FreeBSD etc */\n#endif /* LACKS_UNISTD_H */\n\n/* Declarations for locking */\n#if USE_LOCKS\n#ifndef WIN32\n#if defined (__SVR4) && defined (__sun)  /* solaris */\n#include <thread.h>\n#elif !defined(LACKS_SCHED_H)\n#include <sched.h>\n#endif /* solaris or LACKS_SCHED_H */\n#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS\n#include <pthread.h>\n#endif /* USE_RECURSIVE_LOCKS ... */\n#elif defined(_MSC_VER)\n#ifndef _M_AMD64\n/* These are already defined on AMD64 builds */\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\nLONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);\nLONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n#endif /* _M_AMD64 */\n#pragma intrinsic (_InterlockedCompareExchange)\n#pragma intrinsic (_InterlockedExchange)\n#define interlockedcompareexchange _InterlockedCompareExchange\n#define interlockedexchange _InterlockedExchange\n#elif defined(WIN32) && defined(__GNUC__)\n#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)\n#define interlockedexchange __sync_lock_test_and_set\n#endif /* Win32 */\n#else /* USE_LOCKS */\n#endif /* USE_LOCKS */\n\n#ifndef LOCK_AT_FORK\n#define LOCK_AT_FORK 0\n#endif\n\n/* Declarations for bit scanning on win32 */\n#if defined(_MSC_VER) && _MSC_VER>=1300\n#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\nunsigned char _BitScanForward(unsigned long *index, unsigned long mask);\nunsigned char _BitScanReverse(unsigned long *index, unsigned long mask);\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#define BitScanForward _BitScanForward\n#define BitScanReverse _BitScanReverse\n#pragma intrinsic(_BitScanForward)\n#pragma intrinsic(_BitScanReverse)\n#endif /* BitScanForward */\n#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */\n\n#ifndef WIN32\n#ifndef malloc_getpagesize\n#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */\n#    ifndef _SC_PAGE_SIZE\n#      define _SC_PAGE_SIZE _SC_PAGESIZE\n#    endif\n#  endif\n#  ifdef _SC_PAGE_SIZE\n#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)\n#  else\n#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)\n       extern size_t getpagesize();\n#      define malloc_getpagesize getpagesize()\n#    else\n#      ifdef WIN32 /* use supplied emulation of getpagesize */\n#        define malloc_getpagesize getpagesize()\n#      else\n#        ifndef LACKS_SYS_PARAM_H\n#          include <sys/param.h>\n#        endif\n#        ifdef EXEC_PAGESIZE\n#          define malloc_getpagesize EXEC_PAGESIZE\n#        else\n#          ifdef NBPG\n#            ifndef CLSIZE\n#              define malloc_getpagesize NBPG\n#            else\n#              define malloc_getpagesize (NBPG * CLSIZE)\n#            endif\n#          else\n#            ifdef NBPC\n#              define malloc_getpagesize NBPC\n#            else\n#              ifdef PAGESIZE\n#                define malloc_getpagesize PAGESIZE\n#              else /* just guess */\n#                define malloc_getpagesize ((size_t)4096U)\n#              endif\n#            endif\n#          endif\n#        endif\n#      endif\n#    endif\n#  endif\n#endif\n#endif\n\n/* ------------------- size_t and alignment properties -------------------- */\nnamespace romuluslr{\n/* The byte and bit size of a size_t */\n#define SIZE_T_SIZE         (sizeof(size_t))\n#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)\n\n/* Some constants coerced to size_t */\n/* Annoying but necessary to avoid errors on some platforms */\n#define SIZE_T_ZERO         ((size_t)0)\n#define SIZE_T_ONE          ((size_t)1)\n#define SIZE_T_TWO          ((size_t)2)\n#define SIZE_T_FOUR         ((size_t)4)\n#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)\n#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)\n#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)\n#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)\n\n/* The bit mask value corresponding to MALLOC_ALIGNMENT */\n#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)\n\n/* True if address a has acceptable alignment */\n#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)\n\n/* the number of bytes to offset an address to align it */\n#define align_offset(A)\\\n ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\\\n  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))\n\n/* -------------------------- MMAP preliminaries ------------------------- */\n\n/*\n   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and\n   checks to fail so compiler optimizer can delete code rather than\n   using so many \"#if\"s.\n*/\n\n\n/* MORECORE and MMAP must return MFAIL on failure */\n#define MFAIL                ((void*)(MAX_SIZE_T))\n#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */\n\n#if HAVE_MMAP\n\n#ifndef WIN32\n#define MUNMAP_DEFAULT(a, s)  munmap((a), (s))\n#define MMAP_PROT            (PROT_READ|PROT_WRITE)\n#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)\n#define MAP_ANONYMOUS        MAP_ANON\n#endif /* MAP_ANON */\n#ifdef MAP_ANONYMOUS\n#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)\n#define MMAP_DEFAULT(s)       mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)\n#else /* MAP_ANONYMOUS */\n/*\n   Nearly all versions of mmap support MAP_ANONYMOUS, so the following\n   is unlikely to be needed, but is supplied just in case.\n*/\n#define MMAP_FLAGS           (MAP_PRIVATE)\nstatic int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */\n#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \\\n           (dev_zero_fd = open(\"/dev/zero\", O_RDWR), \\\n            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \\\n            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))\n#endif /* MAP_ANONYMOUS */\n\n#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)\n\n#else /* WIN32 */\n\n/* Win32 MMAP via VirtualAlloc */\nstatic FORCEINLINE void* win32mmap(size_t size) {\n  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);\n  return (ptr != 0)? ptr: MFAIL;\n}\n\n/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */\nstatic FORCEINLINE void* win32direct_mmap(size_t size) {\n  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,\n                           PAGE_READWRITE);\n  return (ptr != 0)? ptr: MFAIL;\n}\n\n/* This function supports releasing coalesed segments */\nstatic FORCEINLINE int win32munmap(void* ptr, size_t size) {\n  MEMORY_BASIC_INFORMATION minfo;\n  char* cptr = (char*)ptr;\n  while (size) {\n    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)\n      return -1;\n    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||\n        minfo.State != MEM_COMMIT || minfo.RegionSize > size)\n      return -1;\n    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)\n      return -1;\n    cptr += minfo.RegionSize;\n    size -= minfo.RegionSize;\n  }\n  return 0;\n}\n\n#define MMAP_DEFAULT(s)             win32mmap(s)\n#define MUNMAP_DEFAULT(a, s)        win32munmap((a), (s))\n#define DIRECT_MMAP_DEFAULT(s)      win32direct_mmap(s)\n#endif /* WIN32 */\n#endif /* HAVE_MMAP */\n\n#if HAVE_MREMAP\n#ifndef WIN32\n#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))\n#endif /* WIN32 */\n#endif /* HAVE_MREMAP */\n\n/**\n * Define CALL_MORECORE\n */\n#if HAVE_MORECORE\n    #ifdef MORECORE\n        #define CALL_MORECORE(S)    MORECORE(S)\n    #else  /* MORECORE */\n        #define CALL_MORECORE(S)    MORECORE_DEFAULT(S)\n    #endif /* MORECORE */\n#else  /* HAVE_MORECORE */\n    #define CALL_MORECORE(S)        MFAIL\n#endif /* HAVE_MORECORE */\n\n/**\n * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP\n */\n#if HAVE_MMAP\n    #define USE_MMAP_BIT            (SIZE_T_ONE)\n\n    #ifdef MMAP\n        #define CALL_MMAP(s)        MMAP(s)\n    #else /* MMAP */\n        #define CALL_MMAP(s)        MMAP_DEFAULT(s)\n    #endif /* MMAP */\n    #ifdef MUNMAP\n        #define CALL_MUNMAP(a, s)   MUNMAP((a), (s))\n    #else /* MUNMAP */\n        #define CALL_MUNMAP(a, s)   MUNMAP_DEFAULT((a), (s))\n    #endif /* MUNMAP */\n    #ifdef DIRECT_MMAP\n        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)\n    #else /* DIRECT_MMAP */\n        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)\n    #endif /* DIRECT_MMAP */\n#else  /* HAVE_MMAP */\n    #define USE_MMAP_BIT            (SIZE_T_ZERO)\n\n    #define MMAP(s)                 MFAIL\n    #define MUNMAP(a, s)            (-1)\n    #define DIRECT_MMAP(s)          MFAIL\n    #define CALL_DIRECT_MMAP(s)     DIRECT_MMAP(s)\n    #define CALL_MMAP(s)            MMAP(s)\n    #define CALL_MUNMAP(a, s)       MUNMAP((a), (s))\n#endif /* HAVE_MMAP */\n\n/**\n * Define CALL_MREMAP\n */\n#if HAVE_MMAP && HAVE_MREMAP\n    #ifdef MREMAP\n        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))\n    #else /* MREMAP */\n        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))\n    #endif /* MREMAP */\n#else  /* HAVE_MMAP && HAVE_MREMAP */\n    #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL\n#endif /* HAVE_MMAP && HAVE_MREMAP */\n\n/* mstate bit set if continguous morecore disabled or failed */\n#define USE_NONCONTIGUOUS_BIT (4U)\n\n/* segment bit set in create_mspace_with_base */\n#define EXTERN_BIT            (8U)\n\n\n/* --------------------------- Lock preliminaries ------------------------ */\n\n/*\n  When locks are defined, there is one global lock, plus\n  one per-mspace lock.\n\n  The global lock_ensures that mparams.magic and other unique\n  mparams values are initialized only once. It also protects\n  sequences of calls to MORECORE.  In many cases sys_alloc requires\n  two calls, that should not be interleaved with calls by other\n  threads.  This does not protect against direct calls to MORECORE\n  by other threads not using this lock, so there is still code to\n  cope the best we can on interference.\n\n  Per-mspace locks surround calls to malloc, free, etc.\n  By default, locks are simple non-reentrant mutexes.\n\n  Because lock-protected regions generally have bounded times, it is\n  OK to use the supplied simple spinlocks. Spinlocks are likely to\n  improve performance for lightly contended applications, but worsen\n  performance under heavy contention.\n\n  If USE_LOCKS is > 1, the definitions of lock routines here are\n  bypassed, in which case you will need to define the type MLOCK_T,\n  and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK\n  and TRY_LOCK.  You must also declare a\n    static MLOCK_T malloc_global_mutex = { initialization values };.\n\n*/\n\n#if !USE_LOCKS\n#define USE_LOCK_BIT               (0U)\n#define INITIAL_LOCK(l)            (0)\n#define DESTROY_LOCK(l)            (0)\n#define ACQUIRE_MALLOC_GLOBAL_LOCK()\n#define RELEASE_MALLOC_GLOBAL_LOCK()\n\n#else\n#if USE_LOCKS > 1\n/* -----------------------  User-defined locks ------------------------ */\n/* Define your own lock implementation here */\n/* #define INITIAL_LOCK(lk)  ... */\n/* #define DESTROY_LOCK(lk)  ... */\n/* #define ACQUIRE_LOCK(lk)  ... */\n/* #define RELEASE_LOCK(lk)  ... */\n/* #define TRY_LOCK(lk) ... */\n/* static MLOCK_T malloc_global_mutex = ... */\n\n#elif USE_SPIN_LOCKS\n\n/* First, define CAS_LOCK and CLEAR_LOCK on ints */\n/* Note CAS_LOCK defined to return 0 on success */\n\n#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))\n#define CAS_LOCK(sl)     __sync_lock_test_and_set(sl, 1)\n#define CLEAR_LOCK(sl)   __sync_lock_release(sl)\n\n#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))\n/* Custom spin locks for older gcc on x86 */\nstatic FORCEINLINE int x86_cas_lock(int *sl) {\n  int ret;\n  int val = 1;\n  int cmp = 0;\n  __asm__ __volatile__  (\"lock; cmpxchgl %1, %2\"\n                         : \"=a\" (ret)\n                         : \"r\" (val), \"m\" (*(sl)), \"0\"(cmp)\n                         : \"memory\", \"cc\");\n  return ret;\n}\n\nstatic FORCEINLINE void x86_clear_lock(int* sl) {\n  assert(*sl != 0);\n  int prev = 0;\n  int ret;\n  __asm__ __volatile__ (\"lock; xchgl %0, %1\"\n                        : \"=r\" (ret)\n                        : \"m\" (*(sl)), \"0\"(prev)\n                        : \"memory\");\n}\n\n#define CAS_LOCK(sl)     x86_cas_lock(sl)\n#define CLEAR_LOCK(sl)   x86_clear_lock(sl)\n\n#else /* Win32 MSC */\n#define CAS_LOCK(sl)     interlockedexchange(sl, (LONG)1)\n#define CLEAR_LOCK(sl)   interlockedexchange (sl, (LONG)0)\n\n#endif /* ... gcc spins locks ... */\n\n/* How to yield for a spin lock */\n#define SPINS_PER_YIELD       63\n#if defined(_MSC_VER)\n#define SLEEP_EX_DURATION     50 /* delay for yield/sleep */\n#define SPIN_LOCK_YIELD  SleepEx(SLEEP_EX_DURATION, FALSE)\n#elif defined (__SVR4) && defined (__sun) /* solaris */\n#define SPIN_LOCK_YIELD   thr_yield();\n#elif !defined(LACKS_SCHED_H)\n#define SPIN_LOCK_YIELD   sched_yield();\n#else\n#define SPIN_LOCK_YIELD\n#endif /* ... yield ... */\n\n#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0\n/* Plain spin locks use single word (embedded in malloc_states) */\nstatic int spin_acquire_lock(int *sl) {\n  int spins = 0;\n  while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {\n    if ((++spins & SPINS_PER_YIELD) == 0) {\n      SPIN_LOCK_YIELD;\n    }\n  }\n  return 0;\n}\n\n#define MLOCK_T               int\n#define TRY_LOCK(sl)          !CAS_LOCK(sl)\n#define RELEASE_LOCK(sl)      CLEAR_LOCK(sl)\n#define ACQUIRE_LOCK(sl)      (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0)\n#define INITIAL_LOCK(sl)      (*sl = 0)\n#define DESTROY_LOCK(sl)      (0)\nstatic MLOCK_T malloc_global_mutex = 0;\n\n#else /* USE_RECURSIVE_LOCKS */\n/* types for lock owners */\n#ifdef WIN32\n#define THREAD_ID_T           DWORD\n#define CURRENT_THREAD        GetCurrentThreadId()\n#define EQ_OWNER(X,Y)         ((X) == (Y))\n#else\n/*\n  Note: the following assume that pthread_t is a type that can be\n  initialized to (casted) zero. If this is not the case, you will need to\n  somehow redefine these or not use spin locks.\n*/\n#define THREAD_ID_T           pthread_t\n#define CURRENT_THREAD        pthread_self()\n#define EQ_OWNER(X,Y)         pthread_equal(X, Y)\n#endif\n\nstruct malloc_recursive_lock {\n  int sl;\n  unsigned int c;\n  THREAD_ID_T threadid;\n};\n\n#define MLOCK_T  struct malloc_recursive_lock\nstatic MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0};\n\nstatic FORCEINLINE void recursive_release_lock(MLOCK_T *lk) {\n  assert(lk->sl != 0);\n  if (--lk->c == 0) {\n    CLEAR_LOCK(&lk->sl);\n  }\n}\n\nstatic FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) {\n  THREAD_ID_T mythreadid = CURRENT_THREAD;\n  int spins = 0;\n  for (;;) {\n    if (*((volatile int *)(&lk->sl)) == 0) {\n      if (!CAS_LOCK(&lk->sl)) {\n        lk->threadid = mythreadid;\n        lk->c = 1;\n        return 0;\n      }\n    }\n    else if (EQ_OWNER(lk->threadid, mythreadid)) {\n      ++lk->c;\n      return 0;\n    }\n    if ((++spins & SPINS_PER_YIELD) == 0) {\n      SPIN_LOCK_YIELD;\n    }\n  }\n}\n\nstatic FORCEINLINE int recursive_try_lock(MLOCK_T *lk) {\n  THREAD_ID_T mythreadid = CURRENT_THREAD;\n  if (*((volatile int *)(&lk->sl)) == 0) {\n    if (!CAS_LOCK(&lk->sl)) {\n      lk->threadid = mythreadid;\n      lk->c = 1;\n      return 1;\n    }\n  }\n  else if (EQ_OWNER(lk->threadid, mythreadid)) {\n    ++lk->c;\n    return 1;\n  }\n  return 0;\n}\n\n#define RELEASE_LOCK(lk)      recursive_release_lock(lk)\n#define TRY_LOCK(lk)          recursive_try_lock(lk)\n#define ACQUIRE_LOCK(lk)      recursive_acquire_lock(lk)\n#define INITIAL_LOCK(lk)      ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0)\n#define DESTROY_LOCK(lk)      (0)\n#endif /* USE_RECURSIVE_LOCKS */\n\n#elif defined(WIN32) /* Win32 critical sections */\n#define MLOCK_T               CRITICAL_SECTION\n#define ACQUIRE_LOCK(lk)      (EnterCriticalSection(lk), 0)\n#define RELEASE_LOCK(lk)      LeaveCriticalSection(lk)\n#define TRY_LOCK(lk)          TryEnterCriticalSection(lk)\n#define INITIAL_LOCK(lk)      (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000))\n#define DESTROY_LOCK(lk)      (DeleteCriticalSection(lk), 0)\n#define NEED_GLOBAL_LOCK_INIT\n\nstatic MLOCK_T malloc_global_mutex;\nstatic volatile LONG malloc_global_mutex_status;\n\n/* Use spin loop to initialize global lock */\nstatic void init_malloc_global_mutex() {\n  for (;;) {\n    long stat = malloc_global_mutex_status;\n    if (stat > 0)\n      return;\n    /* transition to < 0 while initializing, then to > 0) */\n    if (stat == 0 &&\n        interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) {\n      InitializeCriticalSection(&malloc_global_mutex);\n      interlockedexchange(&malloc_global_mutex_status, (LONG)1);\n      return;\n    }\n    SleepEx(0, FALSE);\n  }\n}\n\n#else /* pthreads-based locks */\n#define MLOCK_T               pthread_mutex_t\n#define ACQUIRE_LOCK(lk)      pthread_mutex_lock(lk)\n#define RELEASE_LOCK(lk)      pthread_mutex_unlock(lk)\n#define TRY_LOCK(lk)          (!pthread_mutex_trylock(lk))\n#define INITIAL_LOCK(lk)      pthread_init_lock(lk)\n#define DESTROY_LOCK(lk)      pthread_mutex_destroy(lk)\n\n#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE)\n/* Cope with old-style linux recursive lock initialization by adding */\n/* skipped internal declaration from pthread.h */\nextern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,\n                                              int __kind));\n#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP\n#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)\n#endif /* USE_RECURSIVE_LOCKS ... */\n\nstatic MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;\n\nstatic int pthread_init_lock (MLOCK_T *lk) {\n  pthread_mutexattr_t attr;\n  if (pthread_mutexattr_init(&attr)) return 1;\n#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0\n  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;\n#endif\n  if (pthread_mutex_init(lk, &attr)) return 1;\n  if (pthread_mutexattr_destroy(&attr)) return 1;\n  return 0;\n}\n\n#endif /* ... lock types ... */\n\n/* Common code for all lock types */\n#define USE_LOCK_BIT               (2U)\n\n#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK\n#define ACQUIRE_MALLOC_GLOBAL_LOCK()  ACQUIRE_LOCK(&malloc_global_mutex);\n#endif\n\n#ifndef RELEASE_MALLOC_GLOBAL_LOCK\n#define RELEASE_MALLOC_GLOBAL_LOCK()  RELEASE_LOCK(&malloc_global_mutex);\n#endif\n\n#endif /* USE_LOCKS */\n\n/* -----------------------  Chunk representations ------------------------ */\n\n/*\n  (The following includes lightly edited explanations by Colin Plumb.)\n\n  The malloc_chunk declaration below is misleading (but accurate and\n  necessary).  It declares a \"view\" into memory allowing access to\n  necessary fields at known offsets from a given base.\n\n  Chunks of memory are maintained using a `boundary tag' method as\n  originally described by Knuth.  (See the paper by Paul Wilson\n  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such\n  techniques.)  Sizes of free chunks are stored both in the front of\n  each chunk and at the end.  This makes consolidating fragmented\n  chunks into bigger chunks fast.  The head fields also hold bits\n  representing whether chunks are free or in use.\n\n  Here are some pictures to make it clearer.  They are \"exploded\" to\n  show that the state of a chunk can be thought of as extending from\n  the high 31 bits of the head field of its header through the\n  prev_foot and PINUSE_BIT bit of the following chunk header.\n\n  A chunk that's in use looks like:\n\n   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n           | Size of previous chunk (if P = 0)                             |\n           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|\n         | Size of this chunk                                         1| +-+\n   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         |                                                               |\n         +-                                                             -+\n         |                                                               |\n         +-                                                             -+\n         |                                                               :\n         +-      size - sizeof(size_t) available payload bytes          -+\n         :                                                               |\n chunk-> +-                                                             -+\n         |                                                               |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|\n       | Size of next chunk (may or may not be in use)               | +-+\n mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n\n    And if it's free, it looks like this:\n\n   chunk-> +-                                                             -+\n           | User payload (must be in use, or we would have merged!)       |\n           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|\n         | Size of this chunk                                         0| +-+\n   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         | Next pointer                                                  |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         | Prev pointer                                                  |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         |                                                               :\n         +-      size - sizeof(struct chunk) unused bytes               -+\n         :                                                               |\n chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n         | Size of this chunk                                            |\n         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|\n       | Size of next chunk (must be in use, or we would have merged)| +-+\n mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n       |                                                               :\n       +- User payload                                                -+\n       :                                                               |\n       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n                                                                     |0|\n                                                                     +-+\n  Note that since we always merge adjacent free chunks, the chunks\n  adjacent to a free chunk must be in use.\n\n  Given a pointer to a chunk (which can be derived trivially from the\n  payload pointer) we can, in O(1) time, find out whether the adjacent\n  chunks are free, and if so, unlink them from the lists that they\n  are on and merge them with the current chunk.\n\n  Chunks always begin on even word boundaries, so the mem portion\n  (which is returned to the user) is also on an even word boundary, and\n  thus at least double-word aligned.\n\n  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the\n  chunk size (which is always a multiple of two words), is an in-use\n  bit for the *previous* chunk.  If that bit is *clear*, then the\n  word before the current chunk size contains the previous chunk\n  size, and can be used to find the front of the previous chunk.\n  The very first chunk allocated always has this bit set, preventing\n  access to non-existent (or non-owned) memory. If pinuse is set for\n  any given chunk, then you CANNOT determine the size of the\n  previous chunk, and might even get a memory addressing fault when\n  trying to do so.\n\n  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of\n  the chunk size redundantly records whether the current chunk is\n  inuse (unless the chunk is mmapped). This redundancy enables usage\n  checks within free and realloc, and reduces indirection when freeing\n  and consolidating chunks.\n\n  Each freshly allocated chunk must have both cinuse and pinuse set.\n  That is, each allocated chunk borders either a previously allocated\n  and still in-use chunk, or the base of its memory arena. This is\n  ensured by making all allocations from the `lowest' part of any\n  found chunk.  Further, no free chunk physically borders another one,\n  so each free chunk is known to be preceded and followed by either\n  inuse chunks or the ends of memory.\n\n  Note that the `foot' of the current chunk is actually represented\n  as the prev_foot of the NEXT chunk. This makes it easier to\n  deal with alignments etc but can be very confusing when trying\n  to extend or adapt this code.\n\n  The exceptions to all this are\n\n     1. The special chunk `top' is the top-most available chunk (i.e.,\n        the one bordering the end of available memory). It is treated\n        specially.  Top is never included in any bin, is used only if\n        no other chunk is available, and is released back to the\n        system if it is very large (see M_TRIM_THRESHOLD).  In effect,\n        the top chunk is treated as larger (and thus less well\n        fitting) than any other available chunk.  The top chunk\n        doesn't update its trailing size field since there is no next\n        contiguous chunk that would have to index off it. However,\n        space is still allocated for it (TOP_FOOT_SIZE) to enable\n        separation or merging when space is extended.\n\n     3. Chunks allocated via mmap, have both cinuse and pinuse bits\n        cleared in their head fields.  Because they are allocated\n        one-by-one, each must carry its own prev_foot field, which is\n        also used to hold the offset this chunk has within its mmapped\n        region, which is needed to preserve alignment. Each mmapped\n        chunk is trailed by the first two fields of a fake next-chunk\n        for sake of usage checks.\n\n*/\n\nstruct malloc_chunk {\n  persist<size_t>               prev_foot;  /* Size of previous chunk (if free).  */\n  persist<size_t>               head;       /* Size and inuse bits. */\n  persist<struct malloc_chunk*> fd;         /* double links -- used only if free. */\n  persist<struct malloc_chunk*> bk;\n};\n\ntypedef struct malloc_chunk  mchunk;\ntypedef struct malloc_chunk* mchunkptr;\ntypedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */\ntypedef unsigned int bindex_t;         /* Described below */\ntypedef unsigned int binmap_t;         /* Described below */\ntypedef unsigned int flag_t;           /* The type of various bit flag sets */\n\n/* ------------------- Chunks sizes and alignments ----------------------- */\n\n#define MCHUNK_SIZE         (sizeof(mchunk))\n\n#if FOOTERS\n#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)\n#else /* FOOTERS */\n#define CHUNK_OVERHEAD      (SIZE_T_SIZE)\n#endif /* FOOTERS */\n\n/* MMapped chunks need a second word of overhead ... */\n#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)\n/* ... and additional padding for fake next-chunk at foot */\n#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)\n\n/* The smallest size we can malloc is an aligned minimal chunk */\n#define MIN_CHUNK_SIZE\\\n  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)\n\n/* conversion from malloc headers to user pointers, and back */\n#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))\n#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))\n/* chunk associated with aligned address A */\n#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))\n\n/* Bounds on request (not chunk) sizes. */\n#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)\n#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)\n\n/* pad request bytes into a usable size */\n#define pad_request(req) \\\n   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)\n\n/* pad request, checking for minimum (but not maximum) */\n#define request2size(req) \\\n  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))\n\n\n/* ------------------ Operations on head and foot fields ----------------- */\n\n/*\n  The head field of a chunk is or'ed with PINUSE_BIT when previous\n  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in\n  use, unless mmapped, in which case both bits are cleared.\n\n  FLAG4_BIT is not used by this malloc, but might be useful in extensions.\n*/\n\n#define PINUSE_BIT          (SIZE_T_ONE)\n#define CINUSE_BIT          (SIZE_T_TWO)\n#define FLAG4_BIT           (SIZE_T_FOUR)\n#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)\n#define FLAG_BITS           (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)\n\n/* Head value for fenceposts */\n#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)\n\n/* extraction of fields from head words */\n#define cinuse(p)           ((p)->head & CINUSE_BIT)\n#define pinuse(p)           ((p)->head & PINUSE_BIT)\n#define flag4inuse(p)       ((p)->head & FLAG4_BIT)\n#define is_inuse(p)         (((p)->head & INUSE_BITS) != PINUSE_BIT)\n#define is_mmapped(p)       (((p)->head & INUSE_BITS) == 0)\n\n#define chunksize(p)        ((p)->head & ~(FLAG_BITS))\n\n#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)\n#define set_flag4(p)        ((p)->head |= FLAG4_BIT)\n#define clear_flag4(p)      ((p)->head &= ~FLAG4_BIT)\n\n/* Treat space at ptr +/- offset as a chunk */\n#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))\n#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))\n\n/* Ptr to next or previous physical malloc_chunk. */\n#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))\n#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))\n\n/* extract next chunk's pinuse bit */\n#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)\n\n/* Get/set size at footer */\n#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)\n#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))\n\n/* Set size, pinuse bit, and foot */\n#define set_size_and_pinuse_of_free_chunk(p, s)\\\n  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))\n\n/* Set size, pinuse bit, foot, and clear next pinuse */\n#define set_free_with_pinuse(p, s, n)\\\n  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))\n\n/* Get the internal overhead associated with chunk p */\n#define overhead_for(p)\\\n (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)\n\n/* Return true if malloced space is not necessarily cleared */\n#if MMAP_CLEARS\n#define calloc_must_clear(p) (!is_mmapped(p))\n#else /* MMAP_CLEARS */\n#define calloc_must_clear(p) (1)\n#endif /* MMAP_CLEARS */\n\n/* ---------------------- Overlaid data structures ----------------------- */\n\n/*\n  When chunks are not in use, they are treated as nodes of either\n  lists or trees.\n\n  \"Small\"  chunks are stored in circular doubly-linked lists, and look\n  like this:\n\n    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Size of previous chunk                            |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `head:' |             Size of chunk, in bytes                         |P|\n      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Forward pointer to next chunk in list             |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Back pointer to previous chunk in list            |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Unused space (may be 0 bytes long)                .\n            .                                                               .\n            .                                                               |\nnextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `foot:' |             Size of chunk, in bytes                           |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n\n  Larger chunks are kept in a form of bitwise digital trees (aka\n  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for\n  free chunks greater than 256 bytes, their size doesn't impose any\n  constraints on user chunk sizes.  Each node looks like:\n\n    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Size of previous chunk                            |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `head:' |             Size of chunk, in bytes                         |P|\n      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Forward pointer to next chunk of same size        |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Back pointer to previous chunk of same size       |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Pointer to left child (child[0])                  |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Pointer to right child (child[1])                 |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Pointer to parent                                 |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             bin index of this chunk                           |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n            |             Unused space                                      .\n            .                                                               |\nnextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    `foot:' |             Size of chunk, in bytes                           |\n            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n\n  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks\n  of the same size are arranged in a circularly-linked list, with only\n  the oldest chunk (the next to be used, in our FIFO ordering)\n  actually in the tree.  (Tree members are distinguished by a non-null\n  parent pointer.)  If a chunk with the same size an an existing node\n  is inserted, it is linked off the existing node using pointers that\n  work in the same way as fd/bk pointers of small chunks.\n\n  Each tree contains a power of 2 sized range of chunk sizes (the\n  smallest is 0x100 <= x < 0x180), which is is divided in half at each\n  tree level, with the chunks in the smaller half of the range (0x100\n  <= x < 0x140 for the top nose) in the left subtree and the larger\n  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,\n  done by inspecting individual bits.\n\n  Using these rules, each node's left subtree contains all smaller\n  sizes than its right subtree.  However, the node at the root of each\n  subtree has no particular ordering relationship to either.  (The\n  dividing line between the subtree sizes is based on trie relation.)\n  If we remove the last chunk of a given size from the interior of the\n  tree, we need to replace it with a leaf node.  The tree ordering\n  rules permit a node to be replaced by any leaf below it.\n\n  The smallest chunk in a tree (a common operation in a best-fit\n  allocator) can be found by walking a path to the leftmost leaf in\n  the tree.  Unlike a usual binary tree, where we follow left child\n  pointers until we reach a null, here we follow the right child\n  pointer any time the left one is null, until we reach a leaf with\n  both child pointers null. The smallest chunk in the tree will be\n  somewhere along that path.\n\n  The worst case number of steps to add, find, or remove a node is\n  bounded by the number of bits differentiating chunks within\n  bins. Under current bin calculations, this ranges from 6 up to 21\n  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case\n  is of course much better.\n*/\n\nstruct malloc_tree_chunk {\n  /* The first four fields must be compatible with malloc_chunk */\n  persist<size_t>                    prev_foot;\n  persist<size_t>                    head;\n  persist<struct malloc_tree_chunk*> fd;\n  persist<struct malloc_tree_chunk*> bk;\n\n  persist<struct malloc_tree_chunk*> child[2];\n  persist<struct malloc_tree_chunk*> parent;\n  persist<bindex_t>                  index;\n};\n\ntypedef struct malloc_tree_chunk  tchunk;\ntypedef struct malloc_tree_chunk* tchunkptr;\ntypedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */\n\n/* A little helper macro for trees */\n#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])\n\n/* ----------------------------- Segments -------------------------------- */\n\n/*\n  Each malloc space may include non-contiguous segments, held in a\n  list headed by an embedded malloc_segment record representing the\n  top-most space. Segments also include flags holding properties of\n  the space. Large chunks that are directly allocated by mmap are not\n  included in this list. They are instead independently created and\n  destroyed without otherwise keeping track of them.\n\n  Segment management mainly comes into play for spaces allocated by\n  MMAP.  Any call to MMAP might or might not return memory that is\n  adjacent to an existing segment.  MORECORE normally contiguously\n  extends the current space, so this space is almost always adjacent,\n  which is simpler and faster to deal with. (This is why MORECORE is\n  used preferentially to MMAP when both are available -- see\n  sys_alloc.)  When allocating using MMAP, we don't use any of the\n  hinting mechanisms (inconsistently) supported in various\n  implementations of unix mmap, or distinguish reserving from\n  committing memory. Instead, we just ask for space, and exploit\n  contiguity when we get it.  It is probably possible to do\n  better than this on some systems, but no general scheme seems\n  to be significantly better.\n\n  Management entails a simpler variant of the consolidation scheme\n  used for chunks to reduce fragmentation -- new adjacent memory is\n  normally prepended or appended to an existing segment. However,\n  there are limitations compared to chunk consolidation that mostly\n  reflect the fact that segment processing is relatively infrequent\n  (occurring only when getting memory from system) and that we\n  don't expect to have huge numbers of segments:\n\n  * Segments are not indexed, so traversal requires linear scans.  (It\n    would be possible to index these, but is not worth the extra\n    overhead and complexity for most programs on most platforms.)\n  * New segments are only appended to old ones when holding top-most\n    memory; if they cannot be prepended to others, they are held in\n    different segments.\n\n  Except for the top-most segment of an mstate, each segment record\n  is kept at the tail of its segment. Segments are added by pushing\n  segment records onto the list headed by &mstate.seg for the\n  containing mstate.\n\n  Segment flags control allocation/merge/deallocation policies:\n  * If EXTERN_BIT set, then we did not allocate this segment,\n    and so should not try to deallocate or merge with others.\n    (This currently holds only for the initial segment passed\n    into create_mspace_with_base.)\n  * If USE_MMAP_BIT set, the segment may be merged with\n    other surrounding mmapped segments and trimmed/de-allocated\n    using munmap.\n  * If neither bit is set, then the segment was obtained using\n    MORECORE so can be merged with surrounding MORECORE'd segments\n    and deallocated/trimmed using MORECORE with negative arguments.\n*/\n\nstruct malloc_segment {\n  persist<char*>       base;             /* base address */\n  persist<size_t>       size;             /* allocated size */\n  persist<struct malloc_segment*> next;   /* ptr to next segment */\n  persist<flag_t>       sflags;           /* mmap and extern flag */\n};\n\n#define is_mmapped_segment(S)  ((S)->sflags & USE_MMAP_BIT)\n#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)\n\ntypedef struct malloc_segment  msegment;\ntypedef struct malloc_segment* msegmentptr;\n\n/* ---------------------------- malloc_state ----------------------------- */\n\n/*\n   A malloc_state holds all of the bookkeeping for a space.\n   The main fields are:\n\n  Top\n    The topmost chunk of the currently active segment. Its size is\n    cached in topsize.  The actual size of topmost space is\n    topsize+TOP_FOOT_SIZE, which includes space reserved for adding\n    fenceposts and segment records if necessary when getting more\n    space from the system.  The size at which to autotrim top is\n    cached from mparams in trim_check, except that it is disabled if\n    an autotrim fails.\n\n  Designated victim (dv)\n    This is the preferred chunk for servicing small requests that\n    don't have exact fits.  It is normally the chunk split off most\n    recently to service another small request.  Its size is cached in\n    dvsize. The link fields of this chunk are not maintained since it\n    is not kept in a bin.\n\n  SmallBins\n    An array of bin headers for free chunks.  These bins hold chunks\n    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains\n    chunks of all the same size, spaced 8 bytes apart.  To simplify\n    use in double-linked lists, each bin header acts as a malloc_chunk\n    pointing to the real first node, if it exists (else pointing to\n    itself).  This avoids special-casing for headers.  But to avoid\n    waste, we allocate only the fd/bk pointers of bins, and then use\n    repositioning tricks to treat these as the fields of a chunk.\n\n  TreeBins\n    Treebins are pointers to the roots of trees holding a range of\n    sizes. There are 2 equally spaced treebins for each power of two\n    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything\n    larger.\n\n  Bin maps\n    There is one bit map for small bins (\"smallmap\") and one for\n    treebins (\"treemap).  Each bin sets its bit when non-empty, and\n    clears the bit when empty.  Bit operations are then used to avoid\n    bin-by-bin searching -- nearly all \"search\" is done without ever\n    looking at bins that won't be selected.  The bit maps\n    conservatively use 32 bits per map word, even if on 64bit system.\n    For a good description of some of the bit-based techniques used\n    here, see Henry S. Warren Jr's book \"Hacker's Delight\" (and\n    supplement at http://hackersdelight.org/). Many of these are\n    intended to reduce the branchiness of paths through malloc etc, as\n    well as to reduce the number of memory locations read or written.\n\n  Segments\n    A list of segments headed by an embedded malloc_segment record\n    representing the initial space.\n\n  Address check support\n    The least_addr field is the least address ever obtained from\n    MORECORE or MMAP. Attempted frees and reallocs of any address less\n    than this are trapped (unless INSECURE is defined).\n\n  Magic tag\n    A cross-check field that should always hold same value as mparams.magic.\n\n  Max allowed footprint\n    The maximum allowed bytes to allocate from system (zero means no limit)\n\n  Flags\n    Bits recording whether to use MMAP, locks, or contiguous MORECORE\n\n  Statistics\n    Each space keeps track of current and maximum system memory\n    obtained via MORECORE or MMAP.\n\n  Trim support\n    Fields holding the amount of unused topmost memory that should trigger\n    trimming, and a counter to force periodic scanning to release unused\n    non-topmost segments.\n\n  Locking\n    If USE_LOCKS is defined, the \"mutex\" lock is acquired and released\n    around every public call using this mspace.\n\n  Extension support\n    A void* pointer and a size_t field that can be used to help implement\n    extensions to this malloc.\n*/\n\n/* Bin types, widths and sizes */\n#define NSMALLBINS        (32U)\n#define NTREEBINS         (32U)\n#define SMALLBIN_SHIFT    (3U)\n#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)\n#define TREEBIN_SHIFT     (8U)\n#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)\n#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)\n#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)\n\nstruct malloc_state {\n  persist<binmap_t>   smallmap;\n  persist<binmap_t>   treemap;\n  persist<size_t>     dvsize;\n  persist<size_t>     topsize;\n  persist<char*>      least_addr;\n  persist<mchunkptr>  dv;\n  persist<mchunkptr>  top;\n  persist<size_t>     trim_check;\n  persist<size_t>     release_checks;\n  persist<size_t>     magic;\n  persist<mchunkptr>  smallbins[(NSMALLBINS+1)*2];\n  persist<tbinptr>    treebins[NTREEBINS];\n  persist<size_t>     footprint;\n  persist<size_t>     max_footprint;\n  persist<size_t>     footprint_limit; /* zero means no limit */\n  persist<flag_t>     mflags;\n#if USE_LOCKS\n  MLOCK_T    mutex;     /* locate lock among fields that rarely change */\n#endif /* USE_LOCKS */\n  msegment   seg;\n  persist<void*>      extp;      /* Unused but available for extensions */\n  persist<size_t>     exts;\n};\n\ntypedef struct malloc_state*    mstate;\n\n/* ------------- Global malloc_state and malloc_params ------------------- */\n\n/*\n  malloc_params holds global properties, including those that can be\n  dynamically set using mallopt. There is a single instance, mparams,\n  initialized in init_mparams. Note that the non-zeroness of \"magic\"\n  also serves as an initialization flag.\n*/\n\nstruct malloc_params {\n  size_t magic;\n  size_t page_size;\n  size_t granularity;\n  size_t mmap_threshold;\n  size_t trim_threshold;\n  flag_t default_mflags;\n};\n\nstatic struct malloc_params mparams;\n\n/* Ensure mparams initialized */\n#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())\n\n#if !ONLY_MSPACES\n\n/* The global malloc_state used for all non-\"mspace\" calls */\nstatic struct malloc_state _gm_;\n#define gm                 (&_gm_)\n#define is_global(M)       ((M) == &_gm_)\n\n#endif /* !ONLY_MSPACES */\n\n#define is_initialized(M)  ((M)->top != 0)\n\n/* -------------------------- system alloc setup ------------------------- */\n\n/* Operations on mflags */\n\n#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)\n#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)\n#if USE_LOCKS\n#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)\n#else\n#define disable_lock(M)\n#endif\n\n#define use_mmap(M)           ((M)->mflags &   (flag_t)USE_MMAP_BIT)\n#define enable_mmap(M)        ((M)->mflags |=  (flag_t)USE_MMAP_BIT)\n#if HAVE_MMAP\n#define disable_mmap(M)       ((M)->mflags &=  (flag_t)~USE_MMAP_BIT)\n#else\n#define disable_mmap(M)\n#endif\n\n#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)\n#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)\n\n#define set_lock(M,L)\\\n ((M)->mflags = (L)?\\\n  ((M)->mflags | USE_LOCK_BIT) :\\\n  ((M)->mflags & ~USE_LOCK_BIT))\n\n/* page-align a size */\n#define page_align(S)\\\n (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))\n\n/* granularity-align a size */\n#define granularity_align(S)\\\n  (((S) + (mparams.granularity - SIZE_T_ONE))\\\n   & ~(mparams.granularity - SIZE_T_ONE))\n\n\n/* For mmap, use granularity alignment on windows, else page-align */\n#ifdef WIN32\n#define mmap_align(S) granularity_align(S)\n#else\n#define mmap_align(S) page_align(S)\n#endif\n\n/* For sys_alloc, enough padding to ensure can malloc request on success */\n#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)\n\n#define is_page_aligned(S)\\\n   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)\n#define is_granularity_aligned(S)\\\n   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)\n\n/*  True if segment S holds address A */\n#define segment_holds(S, A)\\\n  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)\n\n/* Return segment holding given address */\nstatic msegmentptr segment_holding(mstate m, char* addr) {\n  msegmentptr sp = &m->seg;\n  for (;;) {\n    if (addr >= sp->base && addr < sp->base + sp->size)\n      return sp;\n    if ((sp = sp->next) == 0)\n      return 0;\n  }\n}\n\n/* Return true if segment contains a segment link */\nstatic int has_segment_link(mstate m, msegmentptr ss) {\n  msegmentptr sp = &m->seg;\n  for (;;) {\n    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)\n      return 1;\n    if ((sp = sp->next) == 0)\n      return 0;\n  }\n}\n\n#ifndef MORECORE_CANNOT_TRIM\n#define should_trim(M,s)  ((s) > (M)->trim_check)\n#else  /* MORECORE_CANNOT_TRIM */\n#define should_trim(M,s)  (0)\n#endif /* MORECORE_CANNOT_TRIM */\n\n/*\n  TOP_FOOT_SIZE is padding at the end of a segment, including space\n  that may be needed to place segment records and fenceposts when new\n  noncontiguous segments are added.\n*/\n#define TOP_FOOT_SIZE\\\n  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)\n\n\n/* -------------------------------  Hooks -------------------------------- */\n\n/*\n  PREACTION should be defined to return 0 on success, and nonzero on\n  failure. If you are not using locking, you can redefine these to do\n  anything you like.\n*/\n\n#if USE_LOCKS\n#define PREACTION(M)  ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)\n#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }\n#else /* USE_LOCKS */\n\n#ifndef PREACTION\n#define PREACTION(M) (0)\n#endif  /* PREACTION */\n\n#ifndef POSTACTION\n#define POSTACTION(M)\n#endif  /* POSTACTION */\n\n#endif /* USE_LOCKS */\n\n/*\n  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.\n  USAGE_ERROR_ACTION is triggered on detected bad frees and\n  reallocs. The argument p is an address that might have triggered the\n  fault. It is ignored by the two predefined actions, but might be\n  useful in custom actions that try to help diagnose errors.\n*/\n\n#if PROCEED_ON_ERROR\n\n/* A count of the number of corruption errors causing resets */\nint malloc_corruption_error_count;\n\n/* default corruption action */\nstatic void reset_on_error(mstate m);\n\n#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)\n#define USAGE_ERROR_ACTION(m, p)\n\n#else /* PROCEED_ON_ERROR */\n\n#ifndef CORRUPTION_ERROR_ACTION\n#define CORRUPTION_ERROR_ACTION(m) ABORT\n#endif /* CORRUPTION_ERROR_ACTION */\n\n#ifndef USAGE_ERROR_ACTION\n#define USAGE_ERROR_ACTION(m,p) ABORT\n#endif /* USAGE_ERROR_ACTION */\n\n#endif /* PROCEED_ON_ERROR */\n\n\n/* -------------------------- Debugging setup ---------------------------- */\n\n#if ! DEBUG\n\n#define check_free_chunk(M,P)\n#define check_inuse_chunk(M,P)\n#define check_malloced_chunk(M,P,N)\n#define check_mmapped_chunk(M,P)\n#define check_malloc_state(M)\n#define check_top_chunk(M,P)\n\n#else /* DEBUG */\n#define check_free_chunk(M,P)       do_check_free_chunk(M,P)\n#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)\n#define check_top_chunk(M,P)        do_check_top_chunk(M,P)\n#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)\n#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)\n#define check_malloc_state(M)       do_check_malloc_state(M)\n\nstatic void   do_check_any_chunk(mstate m, mchunkptr p);\nstatic void   do_check_top_chunk(mstate m, mchunkptr p);\nstatic void   do_check_mmapped_chunk(mstate m, mchunkptr p);\nstatic void   do_check_inuse_chunk(mstate m, mchunkptr p);\nstatic void   do_check_free_chunk(mstate m, mchunkptr p);\nstatic void   do_check_malloced_chunk(mstate m, void* mem, size_t s);\nstatic void   do_check_tree(mstate m, tchunkptr t);\nstatic void   do_check_treebin(mstate m, bindex_t i);\nstatic void   do_check_smallbin(mstate m, bindex_t i);\nstatic void   do_check_malloc_state(mstate m);\nstatic int    bin_find(mstate m, mchunkptr x);\nstatic size_t traverse_and_check(mstate m);\n#endif /* DEBUG */\n\n/* ---------------------------- Indexing Bins ---------------------------- */\n\n#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)\n#define small_index(s)      (bindex_t)((s)  >> SMALLBIN_SHIFT)\n#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)\n#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))\n\n/* addressing by index. See above about smallbin repositioning */\n#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))\n#define treebin_at(M,i)     ((persist<tbinptr>*)&((M)->treebins[i]))\n\n/* assign tree index for size S to variable I. Use x86 asm if possible  */\n#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))\n#define compute_tree_index(S, I)\\\n{\\\n  unsigned int X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \\\n    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\\\n  }\\\n}\n\n#elif defined (__INTEL_COMPILER)\n#define compute_tree_index(S, I)\\\n{\\\n  size_t X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int K = _bit_scan_reverse (X); \\\n    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\\\n  }\\\n}\n\n#elif defined(_MSC_VER) && _MSC_VER>=1300\n#define compute_tree_index(S, I)\\\n{\\\n  size_t X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int K;\\\n    _BitScanReverse((DWORD *) &K, (DWORD) X);\\\n    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\\\n  }\\\n}\n\n#else /* GNUC */\n#define compute_tree_index(S, I)\\\n{\\\n  size_t X = S >> TREEBIN_SHIFT;\\\n  if (X == 0)\\\n    I = 0;\\\n  else if (X > 0xFFFF)\\\n    I = NTREEBINS-1;\\\n  else {\\\n    unsigned int Y = (unsigned int)X;\\\n    unsigned int N = ((Y - 0x100) >> 16) & 8;\\\n    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\\\n    N += K;\\\n    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\\\n    K = 14 - N + ((Y <<= K) >> 15);\\\n    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\\\n  }\\\n}\n#endif /* GNUC */\n\n/* Bit representing maximum resolved size in a treebin at i */\n#define bit_for_tree_index(i) \\\n   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)\n\n/* Shift placing maximum resolved bit in a treebin at i as sign bit */\n#define leftshift_for_tree_index(i) \\\n   ((i == NTREEBINS-1)? 0 : \\\n    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))\n\n/* The size of the smallest chunk held in bin with index i */\n#define minsize_for_tree_index(i) \\\n   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \\\n   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))\n\n\n/* ------------------------ Operations on bin maps ----------------------- */\n\n/* bit corresponding to given index */\n#define idx2bit(i)              ((binmap_t)(1) << (i))\n\n/* Mark/Clear bits with given index */\n#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))\n#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))\n#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))\n\n#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))\n#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))\n#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))\n\n/* isolate the least set bit of a bitmap */\n#define least_bit(x)         ((x) & -(x))\n\n/* mask with all bits to left of least bit of x on */\n#define left_bits(x)         ((x<<1) | -(x<<1))\n\n/* mask with all bits to left of or equal to least bit of x on */\n#define same_or_left_bits(x) ((x) | -(x))\n\n/* index corresponding to given bit. Use x86 asm if possible */\n\n#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int J;\\\n  J = __builtin_ctz(X); \\\n  I = (bindex_t)J;\\\n}\n\n#elif defined (__INTEL_COMPILER)\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int J;\\\n  J = _bit_scan_forward (X); \\\n  I = (bindex_t)J;\\\n}\n\n#elif defined(_MSC_VER) && _MSC_VER>=1300\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int J;\\\n  _BitScanForward((DWORD *) &J, X);\\\n  I = (bindex_t)J;\\\n}\n\n#elif USE_BUILTIN_FFS\n#define compute_bit2idx(X, I) I = ffs(X)-1\n\n#else\n#define compute_bit2idx(X, I)\\\n{\\\n  unsigned int Y = X - 1;\\\n  unsigned int K = Y >> (16-4) & 16;\\\n  unsigned int N = K;        Y >>= K;\\\n  N += K = Y >> (8-3) &  8;  Y >>= K;\\\n  N += K = Y >> (4-2) &  4;  Y >>= K;\\\n  N += K = Y >> (2-1) &  2;  Y >>= K;\\\n  N += K = Y >> (1-0) &  1;  Y >>= K;\\\n  I = (bindex_t)(N + Y);\\\n}\n#endif /* GNUC */\n\n\n/* ----------------------- Runtime Check Support ------------------------- */\n\n/*\n  For security, the main invariant is that malloc/free/etc never\n  writes to a static address other than malloc_state, unless static\n  malloc_state itself has been corrupted, which cannot occur via\n  malloc (because of these checks). In essence this means that we\n  believe all pointers, sizes, maps etc held in malloc_state, but\n  check all of those linked or offsetted from other embedded data\n  structures.  These checks are interspersed with main code in a way\n  that tends to minimize their run-time cost.\n\n  When FOOTERS is defined, in addition to range checking, we also\n  verify footer fields of inuse chunks, which can be used guarantee\n  that the mstate controlling malloc/free is intact.  This is a\n  streamlined version of the approach described by William Robertson\n  et al in \"Run-time Detection of Heap-based Overflows\" LISA'03\n  http://www.usenix.org/events/lisa03/tech/robertson.html The footer\n  of an inuse chunk holds the xor of its mstate and a random seed,\n  that is checked upon calls to free() and realloc().  This is\n  (probabalistically) unguessable from outside the program, but can be\n  computed by any code successfully malloc'ing any chunk, so does not\n  itself provide protection against code that has already broken\n  security through some other means.  Unlike Robertson et al, we\n  always dynamically check addresses of all offset chunks (previous,\n  next, etc). This turns out to be cheaper than relying on hashes.\n*/\n\n#if !INSECURE\n/* Check if address a is at least as high as any from MORECORE or MMAP */\n#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)\n/* Check if address of next chunk n is higher than base chunk p */\n#define ok_next(p, n)    ((char*)(p) < (char*)(n))\n/* Check if p has inuse status */\n#define ok_inuse(p)     is_inuse(p)\n/* Check if p has its pinuse bit on */\n#define ok_pinuse(p)     pinuse(p)\n\n#else /* !INSECURE */\n#define ok_address(M, a) (1)\n#define ok_next(b, n)    (1)\n#define ok_inuse(p)      (1)\n#define ok_pinuse(p)     (1)\n#endif /* !INSECURE */\n\n#if (FOOTERS && !INSECURE)\n/* Check if (alleged) mstate m has expected magic field */\n#define ok_magic(M)      ((M)->magic == mparams.magic)\n#else  /* (FOOTERS && !INSECURE) */\n#define ok_magic(M)      (1)\n#endif /* (FOOTERS && !INSECURE) */\n\n/* In gcc, use __builtin_expect to minimize impact of checks */\n#if !INSECURE\n#if defined(__GNUC__) && __GNUC__ >= 3\n#define RTCHECK(e)  __builtin_expect(e, 1)\n#else /* GNUC */\n#define RTCHECK(e)  (e)\n#endif /* GNUC */\n#else /* !INSECURE */\n#define RTCHECK(e)  (1)\n#endif /* !INSECURE */\n\n/* macros to set up inuse chunks with or without footers */\n\n#if !FOOTERS\n\n#define mark_inuse_foot(M,p,s)\n\n/* Macros for setting head/foot of non-mmapped chunks */\n\n/* Set cinuse bit and pinuse bit of next chunk */\n#define set_inuse(M,p,s)\\\n  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\\\n  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)\n\n/* Set cinuse and pinuse of this chunk and pinuse of next chunk */\n#define set_inuse_and_pinuse(M,p,s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\\\n  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)\n\n/* Set size, cinuse and pinuse bit of this chunk */\n#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))\n\n#else /* FOOTERS */\n\n/* Set foot of inuse chunk to be xor of mstate and seed */\n#define mark_inuse_foot(M,p,s)\\\n  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))\n\n#define get_mstate_for(p)\\\n  ((mstate)(((mchunkptr)((char*)(p) +\\\n    (chunksize(p))))->prev_foot ^ mparams.magic))\n\n#define set_inuse(M,p,s)\\\n  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\\\n  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \\\n  mark_inuse_foot(M,p,s))\n\n#define set_inuse_and_pinuse(M,p,s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\\\n  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\\\n mark_inuse_foot(M,p,s))\n\n#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\\\n  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\\\n  mark_inuse_foot(M, p, s))\n\n#endif /* !FOOTERS */\n\n/* ---------------------------- setting mparams -------------------------- */\n\n#if LOCK_AT_FORK\nstatic void pre_fork(void)         { ACQUIRE_LOCK(&(gm)->mutex); }\nstatic void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); }\nstatic void post_fork_child(void)  { INITIAL_LOCK(&(gm)->mutex); }\n#endif /* LOCK_AT_FORK */\n\n/* Initialize mparams */\nstatic int init_mparams(void) {\n#ifdef NEED_GLOBAL_LOCK_INIT\n  if (malloc_global_mutex_status <= 0)\n    init_malloc_global_mutex();\n#endif\n\n  ACQUIRE_MALLOC_GLOBAL_LOCK();\n  if (mparams.magic == 0) {\n    size_t magic;\n    size_t psize;\n    size_t gsize;\n\n#ifndef WIN32\n    psize = malloc_getpagesize;\n    gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);\n#else /* WIN32 */\n    {\n      SYSTEM_INFO system_info;\n      GetSystemInfo(&system_info);\n      psize = system_info.dwPageSize;\n      gsize = ((DEFAULT_GRANULARITY != 0)?\n               DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);\n    }\n#endif /* WIN32 */\n\n    /* Sanity-check configuration:\n       size_t must be unsigned and as wide as pointer type.\n       ints must be at least 4 bytes.\n       alignment must be at least 8.\n       Alignment, min chunk size, and page size must all be powers of 2.\n    */\n    if ((sizeof(size_t) != sizeof(char*)) ||\n        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||\n        (sizeof(int) < 4)  ||\n        (MALLOC_ALIGNMENT < (size_t)8U) ||\n        ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||\n        ((MCHUNK_SIZE      & (MCHUNK_SIZE-SIZE_T_ONE))      != 0) ||\n        ((gsize            & (gsize-SIZE_T_ONE))            != 0) ||\n        ((psize            & (psize-SIZE_T_ONE))            != 0))\n      ABORT;\n    mparams.granularity = gsize;\n    mparams.page_size = psize;\n    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;\n    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;\n#if MORECORE_CONTIGUOUS\n    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;\n#else  /* MORECORE_CONTIGUOUS */\n    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;\n#endif /* MORECORE_CONTIGUOUS */\n\n#if !ONLY_MSPACES\n    /* Set up lock for main malloc area */\n    gm->mflags = mparams.default_mflags;\n    (void)INITIAL_LOCK(&gm->mutex);\n#endif\n#if LOCK_AT_FORK\n    pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);\n#endif\n\n    {\n#if USE_DEV_RANDOM\n      int fd;\n      unsigned char buf[sizeof(size_t)];\n      /* Try to use /dev/urandom, else fall back on using time */\n      if ((fd = open(\"/dev/urandom\", O_RDONLY)) >= 0 &&\n          read(fd, buf, sizeof(buf)) == sizeof(buf)) {\n        magic = *((size_t *) buf);\n        close(fd);\n      }\n      else\n#endif /* USE_DEV_RANDOM */\n#ifdef WIN32\n      magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);\n#elif defined(LACKS_TIME_H)\n      magic = (size_t)&magic ^ (size_t)0x55555555U;\n#else\n      magic = (size_t)(time(0) ^ (size_t)0x55555555U);\n#endif\n      magic |= (size_t)8U;    /* ensure nonzero */\n      magic &= ~(size_t)7U;   /* improve chances of fault for bad values */\n      /* Until memory modes commonly available, use volatile-write */\n      (*(volatile size_t *)(&(mparams.magic))) = magic;\n    }\n  }\n\n  RELEASE_MALLOC_GLOBAL_LOCK();\n  return 1;\n}\n\n/* support for mallopt */\nstatic int change_mparam(int param_number, int value) {\n  size_t val;\n  ensure_initialization();\n  val = (value == -1)? MAX_SIZE_T : (size_t)value;\n  switch(param_number) {\n  case M_TRIM_THRESHOLD:\n    mparams.trim_threshold = val;\n    return 1;\n  case M_GRANULARITY:\n    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {\n      mparams.granularity = val;\n      return 1;\n    }\n    else\n      return 0;\n  case M_MMAP_THRESHOLD:\n    mparams.mmap_threshold = val;\n    return 1;\n  default:\n    return 0;\n  }\n}\n\n#if DEBUG\n/* ------------------------- Debugging Support --------------------------- */\n\n/* Check properties of any chunk, whether free, inuse, mmapped etc  */\nstatic void do_check_any_chunk(mstate m, mchunkptr p) {\n  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));\n  assert(ok_address(m, p));\n}\n\n/* Check properties of top chunk */\nstatic void do_check_top_chunk(mstate m, mchunkptr p) {\n  msegmentptr sp = segment_holding(m, (char*)p);\n  size_t  sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */\n  assert(sp != 0);\n  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));\n  assert(ok_address(m, p));\n  assert(sz == m->topsize);\n  assert(sz > 0);\n  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);\n  assert(pinuse(p));\n  assert(!pinuse(chunk_plus_offset(p, sz)));\n}\n\n/* Check properties of (inuse) mmapped chunks */\nstatic void do_check_mmapped_chunk(mstate m, mchunkptr p) {\n  size_t  sz = chunksize(p);\n  size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);\n  assert(is_mmapped(p));\n  assert(use_mmap(m));\n  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));\n  assert(ok_address(m, p));\n  assert(!is_small(sz));\n  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);\n  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);\n  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);\n}\n\n/* Check properties of inuse chunks */\nstatic void do_check_inuse_chunk(mstate m, mchunkptr p) {\n  do_check_any_chunk(m, p);\n  assert(is_inuse(p));\n  assert(next_pinuse(p));\n  /* If not pinuse and not mmapped, previous chunk has OK offset */\n  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);\n  if (is_mmapped(p))\n    do_check_mmapped_chunk(m, p);\n}\n\n/* Check properties of free chunks */\nstatic void do_check_free_chunk(mstate m, mchunkptr p) {\n  size_t sz = chunksize(p);\n  mchunkptr next = chunk_plus_offset(p, sz);\n  do_check_any_chunk(m, p);\n  assert(!is_inuse(p));\n  assert(!next_pinuse(p));\n  assert (!is_mmapped(p));\n  if (p != m->dv && p != m->top) {\n    if (sz >= MIN_CHUNK_SIZE) {\n      assert((sz & CHUNK_ALIGN_MASK) == 0);\n      assert(is_aligned(chunk2mem(p)));\n      assert(next->prev_foot == sz);\n      assert(pinuse(p));\n      assert (next == m->top || is_inuse(next));\n      assert(p->fd->bk == p);\n      assert(p->bk->fd == p);\n    }\n    else  /* markers are always of size SIZE_T_SIZE */\n      assert(sz == SIZE_T_SIZE);\n  }\n}\n\n/* Check properties of malloced chunks at the point they are malloced */\nstatic void do_check_malloced_chunk(mstate m, void* mem, size_t s) {\n  if (mem != 0) {\n    mchunkptr p = mem2chunk(mem);\n    size_t sz = p->head & ~INUSE_BITS;\n    do_check_inuse_chunk(m, p);\n    assert((sz & CHUNK_ALIGN_MASK) == 0);\n    assert(sz >= MIN_CHUNK_SIZE);\n    assert(sz >= s);\n    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */\n    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));\n  }\n}\n\n/* Check a tree and its subtrees.  */\nstatic void do_check_tree(mstate m, tchunkptr t) {\n  tchunkptr head = 0;\n  tchunkptr u = t;\n  bindex_t tindex = t->index;\n  size_t tsize = chunksize(t);\n  bindex_t idx;\n  compute_tree_index(tsize, idx);\n  assert(tindex == idx);\n  assert(tsize >= MIN_LARGE_SIZE);\n  assert(tsize >= minsize_for_tree_index(idx));\n  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));\n\n  do { /* traverse through chain of same-sized nodes */\n    do_check_any_chunk(m, ((mchunkptr)u));\n    assert(u->index == tindex);\n    assert(chunksize(u) == tsize);\n    assert(!is_inuse(u));\n    assert(!next_pinuse(u));\n    assert(u->fd->bk == u);\n    assert(u->bk->fd == u);\n    if (u->parent == 0) {\n      assert(u->child[0] == 0);\n      assert(u->child[1] == 0);\n    }\n    else {\n      assert(head == 0); /* only one node on chain has parent */\n      head = u;\n      assert(u->parent != u);\n      assert (u->parent->child[0] == u ||\n              u->parent->child[1] == u ||\n              *((tbinptr*)(u->parent)) == u);\n      if (u->child[0] != 0) {\n        assert(u->child[0]->parent == u);\n        assert(u->child[0] != u);\n        do_check_tree(m, u->child[0]);\n      }\n      if (u->child[1] != 0) {\n        assert(u->child[1]->parent == u);\n        assert(u->child[1] != u);\n        do_check_tree(m, u->child[1]);\n      }\n      if (u->child[0] != 0 && u->child[1] != 0) {\n        assert(chunksize(u->child[0]) < chunksize(u->child[1]));\n      }\n    }\n    u = u->fd;\n  } while (u != t);\n  assert(head != 0);\n}\n\n/*  Check all the chunks in a treebin.  */\nstatic void do_check_treebin(mstate m, bindex_t i) {\n  tbinptr* tb = treebin_at(m, i);\n  tchunkptr t = *tb;\n  int empty = (m->treemap & (1U << i)) == 0;\n  if (t == 0)\n    assert(empty);\n  if (!empty)\n    do_check_tree(m, t);\n}\n\n/*  Check all the chunks in a smallbin.  */\nstatic void do_check_smallbin(mstate m, bindex_t i) {\n  sbinptr b = smallbin_at(m, i);\n  mchunkptr p = b->bk;\n  unsigned int empty = (m->smallmap & (1U << i)) == 0;\n  if (p == b)\n    assert(empty);\n  if (!empty) {\n    for (; p != b; p = p->bk) {\n      size_t size = chunksize(p);\n      mchunkptr q;\n      /* each chunk claims to be free */\n      do_check_free_chunk(m, p);\n      /* chunk belongs in bin */\n      assert(small_index(size) == i);\n      assert(p->bk == b || chunksize(p->bk) == chunksize(p));\n      /* chunk is followed by an inuse chunk */\n      q = next_chunk(p);\n      if (q->head != FENCEPOST_HEAD)\n        do_check_inuse_chunk(m, q);\n    }\n  }\n}\n\n/* Find x in a bin. Used in other check functions. */\nstatic int bin_find(mstate m, mchunkptr x) {\n  size_t size = chunksize(x);\n  if (is_small(size)) {\n    bindex_t sidx = small_index(size);\n    sbinptr b = smallbin_at(m, sidx);\n    if (smallmap_is_marked(m, sidx)) {\n      mchunkptr p = b;\n      do {\n        if (p == x)\n          return 1;\n      } while ((p = p->fd) != b);\n    }\n  }\n  else {\n    bindex_t tidx;\n    compute_tree_index(size, tidx);\n    if (treemap_is_marked(m, tidx)) {\n      tchunkptr t = *treebin_at(m, tidx);\n      size_t sizebits = size << leftshift_for_tree_index(tidx);\n      while (t != 0 && chunksize(t) != size) {\n        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];\n        sizebits <<= 1;\n      }\n      if (t != 0) {\n        tchunkptr u = t;\n        do {\n          if (u == (tchunkptr)x)\n            return 1;\n        } while ((u = u->fd) != t);\n      }\n    }\n  }\n  return 0;\n}\n\n/* Traverse each chunk and check it; return total */\nstatic size_t traverse_and_check(mstate m) {\n  size_t sum = 0;\n  if (is_initialized(m)) {\n    msegmentptr s = &m->seg;\n    sum += m->topsize + TOP_FOOT_SIZE;\n    while (s != 0) {\n      mchunkptr q = align_as_chunk(s->base);\n      mchunkptr lastq = 0;\n      assert(pinuse(q));\n      while (segment_holds(s, q) &&\n             q != m->top && q->head != FENCEPOST_HEAD) {\n        sum += chunksize(q);\n        if (is_inuse(q)) {\n          assert(!bin_find(m, q));\n          do_check_inuse_chunk(m, q);\n        }\n        else {\n          assert(q == m->dv || bin_find(m, q));\n          assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */\n          do_check_free_chunk(m, q);\n        }\n        lastq = q;\n        q = next_chunk(q);\n      }\n      s = s->next;\n    }\n  }\n  return sum;\n}\n\n\n/* Check all properties of malloc_state. */\nstatic void do_check_malloc_state(mstate m) {\n  bindex_t i;\n  size_t total;\n  /* check bins */\n  for (i = 0; i < NSMALLBINS; ++i)\n    do_check_smallbin(m, i);\n  for (i = 0; i < NTREEBINS; ++i)\n    do_check_treebin(m, i);\n\n  if (m->dvsize != 0) { /* check dv chunk */\n    do_check_any_chunk(m, m->dv);\n    assert(m->dvsize == chunksize(m->dv));\n    assert(m->dvsize >= MIN_CHUNK_SIZE);\n    assert(bin_find(m, m->dv) == 0);\n  }\n\n  if (m->top != 0) {   /* check top chunk */\n    do_check_top_chunk(m, m->top);\n    /*assert(m->topsize == chunksize(m->top)); redundant */\n    assert(m->topsize > 0);\n    assert(bin_find(m, m->top) == 0);\n  }\n\n  total = traverse_and_check(m);\n  assert(total <= m->footprint);\n  assert(m->footprint <= m->max_footprint);\n}\n#endif /* DEBUG */\n\n/* ----------------------------- statistics ------------------------------ */\n\n#if !NO_MALLINFO\nstatic struct mallinfo internal_mallinfo(mstate m) {\n  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\n  ensure_initialization();\n  if (!PREACTION(m)) {\n    check_malloc_state(m);\n    if (is_initialized(m)) {\n      size_t nfree = SIZE_T_ONE; /* top always free */\n      size_t mfree = m->topsize + TOP_FOOT_SIZE;\n      size_t sum = mfree;\n      msegmentptr s = &m->seg;\n      while (s != 0) {\n        mchunkptr q = align_as_chunk(s->base);\n        while (segment_holds(s, q) &&\n               q != m->top && q->head != FENCEPOST_HEAD) {\n          size_t sz = chunksize(q);\n          sum += sz;\n          if (!is_inuse(q)) {\n            mfree += sz;\n            ++nfree;\n          }\n          q = next_chunk(q);\n        }\n        s = s->next;\n      }\n\n      nm.arena    = sum;\n      nm.ordblks  = nfree;\n      nm.hblkhd   = m->footprint - sum;\n      nm.usmblks  = m->max_footprint;\n      nm.uordblks = m->footprint - mfree;\n      nm.fordblks = mfree;\n      nm.keepcost = m->topsize;\n    }\n\n    POSTACTION(m);\n  }\n  return nm;\n}\n#endif /* !NO_MALLINFO */\n\n#if !NO_MALLOC_STATS\nstatic void internal_malloc_stats(mstate m) {\n  ensure_initialization();\n  if (!PREACTION(m)) {\n    size_t maxfp = 0;\n    size_t fp = 0;\n    size_t used = 0;\n    check_malloc_state(m);\n    if (is_initialized(m)) {\n      msegmentptr s = &m->seg;\n      maxfp = m->max_footprint;\n      fp = m->footprint;\n      used = fp - (m->topsize + TOP_FOOT_SIZE);\n\n      while (s != 0) {\n        mchunkptr q = align_as_chunk(s->base);\n        while (segment_holds(s, q) &&\n               q != m->top && q->head != FENCEPOST_HEAD) {\n          if (!is_inuse(q))\n            used -= chunksize(q);\n          q = next_chunk(q);\n        }\n        s = s->next;\n      }\n    }\n    POSTACTION(m); /* drop lock */\n    fprintf(stderr, \"max system bytes = %10lu\\n\", (unsigned long)(maxfp));\n    fprintf(stderr, \"system bytes     = %10lu\\n\", (unsigned long)(fp));\n    fprintf(stderr, \"in use bytes     = %10lu\\n\", (unsigned long)(used));\n  }\n}\n#endif /* NO_MALLOC_STATS */\n\n/* ----------------------- Operations on smallbins ----------------------- */\n\n/*\n  Various forms of linking and unlinking are defined as macros.  Even\n  the ones for trees, which are very long but have very short typical\n  paths.  This is ugly but reduces reliance on inlining support of\n  compilers.\n*/\n\n/* Link a free chunk into a smallbin  */\n#define insert_small_chunk(M, P, S) {\\\n  bindex_t I  = small_index(S);\\\n  mchunkptr B = smallbin_at(M, I);\\\n  mchunkptr F = B;\\\n  assert(S >= MIN_CHUNK_SIZE);\\\n  if (!smallmap_is_marked(M, I))\\\n    mark_smallmap(M, I);\\\n  else if (RTCHECK(ok_address(M, B->fd.pload())))\\\n    F = B->fd;\\\n  else {\\\n    CORRUPTION_ERROR_ACTION(M);\\\n  }\\\n  B->fd = P;\\\n  F->bk = P;\\\n  P->fd = F;\\\n  P->bk = B;\\\n}\n\n/* Unlink a chunk from a smallbin  */\n#define unlink_small_chunk(M, P, S) {\\\n  mchunkptr F = P->fd;\\\n  mchunkptr B = P->bk;\\\n  bindex_t I = small_index(S);\\\n  assert(P != B);\\\n  assert(P != F);\\\n  assert(chunksize(P) == small_index2size(I));\\\n  if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \\\n    if (B == F) {\\\n      clear_smallmap(M, I);\\\n    }\\\n    else if (RTCHECK(B == smallbin_at(M,I) ||\\\n                     (ok_address(M, B) && B->fd == P))) {\\\n      F->bk = B;\\\n      B->fd = F;\\\n    }\\\n    else {\\\n      CORRUPTION_ERROR_ACTION(M);\\\n    }\\\n  }\\\n  else {\\\n    CORRUPTION_ERROR_ACTION(M);\\\n  }\\\n}\n\n/* Unlink the first chunk from a smallbin */\n#define unlink_first_small_chunk(M, B, P, I) {\\\n  mchunkptr F = P->fd;\\\n  assert(P != B);\\\n  assert(P != F);\\\n  assert(chunksize(P) == small_index2size(I));\\\n  if (B == F) {\\\n    clear_smallmap(M, I);\\\n  }\\\n  else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\\\n    F->bk = B;\\\n    B->fd = F;\\\n  }\\\n  else {\\\n    CORRUPTION_ERROR_ACTION(M);\\\n  }\\\n}\n\n/* Replace dv node, binning the old one */\n/* Used only when dvsize known to be small */\n#define replace_dv(M, P, S) {\\\n  size_t DVS = M->dvsize;\\\n  assert(is_small(DVS));\\\n  if (DVS != 0) {\\\n    mchunkptr DV = M->dv;\\\n    insert_small_chunk(M, DV, DVS);\\\n  }\\\n  M->dvsize = S;\\\n  M->dv = P;\\\n}\n\n/* ------------------------- Operations on trees ------------------------- */\n\n/* Insert chunk into tree */\n#define insert_large_chunk(M, X, S) {\\\n  persist<tbinptr>* H;\\\n  bindex_t I;\\\n  compute_tree_index(S, I);\\\n  H = treebin_at(M, I);\\\n  X->index = I;\\\n  X->child[0] = X->child[1] = 0;\\\n  if (!treemap_is_marked(M, I)) {\\\n    mark_treemap(M, I);\\\n    *H = X;\\\n    X->parent = (tchunkptr)H;\\\n    X->fd = X->bk = X;\\\n  }\\\n  else {\\\n    tchunkptr T = *H;\\\n    size_t K = S << leftshift_for_tree_index(I);\\\n    for (;;) {\\\n      if (chunksize(T) != S) {\\\n        persist<tchunkptr>* C = (persist<tchunkptr>*)&(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\\\n        K <<= 1;\\\n        if (*C != 0)\\\n          T = *C;\\\n        else if (RTCHECK(ok_address(M, C))) {\\\n          *C = X;\\\n          X->parent = T;\\\n          X->fd = X->bk = X;\\\n          break;\\\n        }\\\n        else {\\\n          CORRUPTION_ERROR_ACTION(M);\\\n          break;\\\n        }\\\n      }\\\n      else {\\\n        tchunkptr F = T->fd;\\\n        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\\\n          T->fd = F->bk = X;\\\n          X->fd = F;\\\n          X->bk = T;\\\n          X->parent = 0;\\\n          break;\\\n        }\\\n        else {\\\n          CORRUPTION_ERROR_ACTION(M);\\\n          break;\\\n        }\\\n      }\\\n    }\\\n  }\\\n}\n\n/*\n  Unlink steps:\n\n  1. If x is a chained node, unlink it from its same-sized fd/bk links\n     and choose its bk node as its replacement.\n  2. If x was the last node of its size, but not a leaf node, it must\n     be replaced with a leaf node (not merely one with an open left or\n     right), to make sure that lefts and rights of descendents\n     correspond properly to bit masks.  We use the rightmost descendent\n     of x.  We could use any other leaf, but this is easy to locate and\n     tends to counteract removal of leftmosts elsewhere, and so keeps\n     paths shorter than minimally guaranteed.  This doesn't loop much\n     because on average a node in a tree is near the bottom.\n  3. If x is the base of a chain (i.e., has parent links) relink\n     x's parent and children to x's replacement (or null if none).\n*/\n\n#define unlink_large_chunk(M, X) {\\\n  tchunkptr XP = X->parent;\\\n  tchunkptr R;\\\n  if (X->bk != X) {\\\n    tchunkptr F = X->fd;\\\n    R = X->bk;\\\n    if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\\\n      F->bk = R;\\\n      R->fd = F;\\\n    }\\\n    else {\\\n      CORRUPTION_ERROR_ACTION(M);\\\n    }\\\n  }\\\n  else {\\\n    persist<tchunkptr>* RP;\\\n    if (((R = *(RP = (persist<tchunkptr>*)&(X->child[1]))) != 0) ||\\\n        ((R = *(RP = (persist<tchunkptr>*)&(X->child[0]))) != 0)) {\\\n      persist<tchunkptr>* CP;\\\n      while ((*(CP = (persist<tchunkptr>*)&(R->child[1])) != 0) ||\\\n             (*(CP = (persist<tchunkptr>*)&(R->child[0])) != 0)) {\\\n        R = *(RP = CP);\\\n      }\\\n      if (RTCHECK(ok_address(M, RP)))\\\n        *RP = 0;\\\n      else {\\\n        CORRUPTION_ERROR_ACTION(M);\\\n      }\\\n    }\\\n  }\\\n  if (XP != 0) {\\\n    persist<tbinptr>* H = treebin_at(M, X->index);\\\n    if (X == *H) {\\\n      if ((*H = R) == 0) \\\n        clear_treemap(M, X->index);\\\n    }\\\n    else if (RTCHECK(ok_address(M, XP))) {\\\n      if (XP->child[0] == X) \\\n        XP->child[0] = R;\\\n      else \\\n        XP->child[1] = R;\\\n    }\\\n    else\\\n      CORRUPTION_ERROR_ACTION(M);\\\n    if (R != 0) {\\\n      if (RTCHECK(ok_address(M, R))) {\\\n        tchunkptr C0, C1;\\\n        R->parent = XP;\\\n        if ((C0 = X->child[0]) != 0) {\\\n          if (RTCHECK(ok_address(M, C0))) {\\\n            R->child[0] = C0;\\\n            C0->parent = R;\\\n          }\\\n          else\\\n            CORRUPTION_ERROR_ACTION(M);\\\n        }\\\n        if ((C1 = X->child[1]) != 0) {\\\n          if (RTCHECK(ok_address(M, C1))) {\\\n            R->child[1] = C1;\\\n            C1->parent = R;\\\n          }\\\n          else\\\n            CORRUPTION_ERROR_ACTION(M);\\\n        }\\\n      }\\\n      else\\\n        CORRUPTION_ERROR_ACTION(M);\\\n    }\\\n  }\\\n}\n\n/* Relays to large vs small bin operations */\n\n#define insert_chunk(M, P, S)\\\n  if (is_small(S)) insert_small_chunk(M, P, S)\\\n  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }\n\n#define unlink_chunk(M, P, S)\\\n  if (is_small(S)) unlink_small_chunk(M, P, S)\\\n  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }\n\n\n/* Relays to internal calls to malloc/free from realloc, memalign etc */\n\n#if ONLY_MSPACES\n#define internal_malloc(m, b) mspace_malloc(m, b)\n#define internal_free(m, mem) mspace_free(m,mem);\n#else /* ONLY_MSPACES */\n#if MSPACES\n#define internal_malloc(m, b)\\\n  ((m == gm)? dlmalloc(b) : mspace_malloc(m, b))\n#define internal_free(m, mem)\\\n   if (m == gm) dlfree(mem); else mspace_free(m,mem);\n#else /* MSPACES */\n#define internal_malloc(m, b) dlmalloc(b)\n#define internal_free(m, mem) dlfree(mem)\n#endif /* MSPACES */\n#endif /* ONLY_MSPACES */\n\n/* -----------------------  Direct-mmapping chunks ----------------------- */\n\n/*\n  Directly mmapped chunks are set up with an offset to the start of\n  the mmapped region stored in the prev_foot field of the chunk. This\n  allows reconstruction of the required argument to MUNMAP when freed,\n  and also allows adjustment of the returned chunk to meet alignment\n  requirements (especially in memalign).\n*/\n\n/* Malloc using mmap */\nstatic void* mmap_alloc(mstate m, size_t nb) {\n  size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);\n  if (m->footprint_limit.pload() != 0) {\n    size_t fp = m->footprint + mmsize;\n    if (fp <= m->footprint || fp > m->footprint_limit)\n      return 0;\n  }\n  if (mmsize > nb) {     /* Check for wrap around 0 */\n    char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));\n    if (mm != CMFAIL) {\n      size_t offset = align_offset(chunk2mem(mm));\n      size_t psize = mmsize - offset - MMAP_FOOT_PAD;\n      mchunkptr p = (mchunkptr)(mm + offset);\n      p->prev_foot = offset;\n      p->head = psize;\n      mark_inuse_foot(m, p, psize);\n      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;\n      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;\n\n      if (m->least_addr == 0 || mm < m->least_addr)\n        m->least_addr = mm;\n      if ((m->footprint += mmsize) > m->max_footprint)\n        m->max_footprint = m->footprint;\n      assert(is_aligned(chunk2mem(p)));\n      check_mmapped_chunk(m, p);\n      return chunk2mem(p);\n    }\n  }\n  return 0;\n}\n\n/* Realloc using mmap */\nstatic mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {\n  size_t oldsize = chunksize(oldp);\n  (void)flags; /* placate people compiling -Wunused */\n  if (is_small(nb)) /* Can't shrink mmap regions below small size */\n    return 0;\n  /* Keep old chunk if big enough but not too big */\n  if (oldsize >= nb + SIZE_T_SIZE &&\n      (oldsize - nb) <= (mparams.granularity << 1))\n    return oldp;\n  else {\n    size_t offset = oldp->prev_foot;\n    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;\n    size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);\n    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,\n                                  oldmmsize, newmmsize, flags);\n    if (cp != CMFAIL) {\n      mchunkptr newp = (mchunkptr)(cp + offset);\n      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;\n      newp->head = psize;\n      mark_inuse_foot(m, newp, psize);\n      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;\n      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;\n\n      if (cp < m->least_addr)\n        m->least_addr = cp;\n      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)\n        m->max_footprint = m->footprint;\n      check_mmapped_chunk(m, newp);\n      return newp;\n    }\n  }\n  return 0;\n}\n\n\n/* -------------------------- mspace management -------------------------- */\n\n/* Initialize top chunk and its size */\nstatic void init_top(mstate m, mchunkptr p, size_t psize) {\n  /* Ensure alignment */\n  size_t offset = align_offset(chunk2mem(p));\n  p = (mchunkptr)((char*)p + offset);\n  psize -= offset;\n\n  m->top = p;\n  m->topsize = psize;\n  p->head = psize | PINUSE_BIT;\n  /* set size of fake trailing chunk holding overhead space only once */\n  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;\n  m->trim_check = mparams.trim_threshold; /* reset on each update */\n}\n\n/* Initialize bins for a new mstate that is otherwise zeroed out */\nstatic void init_bins(mstate m) {\n  /* Establish circular links for smallbins */\n  bindex_t i;\n  for (i = 0; i < NSMALLBINS; ++i) {\n    sbinptr bin = smallbin_at(m,i);\n    bin->fd = bin->bk = bin;\n  }\n}\n\n#if PROCEED_ON_ERROR\n\n/* default corruption action */\nstatic void reset_on_error(mstate m) {\n  int i;\n  ++malloc_corruption_error_count;\n  /* Reinitialize fields to forget about all memory */\n  m->smallmap = m->treemap = 0;\n  m->dvsize = m->topsize = 0;\n  m->seg.base = 0;\n  m->seg.size = 0;\n  m->seg.next = 0;\n  m->top = m->dv = 0;\n  for (i = 0; i < NTREEBINS; ++i)\n    *treebin_at(m, i) = 0;\n  init_bins(m);\n}\n#endif /* PROCEED_ON_ERROR */\n\n/* Allocate chunk and prepend remainder with chunk in successor base. */\nstatic void* prepend_alloc(mstate m, char* newbase, char* oldbase,\n                           size_t nb) {\n  mchunkptr p = align_as_chunk(newbase);\n  mchunkptr oldfirst = align_as_chunk(oldbase);\n  size_t psize = (char*)oldfirst - (char*)p;\n  mchunkptr q = chunk_plus_offset(p, nb);\n  size_t qsize = psize - nb;\n  set_size_and_pinuse_of_inuse_chunk(m, p, nb);\n\n  assert((char*)oldfirst > (char*)q);\n  assert(pinuse(oldfirst));\n  assert(qsize >= MIN_CHUNK_SIZE);\n\n  /* consolidate remainder with first chunk of old base */\n  if (oldfirst == m->top) {\n    size_t tsize = m->topsize += qsize;\n    m->top = q;\n    q->head = tsize | PINUSE_BIT;\n    check_top_chunk(m, q);\n  }\n  else if (oldfirst == m->dv) {\n    size_t dsize = m->dvsize += qsize;\n    m->dv = q;\n    set_size_and_pinuse_of_free_chunk(q, dsize);\n  }\n  else {\n    if (!is_inuse(oldfirst)) {\n      size_t nsize = chunksize(oldfirst);\n      unlink_chunk(m, oldfirst, nsize);\n      oldfirst = chunk_plus_offset(oldfirst, nsize);\n      qsize += nsize;\n    }\n    set_free_with_pinuse(q, qsize, oldfirst);\n    insert_chunk(m, q, qsize);\n    check_free_chunk(m, q);\n  }\n\n  check_malloced_chunk(m, chunk2mem(p), nb);\n  return chunk2mem(p);\n}\n\n/* Add a segment to hold a new noncontiguous region */\nstatic void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {\n  /* Determine locations and sizes of segment, fenceposts, old top */\n  char* old_top = (char*)m->top.pload();\n  msegmentptr oldsp = segment_holding(m, old_top);\n  char* old_end = oldsp->base + oldsp->size;\n  size_t ssize = pad_request(sizeof(struct malloc_segment));\n  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);\n  size_t offset = align_offset(chunk2mem(rawsp));\n  char* asp = rawsp + offset;\n  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;\n  mchunkptr sp = (mchunkptr)csp;\n  msegmentptr ss = (msegmentptr)(chunk2mem(sp));\n  mchunkptr tnext = chunk_plus_offset(sp, ssize);\n  mchunkptr p = tnext;\n  int nfences = 0;\n\n  /* reset top to new space */\n  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);\n\n  /* Set up segment record */\n  assert(is_aligned(ss));\n  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);\n  *ss = m->seg; /* Push current record */\n  m->seg.base = tbase;\n  m->seg.size = tsize;\n  m->seg.sflags = mmapped;\n  m->seg.next = ss;\n\n  /* Insert trailing fenceposts */\n  for (;;) {\n    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);\n    p->head = FENCEPOST_HEAD;\n    ++nfences;\n    if ((char*)(&(nextp->head)) < old_end)\n      p = nextp;\n    else\n      break;\n  }\n  assert(nfences >= 2);\n\n  /* Insert the rest of old top into a bin as an ordinary free chunk */\n  if (csp != old_top) {\n    mchunkptr q = (mchunkptr)old_top;\n    size_t psize = csp - old_top;\n    mchunkptr tn = chunk_plus_offset(q, psize);\n    set_free_with_pinuse(q, psize, tn);\n    insert_chunk(m, q, psize);\n  }\n\n  check_top_chunk(m, m->top);\n}\n\n/* -------------------------- System allocation -------------------------- */\n\n/* Get memory from system using MORECORE or MMAP */\nstatic void* sys_alloc(mstate m, size_t nb) {\n  char* tbase = CMFAIL;\n  size_t tsize = 0;\n  flag_t mmap_flag = 0;\n  size_t asize; /* allocation size */\n\n  ensure_initialization();\n\n  /* Directly map large chunks, but only if already initialized */\n  if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize.pload() != 0) {\n    void* mem = mmap_alloc(m, nb);\n    if (mem != 0)\n      return mem;\n  }\n\n  asize = granularity_align(nb + SYS_ALLOC_PADDING);\n  if (asize <= nb)\n    return 0; /* wraparound */\n  if (m->footprint_limit.pload() != 0) {\n    size_t fp = m->footprint + asize;\n    if (fp <= m->footprint || fp > m->footprint_limit)\n      return 0;\n  }\n\n  /*\n    Try getting memory in any of three ways (in most-preferred to\n    least-preferred order):\n    1. A call to MORECORE that can normally contiguously extend memory.\n       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or\n       or main space is mmapped or a previous contiguous call failed)\n    2. A call to MMAP new space (disabled if not HAVE_MMAP).\n       Note that under the default settings, if MORECORE is unable to\n       fulfill a request, and HAVE_MMAP is true, then mmap is\n       used as a noncontiguous system allocator. This is a useful backup\n       strategy for systems with holes in address spaces -- in this case\n       sbrk cannot contiguously expand the heap, but mmap may be able to\n       find space.\n    3. A call to MORECORE that cannot usually contiguously extend memory.\n       (disabled if not HAVE_MORECORE)\n\n   In all cases, we need to request enough bytes from system to ensure\n   we can malloc nb bytes upon success, so pad with enough space for\n   top_foot, plus alignment-pad to make sure we don't lose bytes if\n   not on boundary, and round this up to a granularity unit.\n  */\n\n  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {\n    char* br = CMFAIL;\n    size_t ssize = asize; /* sbrk call size */\n    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top.pload());\n    ACQUIRE_MALLOC_GLOBAL_LOCK();\n\n    if (ss == 0) {  /* First time through or recovery */\n      char* base = (char*)CALL_MORECORE(0);\n      if (base != CMFAIL) {\n        size_t fp;\n        /* Adjust to end on a page boundary */\n        if (!is_page_aligned(base))\n          ssize += (page_align((size_t)base) - (size_t)base);\n        fp = m->footprint + ssize; /* recheck limits */\n        if (ssize > nb && ssize < HALF_MAX_SIZE_T &&\n            (m->footprint_limit.pload() == 0 ||\n             (fp > m->footprint && fp <= m->footprint_limit)) &&\n            (br = (char*)(CALL_MORECORE(ssize))) == base) {\n          tbase = base;\n          tsize = ssize;\n        }\n      }\n    }\n    else {\n      /* Subtract out existing available top space from MORECORE request. */\n      ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);\n      /* Use mem here only if it did continuously extend old space */\n      if (ssize < HALF_MAX_SIZE_T &&\n          (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {\n        tbase = br;\n        tsize = ssize;\n      }\n    }\n\n    if (tbase == CMFAIL) {    /* Cope with partial failure */\n      if (br != CMFAIL) {    /* Try to use/extend the space we did get */\n        if (ssize < HALF_MAX_SIZE_T &&\n            ssize < nb + SYS_ALLOC_PADDING) {\n          size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);\n          if (esize < HALF_MAX_SIZE_T) {\n            char* end = (char*)CALL_MORECORE(esize);\n            if (end != CMFAIL)\n              ssize += esize;\n            else {            /* Can't use; try to release */\n              (void) CALL_MORECORE(-ssize);\n              br = CMFAIL;\n            }\n          }\n        }\n      }\n      if (br != CMFAIL) {    /* Use the space we did get */\n        tbase = br;\n        tsize = ssize;\n      }\n      else\n        disable_contiguous(m); /* Don't try contiguous path in the future */\n    }\n\n    RELEASE_MALLOC_GLOBAL_LOCK();\n  }\n\n  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */\n    char* mp = (char*)(CALL_MMAP(asize));\n    if (mp != CMFAIL) {\n      tbase = mp;\n      tsize = asize;\n      mmap_flag = USE_MMAP_BIT;\n    }\n  }\n\n  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */\n    if (asize < HALF_MAX_SIZE_T) {\n      char* br = CMFAIL;\n      char* end = CMFAIL;\n      ACQUIRE_MALLOC_GLOBAL_LOCK();\n      br = (char*)(CALL_MORECORE(asize));\n      end = (char*)(CALL_MORECORE(0));\n      RELEASE_MALLOC_GLOBAL_LOCK();\n      if (br != CMFAIL && end != CMFAIL && br < end) {\n        size_t ssize = end - br;\n        if (ssize > nb + TOP_FOOT_SIZE) {\n          tbase = br;\n          tsize = ssize;\n        }\n      }\n    }\n  }\n\n  if (tbase != CMFAIL) {\n\n    if ((m->footprint += tsize) > m->max_footprint)\n      m->max_footprint = m->footprint;\n\n    if (!is_initialized(m)) { /* first-time initialization */\n      if (m->least_addr == 0 || tbase < m->least_addr)\n        m->least_addr = tbase;\n      m->seg.base = tbase;\n      m->seg.size = tsize;\n      m->seg.sflags = mmap_flag;\n      m->magic = mparams.magic;\n      m->release_checks = MAX_RELEASE_CHECK_RATE;\n      init_bins(m);\n#if !ONLY_MSPACES\n      if (is_global(m))\n        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);\n      else\n#endif\n      {\n        /* Offset top by embedded malloc_state */\n        mchunkptr mn = next_chunk(mem2chunk(m));\n        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);\n      }\n    }\n\n    else {\n      /* Try to merge with an existing segment */\n      msegmentptr sp = &m->seg;\n      /* Only consider most recent segment if traversal suppressed */\n      while (sp != 0 && tbase != sp->base + sp->size)\n        sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;\n      if (sp != 0 &&\n          !is_extern_segment(sp) &&\n          (sp->sflags & USE_MMAP_BIT) == mmap_flag &&\n          segment_holds(sp, m->top.pload())) { /* append */\n        sp->size += tsize;\n        init_top(m, m->top, m->topsize + tsize);\n      }\n      else {\n        if (tbase < m->least_addr)\n          m->least_addr = tbase;\n        sp = &m->seg;\n        while (sp != 0 && sp->base != tbase + tsize)\n          sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;\n        if (sp != 0 &&\n            !is_extern_segment(sp) &&\n            (sp->sflags & USE_MMAP_BIT) == mmap_flag) {\n          char* oldbase = sp->base;\n          sp->base = tbase;\n          sp->size += tsize;\n          return prepend_alloc(m, tbase, oldbase, nb);\n        }\n        else\n          add_segment(m, tbase, tsize, mmap_flag);\n      }\n    }\n\n    if (nb < m->topsize) { /* Allocate from new or extended top space */\n      size_t rsize = m->topsize -= nb;\n      mchunkptr p = m->top;\n      mchunkptr r = m->top = chunk_plus_offset(p, nb);\n      r->head = rsize | PINUSE_BIT;\n      set_size_and_pinuse_of_inuse_chunk(m, p, nb);\n      check_top_chunk(m, m->top);\n      check_malloced_chunk(m, chunk2mem(p), nb);\n      return chunk2mem(p);\n    }\n  }\n\n  MALLOC_FAILURE_ACTION;\n  return 0;\n}\n\n/* -----------------------  system deallocation -------------------------- */\n\n/* Unmap and unlink any mmapped segments that don't contain used chunks */\nstatic size_t release_unused_segments(mstate m) {\n  size_t released = 0;\n  int nsegs = 0;\n  msegmentptr pred = &m->seg;\n  msegmentptr sp = pred->next;\n  while (sp != 0) {\n    char* base = sp->base;\n    size_t size = sp->size;\n    msegmentptr next = sp->next;\n    ++nsegs;\n    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {\n      mchunkptr p = align_as_chunk(base);\n      size_t psize = chunksize(p);\n      /* Can unmap if first chunk holds entire segment and not pinned */\n      if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {\n        tchunkptr tp = (tchunkptr)p;\n        assert(segment_holds(sp, (char*)sp));\n        if (p == m->dv) {\n          m->dv = 0;\n          m->dvsize = 0;\n        }\n        else {\n          unlink_large_chunk(m, tp);\n        }\n        if (CALL_MUNMAP(base, size) == 0) {\n          released += size;\n          m->footprint -= size;\n          /* unlink obsoleted record */\n          sp = pred;\n          sp->next = next;\n        }\n        else { /* back out if cannot unmap */\n          insert_large_chunk(m, tp, psize);\n        }\n      }\n    }\n    if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */\n      break;\n    pred = sp;\n    sp = next;\n  }\n  /* Reset check counter */\n  m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)?\n                       (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE);\n  return released;\n}\n\nstatic int sys_trim(mstate m, size_t pad) {\n  size_t released = 0;\n  ensure_initialization();\n  if (pad < MAX_REQUEST && is_initialized(m)) {\n    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */\n\n    if (m->topsize > pad) {\n      /* Shrink top space in granularity-size units, keeping at least one */\n      size_t unit = mparams.granularity;\n      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -\n                      SIZE_T_ONE) * unit;\n      msegmentptr sp = segment_holding(m, (char*)m->top.pload());\n\n      if (!is_extern_segment(sp)) {\n        if (is_mmapped_segment(sp)) {\n          if (HAVE_MMAP &&\n              sp->size >= extra &&\n              !has_segment_link(m, sp)) { /* can't shrink if pinned */\n            size_t newsize = sp->size - extra;\n            (void)newsize; /* placate people compiling -Wunused-variable */\n            /* Prefer mremap, fall back to munmap */\n            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||\n                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {\n              released = extra;\n            }\n          }\n        }\n        else if (HAVE_MORECORE) {\n          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */\n            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;\n          ACQUIRE_MALLOC_GLOBAL_LOCK();\n          {\n            /* Make sure end of memory is where we last set it. */\n            char* old_br = (char*)(CALL_MORECORE(0));\n            if (old_br == sp->base + sp->size) {\n              char* rel_br = (char*)(CALL_MORECORE(-extra));\n              char* new_br = (char*)(CALL_MORECORE(0));\n              if (rel_br != CMFAIL && new_br < old_br)\n                released = old_br - new_br;\n            }\n          }\n          RELEASE_MALLOC_GLOBAL_LOCK();\n        }\n      }\n\n      if (released != 0) {\n        sp->size -= released;\n        m->footprint -= released;\n        init_top(m, m->top, m->topsize - released);\n        check_top_chunk(m, m->top);\n      }\n    }\n\n    /* Unmap any unused mmapped segments */\n    if (HAVE_MMAP)\n      released += release_unused_segments(m);\n\n    /* On failure, disable autotrim to avoid repeated failed future calls */\n    if (released == 0 && m->topsize > m->trim_check)\n      m->trim_check = MAX_SIZE_T;\n  }\n\n  return (released != 0)? 1 : 0;\n}\n\n/* Consolidate and bin a chunk. Differs from exported versions\n   of free mainly in that the chunk need not be marked as inuse.\n*/\nstatic void dispose_chunk(mstate m, mchunkptr p, size_t psize) {\n  mchunkptr next = chunk_plus_offset(p, psize);\n  if (!pinuse(p)) {\n    mchunkptr prev;\n    size_t prevsize = p->prev_foot;\n    if (is_mmapped(p)) {\n      psize += prevsize + MMAP_FOOT_PAD;\n      if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)\n        m->footprint -= psize;\n      return;\n    }\n    prev = chunk_minus_offset(p, prevsize);\n    psize += prevsize;\n    p = prev;\n    if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */\n      if (p != m->dv) {\n        unlink_chunk(m, p, prevsize);\n      }\n      else if ((next->head & INUSE_BITS) == INUSE_BITS) {\n        m->dvsize = psize;\n        set_free_with_pinuse(p, psize, next);\n        return;\n      }\n    }\n    else {\n      CORRUPTION_ERROR_ACTION(m);\n      return;\n    }\n  }\n  if (RTCHECK(ok_address(m, next))) {\n    if (!cinuse(next)) {  /* consolidate forward */\n      if (next == m->top) {\n        size_t tsize = m->topsize += psize;\n        m->top = p;\n        p->head = tsize | PINUSE_BIT;\n        if (p == m->dv) {\n          m->dv = 0;\n          m->dvsize = 0;\n        }\n        return;\n      }\n      else if (next == m->dv) {\n        size_t dsize = m->dvsize += psize;\n        m->dv = p;\n        set_size_and_pinuse_of_free_chunk(p, dsize);\n        return;\n      }\n      else {\n        size_t nsize = chunksize(next);\n        psize += nsize;\n        unlink_chunk(m, next, nsize);\n        set_size_and_pinuse_of_free_chunk(p, psize);\n        if (p == m->dv) {\n          m->dvsize = psize;\n          return;\n        }\n      }\n    }\n    else {\n      set_free_with_pinuse(p, psize, next);\n    }\n    insert_chunk(m, p, psize);\n  }\n  else {\n    CORRUPTION_ERROR_ACTION(m);\n  }\n}\n\n/* ---------------------------- malloc --------------------------- */\n\n/* allocate a large request from the best fitting chunk in a treebin */\nstatic void* tmalloc_large(mstate m, size_t nb) {\n  tchunkptr v = 0;\n  size_t rsize = -nb; /* Unsigned negation */\n  tchunkptr t;\n  bindex_t idx;\n  compute_tree_index(nb, idx);\n  if ((t = *treebin_at(m, idx)) != 0) {\n    /* Traverse tree for this bin looking for node with size == nb */\n    size_t sizebits = nb << leftshift_for_tree_index(idx);\n    tchunkptr rst = 0;  /* The deepest untaken right subtree */\n    for (;;) {\n      tchunkptr rt;\n      size_t trem = chunksize(t) - nb;\n      if (trem < rsize) {\n        v = t;\n        if ((rsize = trem) == 0)\n          break;\n      }\n      rt = t->child[1];\n      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];\n      if (rt != 0 && rt != t)\n        rst = rt;\n      if (t == 0) {\n        t = rst; /* set t to least subtree holding sizes > nb */\n        break;\n      }\n      sizebits <<= 1;\n    }\n  }\n  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */\n    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;\n    if (leftbits != 0) {\n      bindex_t i;\n      binmap_t leastbit = least_bit(leftbits);\n      compute_bit2idx(leastbit, i);\n      t = *treebin_at(m, i);\n    }\n  }\n\n  while (t != 0) { /* find smallest of tree or subtree */\n    size_t trem = chunksize(t) - nb;\n    if (trem < rsize) {\n      rsize = trem;\n      v = t;\n    }\n    t = leftmost_child(t);\n  }\n\n  /*  If dv is a better fit, return 0 so malloc will use it */\n  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {\n    if (RTCHECK(ok_address(m, v))) { /* split */\n      mchunkptr r = chunk_plus_offset(v, nb);\n      assert(chunksize(v) == rsize + nb);\n      if (RTCHECK(ok_next(v, r))) {\n        unlink_large_chunk(m, v);\n        if (rsize < MIN_CHUNK_SIZE)\n          set_inuse_and_pinuse(m, v, (rsize + nb));\n        else {\n          set_size_and_pinuse_of_inuse_chunk(m, v, nb);\n          set_size_and_pinuse_of_free_chunk(r, rsize);\n          insert_chunk(m, r, rsize);\n        }\n        return chunk2mem(v);\n      }\n    }\n    CORRUPTION_ERROR_ACTION(m);\n  }\n  return 0;\n}\n\n/* allocate a small request from the best fitting chunk in a treebin */\nstatic void* tmalloc_small(mstate m, size_t nb) {\n  tchunkptr t, v;\n  size_t rsize;\n  bindex_t i;\n  binmap_t leastbit = least_bit(m->treemap);\n  compute_bit2idx(leastbit, i);\n  v = t = *treebin_at(m, i);\n  rsize = chunksize(t) - nb;\n\n  while ((t = leftmost_child(t)) != 0) {\n    size_t trem = chunksize(t) - nb;\n    if (trem < rsize) {\n      rsize = trem;\n      v = t;\n    }\n  }\n\n  if (RTCHECK(ok_address(m, v))) {\n    mchunkptr r = chunk_plus_offset(v, nb);\n    assert(chunksize(v) == rsize + nb);\n    if (RTCHECK(ok_next(v, r))) {\n      unlink_large_chunk(m, v);\n      if (rsize < MIN_CHUNK_SIZE)\n        set_inuse_and_pinuse(m, v, (rsize + nb));\n      else {\n        set_size_and_pinuse_of_inuse_chunk(m, v, nb);\n        set_size_and_pinuse_of_free_chunk(r, rsize);\n        replace_dv(m, r, rsize);\n      }\n      return chunk2mem(v);\n    }\n  }\n\n  CORRUPTION_ERROR_ACTION(m);\n  return 0;\n}\n\n#if !ONLY_MSPACES\n\nvoid* dlmalloc(size_t bytes) {\n  /*\n     Basic algorithm:\n     If a small request (< 256 bytes minus per-chunk overhead):\n       1. If one exists, use a remainderless chunk in associated smallbin.\n          (Remainderless means that there are too few excess bytes to\n          represent as a chunk.)\n       2. If it is big enough, use the dv chunk, which is normally the\n          chunk adjacent to the one used for the most recent small request.\n       3. If one exists, split the smallest available chunk in a bin,\n          saving remainder in dv.\n       4. If it is big enough, use the top chunk.\n       5. If available, get memory from system and use it\n     Otherwise, for a large request:\n       1. Find the smallest available binned chunk that fits, and use it\n          if it is better fitting than dv chunk, splitting if necessary.\n       2. If better fitting than any binned chunk, use the dv chunk.\n       3. If it is big enough, use the top chunk.\n       4. If request size >= mmap threshold, try to directly mmap this chunk.\n       5. If available, get memory from system and use it\n\n     The ugly goto's here ensure that postaction occurs along all paths.\n  */\n\n#if USE_LOCKS\n  ensure_initialization(); /* initialize in sys_alloc if not using locks */\n#endif\n\n  if (!PREACTION(gm)) {\n    void* mem;\n    size_t nb;\n    if (bytes <= MAX_SMALL_REQUEST) {\n      bindex_t idx;\n      binmap_t smallbits;\n      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);\n      idx = small_index(nb);\n      smallbits = gm->smallmap >> idx;\n\n      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */\n        mchunkptr b, p;\n        idx += ~smallbits & 1;       /* Uses next bin if idx empty */\n        b = smallbin_at(gm, idx);\n        p = b->fd;\n        assert(chunksize(p) == small_index2size(idx));\n        unlink_first_small_chunk(gm, b, p, idx);\n        set_inuse_and_pinuse(gm, p, small_index2size(idx));\n        mem = chunk2mem(p);\n        check_malloced_chunk(gm, mem, nb);\n        goto postaction;\n      }\n\n      else if (nb > gm->dvsize) {\n        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */\n          mchunkptr b, p, r;\n          size_t rsize;\n          bindex_t i;\n          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));\n          binmap_t leastbit = least_bit(leftbits);\n          compute_bit2idx(leastbit, i);\n          b = smallbin_at(gm, i);\n          p = b->fd;\n          assert(chunksize(p) == small_index2size(i));\n          unlink_first_small_chunk(gm, b, p, i);\n          rsize = small_index2size(i) - nb;\n          /* Fit here cannot be remainderless if 4byte sizes */\n          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)\n            set_inuse_and_pinuse(gm, p, small_index2size(i));\n          else {\n            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);\n            r = chunk_plus_offset(p, nb);\n            set_size_and_pinuse_of_free_chunk(r, rsize);\n            replace_dv(gm, r, rsize);\n          }\n          mem = chunk2mem(p);\n          check_malloced_chunk(gm, mem, nb);\n          goto postaction;\n        }\n\n        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {\n          check_malloced_chunk(gm, mem, nb);\n          goto postaction;\n        }\n      }\n    }\n    else if (bytes >= MAX_REQUEST)\n      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */\n    else {\n      nb = pad_request(bytes);\n      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {\n        check_malloced_chunk(gm, mem, nb);\n        goto postaction;\n      }\n    }\n\n    if (nb <= gm->dvsize) {\n      size_t rsize = gm->dvsize - nb;\n      mchunkptr p = gm->dv;\n      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */\n        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);\n        gm->dvsize = rsize;\n        set_size_and_pinuse_of_free_chunk(r, rsize);\n        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);\n      }\n      else { /* exhaust dv */\n        size_t dvs = gm->dvsize;\n        gm->dvsize = 0;\n        gm->dv = 0;\n        set_inuse_and_pinuse(gm, p, dvs);\n      }\n      mem = chunk2mem(p);\n      check_malloced_chunk(gm, mem, nb);\n      goto postaction;\n    }\n\n    else if (nb < gm->topsize) { /* Split top */\n      size_t rsize = gm->topsize -= nb;\n      mchunkptr p = gm->top;\n      mchunkptr r = gm->top = chunk_plus_offset(p, nb);\n      r->head = rsize | PINUSE_BIT;\n      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);\n      mem = chunk2mem(p);\n      check_top_chunk(gm, gm->top);\n      check_malloced_chunk(gm, mem, nb);\n      goto postaction;\n    }\n\n    mem = sys_alloc(gm, nb);\n\n  postaction:\n    POSTACTION(gm);\n    return mem;\n  }\n\n  return 0;\n}\n\n/* ---------------------------- free --------------------------- */\n\nvoid dlfree(void* mem) {\n  /*\n     Consolidate freed chunks with preceeding or succeeding bordering\n     free chunks, if they exist, and then place in a bin.  Intermixed\n     with special cases for top, dv, mmapped chunks, and usage errors.\n  */\n\n  if (mem != 0) {\n    mchunkptr p  = mem2chunk(mem);\n#if FOOTERS\n    mstate fm = get_mstate_for(p);\n    if (!ok_magic(fm)) {\n      USAGE_ERROR_ACTION(fm, p);\n      return;\n    }\n#else /* FOOTERS */\n#define fm gm\n#endif /* FOOTERS */\n    if (!PREACTION(fm)) {\n      check_inuse_chunk(fm, p);\n      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {\n        size_t psize = chunksize(p);\n        mchunkptr next = chunk_plus_offset(p, psize);\n        if (!pinuse(p)) {\n          size_t prevsize = p->prev_foot;\n          if (is_mmapped(p)) {\n            psize += prevsize + MMAP_FOOT_PAD;\n            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)\n              fm->footprint -= psize;\n            goto postaction;\n          }\n          else {\n            mchunkptr prev = chunk_minus_offset(p, prevsize);\n            psize += prevsize;\n            p = prev;\n            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */\n              if (p != fm->dv) {\n                unlink_chunk(fm, p, prevsize);\n              }\n              else if ((next->head & INUSE_BITS) == INUSE_BITS) {\n                fm->dvsize = psize;\n                set_free_with_pinuse(p, psize, next);\n                goto postaction;\n              }\n            }\n            else\n              goto erroraction;\n          }\n        }\n\n        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {\n          if (!cinuse(next)) {  /* consolidate forward */\n            if (next == fm->top) {\n              size_t tsize = fm->topsize += psize;\n              fm->top = p;\n              p->head = tsize | PINUSE_BIT;\n              if (p == fm->dv) {\n                fm->dv = 0;\n                fm->dvsize = 0;\n              }\n              if (should_trim(fm, tsize))\n                sys_trim(fm, 0);\n              goto postaction;\n            }\n            else if (next == fm->dv) {\n              size_t dsize = fm->dvsize += psize;\n              fm->dv = p;\n              set_size_and_pinuse_of_free_chunk(p, dsize);\n              goto postaction;\n            }\n            else {\n              size_t nsize = chunksize(next);\n              psize += nsize;\n              unlink_chunk(fm, next, nsize);\n              set_size_and_pinuse_of_free_chunk(p, psize);\n              if (p == fm->dv) {\n                fm->dvsize = psize;\n                goto postaction;\n              }\n            }\n          }\n          else\n            set_free_with_pinuse(p, psize, next);\n\n          if (is_small(psize)) {\n            insert_small_chunk(fm, p, psize);\n            check_free_chunk(fm, p);\n          }\n          else {\n            tchunkptr tp = (tchunkptr)p;\n            insert_large_chunk(fm, tp, psize);\n            check_free_chunk(fm, p);\n            if (--fm->release_checks == 0)\n              release_unused_segments(fm);\n          }\n          goto postaction;\n        }\n      }\n    erroraction:\n      USAGE_ERROR_ACTION(fm, p);\n    postaction:\n      POSTACTION(fm);\n    }\n  }\n#if !FOOTERS\n#undef fm\n#endif /* FOOTERS */\n}\n\nvoid* dlcalloc(size_t n_elements, size_t elem_size) {\n  void* mem;\n  size_t req = 0;\n  if (n_elements != 0) {\n    req = n_elements * elem_size;\n    if (((n_elements | elem_size) & ~(size_t)0xffff) &&\n        (req / n_elements != elem_size))\n      req = MAX_SIZE_T; /* force downstream failure on overflow */\n  }\n  mem = dlmalloc(req);\n  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))\n    memset(mem, 0, req);\n  return mem;\n}\n\n#endif /* !ONLY_MSPACES */\n\n/* ------------ Internal support for realloc, memalign, etc -------------- */\n\n/* Try to realloc; only in-place unless can_move true */\nstatic mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,\n                                   int can_move) {\n  mchunkptr newp = 0;\n  size_t oldsize = chunksize(p);\n  mchunkptr next = chunk_plus_offset(p, oldsize);\n  if (RTCHECK(ok_address(m, p) && ok_inuse(p) &&\n              ok_next(p, next) && ok_pinuse(next))) {\n    if (is_mmapped(p)) {\n      newp = mmap_resize(m, p, nb, can_move);\n    }\n    else if (oldsize >= nb) {             /* already big enough */\n      size_t rsize = oldsize - nb;\n      if (rsize >= MIN_CHUNK_SIZE) {      /* split off remainder */\n        mchunkptr r = chunk_plus_offset(p, nb);\n        set_inuse(m, p, nb);\n        set_inuse(m, r, rsize);\n        dispose_chunk(m, r, rsize);\n      }\n      newp = p;\n    }\n    else if (next == m->top) {  /* extend into top */\n      if (oldsize + m->topsize > nb) {\n        size_t newsize = oldsize + m->topsize;\n        size_t newtopsize = newsize - nb;\n        mchunkptr newtop = chunk_plus_offset(p, nb);\n        set_inuse(m, p, nb);\n        newtop->head = newtopsize |PINUSE_BIT;\n        m->top = newtop;\n        m->topsize = newtopsize;\n        newp = p;\n      }\n    }\n    else if (next == m->dv) { /* extend into dv */\n      size_t dvs = m->dvsize;\n      if (oldsize + dvs >= nb) {\n        size_t dsize = oldsize + dvs - nb;\n        if (dsize >= MIN_CHUNK_SIZE) {\n          mchunkptr r = chunk_plus_offset(p, nb);\n          mchunkptr n = chunk_plus_offset(r, dsize);\n          set_inuse(m, p, nb);\n          set_size_and_pinuse_of_free_chunk(r, dsize);\n          clear_pinuse(n);\n          m->dvsize = dsize;\n          m->dv = r;\n        }\n        else { /* exhaust dv */\n          size_t newsize = oldsize + dvs;\n          set_inuse(m, p, newsize);\n          m->dvsize = 0;\n          m->dv = 0;\n        }\n        newp = p;\n      }\n    }\n    else if (!cinuse(next)) { /* extend into next free chunk */\n      size_t nextsize = chunksize(next);\n      if (oldsize + nextsize >= nb) {\n        size_t rsize = oldsize + nextsize - nb;\n        unlink_chunk(m, next, nextsize);\n        if (rsize < MIN_CHUNK_SIZE) {\n          size_t newsize = oldsize + nextsize;\n          set_inuse(m, p, newsize);\n        }\n        else {\n          mchunkptr r = chunk_plus_offset(p, nb);\n          set_inuse(m, p, nb);\n          set_inuse(m, r, rsize);\n          dispose_chunk(m, r, rsize);\n        }\n        newp = p;\n      }\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(m, chunk2mem(p));\n  }\n  return newp;\n}\n\nstatic void* internal_memalign(mstate m, size_t alignment, size_t bytes) {\n  void* mem = 0;\n  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */\n    alignment = MIN_CHUNK_SIZE;\n  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */\n    size_t a = MALLOC_ALIGNMENT << 1;\n    while (a < alignment) a <<= 1;\n    alignment = a;\n  }\n  if (bytes >= MAX_REQUEST - alignment) {\n    if (m != 0)  { /* Test isn't needed but avoids compiler warning */\n      MALLOC_FAILURE_ACTION;\n    }\n  }\n  else {\n    size_t nb = request2size(bytes);\n    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;\n    mem = internal_malloc(m, req);\n    if (mem != 0) {\n      mchunkptr p = mem2chunk(mem);\n      if (PREACTION(m))\n        return 0;\n      if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */\n        /*\n          Find an aligned spot inside chunk.  Since we need to give\n          back leading space in a chunk of at least MIN_CHUNK_SIZE, if\n          the first calculation places us at a spot with less than\n          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.\n          We've allocated enough total room so that this is always\n          possible.\n        */\n        char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment -\n                                                       SIZE_T_ONE)) &\n                                             -alignment));\n        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?\n          br : br+alignment;\n        mchunkptr newp = (mchunkptr)pos;\n        size_t leadsize = pos - (char*)(p);\n        size_t newsize = chunksize(p) - leadsize;\n\n        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */\n          newp->prev_foot = p->prev_foot + leadsize;\n          newp->head = newsize;\n        }\n        else { /* Otherwise, give back leader, use the rest */\n          set_inuse(m, newp, newsize);\n          set_inuse(m, p, leadsize);\n          dispose_chunk(m, p, leadsize);\n        }\n        p = newp;\n      }\n\n      /* Give back spare room at the end */\n      if (!is_mmapped(p)) {\n        size_t size = chunksize(p);\n        if (size > nb + MIN_CHUNK_SIZE) {\n          size_t remainder_size = size - nb;\n          mchunkptr remainder = chunk_plus_offset(p, nb);\n          set_inuse(m, p, nb);\n          set_inuse(m, remainder, remainder_size);\n          dispose_chunk(m, remainder, remainder_size);\n        }\n      }\n\n      mem = chunk2mem(p);\n      assert (chunksize(p) >= nb);\n      assert(((size_t)mem & (alignment - 1)) == 0);\n      check_inuse_chunk(m, p);\n      POSTACTION(m);\n    }\n  }\n  return mem;\n}\n\n/*\n  Common support for independent_X routines, handling\n    all of the combinations that can result.\n  The opts arg has:\n    bit 0 set if all elements are same size (using sizes[0])\n    bit 1 set if elements should be zeroed\n*/\nstatic void** ialloc(mstate m,\n                     size_t n_elements,\n                     size_t* sizes,\n                     int opts,\n                     void* chunks[]) {\n\n  size_t    element_size;   /* chunksize of each element, if all same */\n  size_t    contents_size;  /* total size of elements */\n  size_t    array_size;     /* request size of pointer array */\n  void*     mem;            /* malloced aggregate space */\n  mchunkptr p;              /* corresponding chunk */\n  size_t    remainder_size; /* remaining bytes while splitting */\n  void**    marray;         /* either \"chunks\" or malloced ptr array */\n  mchunkptr array_chunk;    /* chunk for malloced ptr array */\n  flag_t    was_enabled;    /* to disable mmap */\n  size_t    size;\n  size_t    i;\n\n  ensure_initialization();\n  /* compute array length, if needed */\n  if (chunks != 0) {\n    if (n_elements == 0)\n      return chunks; /* nothing to do */\n    marray = chunks;\n    array_size = 0;\n  }\n  else {\n    /* if empty req, must still return chunk representing empty array */\n    if (n_elements == 0)\n      return (void**)internal_malloc(m, 0);\n    marray = 0;\n    array_size = request2size(n_elements * (sizeof(void*)));\n  }\n\n  /* compute total element size */\n  if (opts & 0x1) { /* all-same-size */\n    element_size = request2size(*sizes);\n    contents_size = n_elements * element_size;\n  }\n  else { /* add up all the sizes */\n    element_size = 0;\n    contents_size = 0;\n    for (i = 0; i != n_elements; ++i)\n      contents_size += request2size(sizes[i]);\n  }\n\n  size = contents_size + array_size;\n\n  /*\n     Allocate the aggregate chunk.  First disable direct-mmapping so\n     malloc won't use it, since we would not be able to later\n     free/realloc space internal to a segregated mmap region.\n  */\n  was_enabled = use_mmap(m);\n  disable_mmap(m);\n  mem = internal_malloc(m, size - CHUNK_OVERHEAD);\n  if (was_enabled)\n    enable_mmap(m);\n  if (mem == 0)\n    return 0;\n\n  if (PREACTION(m)) return 0;\n  p = mem2chunk(mem);\n  remainder_size = chunksize(p);\n\n  assert(!is_mmapped(p));\n\n  if (opts & 0x2) {       /* optionally clear the elements */\n    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);\n  }\n\n  /* If not provided, allocate the pointer array as final part of chunk */\n  if (marray == 0) {\n    size_t  array_chunk_size;\n    array_chunk = chunk_plus_offset(p, contents_size);\n    array_chunk_size = remainder_size - contents_size;\n    marray = (void**) (chunk2mem(array_chunk));\n    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);\n    remainder_size = contents_size;\n  }\n\n  /* split out elements */\n  for (i = 0; ; ++i) {\n    marray[i] = chunk2mem(p);\n    if (i != n_elements-1) {\n      if (element_size != 0)\n        size = element_size;\n      else\n        size = request2size(sizes[i]);\n      remainder_size -= size;\n      set_size_and_pinuse_of_inuse_chunk(m, p, size);\n      p = chunk_plus_offset(p, size);\n    }\n    else { /* the final element absorbs any overallocation slop */\n      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);\n      break;\n    }\n  }\n\n#if DEBUG\n  if (marray != chunks) {\n    /* final element must have exactly exhausted chunk */\n    if (element_size != 0) {\n      assert(remainder_size == element_size);\n    }\n    else {\n      assert(remainder_size == request2size(sizes[i]));\n    }\n    check_inuse_chunk(m, mem2chunk(marray));\n  }\n  for (i = 0; i != n_elements; ++i)\n    check_inuse_chunk(m, mem2chunk(marray[i]));\n\n#endif /* DEBUG */\n\n  POSTACTION(m);\n  return marray;\n}\n\n/* Try to free all pointers in the given array.\n   Note: this could be made faster, by delaying consolidation,\n   at the price of disabling some user integrity checks, We\n   still optimize some consolidations by combining adjacent\n   chunks before freeing, which will occur often if allocated\n   with ialloc or the array is sorted.\n*/\nstatic size_t internal_bulk_free(mstate m, void* array[], size_t nelem) {\n  size_t unfreed = 0;\n  if (!PREACTION(m)) {\n    persist<void*>* a;\n    persist<void*>* fence = (persist<void*>*)&(array[nelem]);\n    for (a = (persist<void*>*)array; a != fence; ++a) {\n      void* mem = *a;\n      if (mem != 0) {\n        mchunkptr p = mem2chunk(mem);\n        size_t psize = chunksize(p);\n#if FOOTERS\n        if (get_mstate_for(p) != m) {\n          ++unfreed;\n          continue;\n        }\n#endif\n        check_inuse_chunk(m, p);\n        *a = 0;\n        if (RTCHECK(ok_address(m, p) && ok_inuse(p))) {\n          persist<void *>* b = a + 1; /* try to merge with next chunk */\n          mchunkptr next = next_chunk(p);\n          if (b != fence && *b == chunk2mem(next)) {\n            size_t newsize = chunksize(next) + psize;\n            set_inuse(m, p, newsize);\n            *b = chunk2mem(p);\n          }\n          else\n            dispose_chunk(m, p, psize);\n        }\n        else {\n          CORRUPTION_ERROR_ACTION(m);\n          break;\n        }\n      }\n    }\n    if (should_trim(m, m->topsize))\n      sys_trim(m, 0);\n    POSTACTION(m);\n  }\n  return unfreed;\n}\n\n/* Traversal */\n#if MALLOC_INSPECT_ALL\nstatic void internal_inspect_all(mstate m,\n                                 void(*handler)(void *start,\n                                                void *end,\n                                                size_t used_bytes,\n                                                void* callback_arg),\n                                 void* arg) {\n  if (is_initialized(m)) {\n    mchunkptr top = m->top;\n    msegmentptr s;\n    for (s = &m->seg; s != 0; s = s->next) {\n      mchunkptr q = align_as_chunk(s->base);\n      while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) {\n        mchunkptr next = next_chunk(q);\n        size_t sz = chunksize(q);\n        size_t used;\n        void* start;\n        if (is_inuse(q)) {\n          used = sz - CHUNK_OVERHEAD; /* must not be mmapped */\n          start = chunk2mem(q);\n        }\n        else {\n          used = 0;\n          if (is_small(sz)) {     /* offset by possible bookkeeping */\n            start = (void*)((char*)q + sizeof(struct malloc_chunk));\n          }\n          else {\n            start = (void*)((char*)q + sizeof(struct malloc_tree_chunk));\n          }\n        }\n        if (start < (void*)next)  /* skip if all space is bookkeeping */\n          handler(start, next, used, arg);\n        if (q == top)\n          break;\n        q = next;\n      }\n    }\n  }\n}\n#endif /* MALLOC_INSPECT_ALL */\n\n/* ------------------ Exported realloc, memalign, etc -------------------- */\n\n#if !ONLY_MSPACES\n\nvoid* dlrealloc(void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem == 0) {\n    mem = dlmalloc(bytes);\n  }\n  else if (bytes >= MAX_REQUEST) {\n    MALLOC_FAILURE_ACTION;\n  }\n#ifdef REALLOC_ZERO_BYTES_FREES\n  else if (bytes == 0) {\n    dlfree(oldmem);\n  }\n#endif /* REALLOC_ZERO_BYTES_FREES */\n  else {\n    size_t nb = request2size(bytes);\n    mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n    mstate m = gm;\n#else /* FOOTERS */\n    mstate m = get_mstate_for(oldp);\n    if (!ok_magic(m)) {\n      USAGE_ERROR_ACTION(m, oldmem);\n      return 0;\n    }\n#endif /* FOOTERS */\n    if (!PREACTION(m)) {\n      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);\n      POSTACTION(m);\n      if (newp != 0) {\n        check_inuse_chunk(m, newp);\n        mem = chunk2mem(newp);\n      }\n      else {\n        mem = internal_malloc(m, bytes);\n        if (mem != 0) {\n          size_t oc = chunksize(oldp) - overhead_for(oldp);\n          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);\n          internal_free(m, oldmem);\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* dlrealloc_in_place(void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem != 0) {\n    if (bytes >= MAX_REQUEST) {\n      MALLOC_FAILURE_ACTION;\n    }\n    else {\n      size_t nb = request2size(bytes);\n      mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n      mstate m = gm;\n#else /* FOOTERS */\n      mstate m = get_mstate_for(oldp);\n      if (!ok_magic(m)) {\n        USAGE_ERROR_ACTION(m, oldmem);\n        return 0;\n      }\n#endif /* FOOTERS */\n      if (!PREACTION(m)) {\n        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);\n        POSTACTION(m);\n        if (newp == oldp) {\n          check_inuse_chunk(m, newp);\n          mem = oldmem;\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* dlmemalign(size_t alignment, size_t bytes) {\n  if (alignment <= MALLOC_ALIGNMENT) {\n    return dlmalloc(bytes);\n  }\n  return internal_memalign(gm, alignment, bytes);\n}\n\nint dlposix_memalign(void** pp, size_t alignment, size_t bytes) {\n  void* mem = 0;\n  if (alignment == MALLOC_ALIGNMENT)\n    mem = dlmalloc(bytes);\n  else {\n    size_t d = alignment / sizeof(void*);\n    size_t r = alignment % sizeof(void*);\n    if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0)\n      return EINVAL;\n    else if (bytes <= MAX_REQUEST - alignment) {\n      if (alignment <  MIN_CHUNK_SIZE)\n        alignment = MIN_CHUNK_SIZE;\n      mem = internal_memalign(gm, alignment, bytes);\n    }\n  }\n  if (mem == 0)\n    return ENOMEM;\n  else {\n    *pp = mem;\n    return 0;\n  }\n}\n\nvoid* dlvalloc(size_t bytes) {\n  size_t pagesz;\n  ensure_initialization();\n  pagesz = mparams.page_size;\n  return dlmemalign(pagesz, bytes);\n}\n\nvoid* dlpvalloc(size_t bytes) {\n  size_t pagesz;\n  ensure_initialization();\n  pagesz = mparams.page_size;\n  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));\n}\n\nvoid** dlindependent_calloc(size_t n_elements, size_t elem_size,\n                            void* chunks[]) {\n  size_t sz = elem_size; /* serves as 1-element array */\n  return ialloc(gm, n_elements, &sz, 3, chunks);\n}\n\nvoid** dlindependent_comalloc(size_t n_elements, size_t sizes[],\n                              void* chunks[]) {\n  return ialloc(gm, n_elements, sizes, 0, chunks);\n}\n\nsize_t dlbulk_free(void* array[], size_t nelem) {\n  return internal_bulk_free(gm, array, nelem);\n}\n\n#if MALLOC_INSPECT_ALL\nvoid dlmalloc_inspect_all(void(*handler)(void *start,\n                                         void *end,\n                                         size_t used_bytes,\n                                         void* callback_arg),\n                          void* arg) {\n  ensure_initialization();\n  if (!PREACTION(gm)) {\n    internal_inspect_all(gm, handler, arg);\n    POSTACTION(gm);\n  }\n}\n#endif /* MALLOC_INSPECT_ALL */\n\nint dlmalloc_trim(size_t pad) {\n  int result = 0;\n  ensure_initialization();\n  if (!PREACTION(gm)) {\n    result = sys_trim(gm, pad);\n    POSTACTION(gm);\n  }\n  return result;\n}\n\nsize_t dlmalloc_footprint(void) {\n  return gm->footprint;\n}\n\nsize_t dlmalloc_max_footprint(void) {\n  return gm->max_footprint;\n}\n\nsize_t dlmalloc_footprint_limit(void) {\n  size_t maf = gm->footprint_limit;\n  return maf == 0 ? MAX_SIZE_T : maf;\n}\n\nsize_t dlmalloc_set_footprint_limit(size_t bytes) {\n  size_t result;  /* invert sense of 0 */\n  if (bytes == 0)\n    result = granularity_align(1); /* Use minimal size */\n  if (bytes == MAX_SIZE_T)\n    result = 0;                    /* disable */\n  else\n    result = granularity_align(bytes);\n  return gm->footprint_limit = result;\n}\n\n#if !NO_MALLINFO\nstruct mallinfo dlmallinfo(void) {\n  return internal_mallinfo(gm);\n}\n#endif /* NO_MALLINFO */\n\n#if !NO_MALLOC_STATS\nvoid dlmalloc_stats() {\n  internal_malloc_stats(gm);\n}\n#endif /* NO_MALLOC_STATS */\n\nint dlmallopt(int param_number, int value) {\n  return change_mparam(param_number, value);\n}\n\nsize_t dlmalloc_usable_size(void* mem) {\n  if (mem != 0) {\n    mchunkptr p = mem2chunk(mem);\n    if (is_inuse(p))\n      return chunksize(p) - overhead_for(p);\n  }\n  return 0;\n}\n\n#endif /* !ONLY_MSPACES */\n\n/* ----------------------------- user mspaces ---------------------------- */\n\n#if MSPACES\n\nstatic mstate init_user_mstate(char* tbase, size_t tsize) {\n  size_t msize = pad_request(sizeof(struct malloc_state));\n  mchunkptr mn;\n  mchunkptr msp = align_as_chunk(tbase);\n  mstate m = (mstate)(chunk2mem(msp));\n  memset(m, 0, msize);\n  (void)INITIAL_LOCK(&m->mutex);\n  msp->head = (msize|INUSE_BITS);\n  m->seg.base = m->least_addr = tbase;\n  m->seg.size = m->footprint = m->max_footprint = tsize;\n  m->magic = mparams.magic;\n  m->release_checks = MAX_RELEASE_CHECK_RATE;\n  m->mflags = mparams.default_mflags;\n  m->extp = 0;\n  m->exts = 0;\n  disable_contiguous(m);\n  init_bins(m);\n  mn = next_chunk(mem2chunk(m));\n  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);\n  check_top_chunk(m, m->top);\n  return m;\n}\n\nmspace create_mspace(size_t capacity, int locked) {\n  mstate m = 0;\n  size_t msize;\n  ensure_initialization();\n  msize = pad_request(sizeof(struct malloc_state));\n  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {\n    size_t rs = ((capacity == 0)? mparams.granularity :\n                 (capacity + TOP_FOOT_SIZE + msize));\n    size_t tsize = granularity_align(rs);\n    char* tbase = (char*)(CALL_MMAP(tsize));\n    if (tbase != CMFAIL) {\n      m = init_user_mstate(tbase, tsize);\n      m->seg.sflags = USE_MMAP_BIT;\n      set_lock(m, locked);\n    }\n  }\n  return (mspace)m;\n}\n\nmspace create_mspace_with_base(void* base, size_t capacity, int locked) {\n  mstate m = 0;\n  size_t msize;\n  ensure_initialization();\n  msize = pad_request(sizeof(struct malloc_state));\n  if (capacity > msize + TOP_FOOT_SIZE &&\n      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {\n    m = init_user_mstate((char*)base, capacity);\n    m->seg.sflags = EXTERN_BIT;\n    set_lock(m, locked);\n  }\n  return (mspace)m;\n}\n\nint mspace_track_large_chunks(mspace msp, int enable) {\n  int ret = 0;\n  mstate ms = (mstate)msp;\n  if (!PREACTION(ms)) {\n    if (!use_mmap(ms)) {\n      ret = 1;\n    }\n    if (!enable) {\n      enable_mmap(ms);\n    } else {\n      disable_mmap(ms);\n    }\n    POSTACTION(ms);\n  }\n  return ret;\n}\n\nsize_t destroy_mspace(mspace msp) {\n  size_t freed = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    msegmentptr sp = &ms->seg;\n    (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */\n    while (sp != 0) {\n      char* base = sp->base;\n      size_t size = sp->size;\n      flag_t flag = sp->sflags;\n      (void)base; /* placate people compiling -Wunused-variable */\n      sp = sp->next;\n      if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&\n          CALL_MUNMAP(base, size) == 0)\n        freed += size;\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return freed;\n}\n\n/*\n  mspace versions of routines are near-clones of the global\n  versions. This is not so nice but better than the alternatives.\n*/\n\nvoid* mspace_malloc(mspace msp, size_t bytes) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  if (!PREACTION(ms)) {\n    void* mem;\n    size_t nb;\n    if (bytes <= MAX_SMALL_REQUEST) {\n      bindex_t idx;\n      binmap_t smallbits;\n      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);\n      idx = small_index(nb);\n      smallbits = ms->smallmap >> idx;\n\n      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */\n        mchunkptr b, p;\n        idx += ~smallbits & 1;       /* Uses next bin if idx empty */\n        b = smallbin_at(ms, idx);\n        p = b->fd;\n        assert(chunksize(p) == small_index2size(idx));\n        unlink_first_small_chunk(ms, b, p, idx);\n        set_inuse_and_pinuse(ms, p, small_index2size(idx));\n        mem = chunk2mem(p);\n        check_malloced_chunk(ms, mem, nb);\n        goto postaction;\n      }\n\n      else if (nb > ms->dvsize) {\n        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */\n          mchunkptr b, p, r;\n          size_t rsize;\n          bindex_t i;\n          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));\n          binmap_t leastbit = least_bit(leftbits);\n          compute_bit2idx(leastbit, i);\n          b = smallbin_at(ms, i);\n          p = b->fd;\n          assert(chunksize(p) == small_index2size(i));\n          unlink_first_small_chunk(ms, b, p, i);\n          rsize = small_index2size(i) - nb;\n          /* Fit here cannot be remainderless if 4byte sizes */\n          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)\n            set_inuse_and_pinuse(ms, p, small_index2size(i));\n          else {\n            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);\n            r = chunk_plus_offset(p, nb);\n            set_size_and_pinuse_of_free_chunk(r, rsize);\n            replace_dv(ms, r, rsize);\n          }\n          mem = chunk2mem(p);\n          check_malloced_chunk(ms, mem, nb);\n          goto postaction;\n        }\n\n        else if (ms->treemap.pload() != 0 && (mem = tmalloc_small(ms, nb)) != 0) {\n          check_malloced_chunk(ms, mem, nb);\n          goto postaction;\n        }\n      }\n    }\n    else if (bytes >= MAX_REQUEST)\n      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */\n    else {\n      nb = pad_request(bytes);\n      if (ms->treemap.pload() != 0 && (mem = tmalloc_large(ms, nb)) != 0) {\n        check_malloced_chunk(ms, mem, nb);\n        goto postaction;\n      }\n    }\n\n    if (nb <= ms->dvsize) {\n      size_t rsize = ms->dvsize - nb;\n      mchunkptr p = ms->dv;\n      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */\n        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);\n        ms->dvsize = rsize;\n        set_size_and_pinuse_of_free_chunk(r, rsize);\n        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);\n      }\n      else { /* exhaust dv */\n        size_t dvs = ms->dvsize;\n        ms->dvsize = 0;\n        ms->dv = 0;\n        set_inuse_and_pinuse(ms, p, dvs);\n      }\n      mem = chunk2mem(p);\n      check_malloced_chunk(ms, mem, nb);\n      goto postaction;\n    }\n\n    else if (nb < ms->topsize) { /* Split top */\n      size_t rsize = ms->topsize -= nb;\n      mchunkptr p = ms->top;\n      mchunkptr r = ms->top = chunk_plus_offset(p, nb);\n      r->head = rsize | PINUSE_BIT;\n      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);\n      mem = chunk2mem(p);\n      check_top_chunk(ms, ms->top);\n      check_malloced_chunk(ms, mem, nb);\n      goto postaction;\n    }\n    mem = 0;\n    //mem = sys_alloc(ms, nb);\n\n  postaction:\n    POSTACTION(ms);\n    return mem;\n  }\n\n  return 0;\n}\n\nvoid mspace_free(mspace msp, void* mem) {\n  if (mem != 0) {\n    mchunkptr p  = mem2chunk(mem);\n#if FOOTERS\n    mstate fm = get_mstate_for(p);\n    (void)msp; /* placate people compiling -Wunused */\n#else /* FOOTERS */\n    mstate fm = (mstate)msp;\n#endif /* FOOTERS */\n    if (!ok_magic(fm)) {\n      USAGE_ERROR_ACTION(fm, p);\n      return;\n    }\n    if (!PREACTION(fm)) {\n      check_inuse_chunk(fm, p);\n      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {\n        size_t psize = chunksize(p);\n        mchunkptr next = chunk_plus_offset(p, psize);\n        if (!pinuse(p)) {\n          size_t prevsize = p->prev_foot;\n          if (is_mmapped(p)) {\n            psize += prevsize + MMAP_FOOT_PAD;\n            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)\n              fm->footprint -= psize;\n            goto postaction;\n          }\n          else {\n            mchunkptr prev = chunk_minus_offset(p, prevsize);\n            psize += prevsize;\n            p = prev;\n            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */\n              if (p != fm->dv) {\n                unlink_chunk(fm, p, prevsize);\n              }\n              else if ((next->head & INUSE_BITS) == INUSE_BITS) {\n                fm->dvsize = psize;\n                set_free_with_pinuse(p, psize, next);\n                goto postaction;\n              }\n            }\n            else\n              goto erroraction;\n          }\n        }\n\n        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {\n          if (!cinuse(next)) {  /* consolidate forward */\n            if (next == fm->top) {\n              size_t tsize = fm->topsize += psize;\n              fm->top = p;\n              p->head = tsize | PINUSE_BIT;\n              if (p == fm->dv) {\n                fm->dv = 0;\n                fm->dvsize = 0;\n              }\n              if (should_trim(fm, tsize))\n                sys_trim(fm, 0);\n              goto postaction;\n            }\n            else if (next == fm->dv) {\n              size_t dsize = fm->dvsize += psize;\n              fm->dv = p;\n              set_size_and_pinuse_of_free_chunk(p, dsize);\n              goto postaction;\n            }\n            else {\n              size_t nsize = chunksize(next);\n              psize += nsize;\n              unlink_chunk(fm, next, nsize);\n              set_size_and_pinuse_of_free_chunk(p, psize);\n              if (p == fm->dv) {\n                fm->dvsize = psize;\n                goto postaction;\n              }\n            }\n          }\n          else\n            set_free_with_pinuse(p, psize, next);\n\n          if (is_small(psize)) {\n            insert_small_chunk(fm, p, psize);\n            check_free_chunk(fm, p);\n          }\n          else {\n            tchunkptr tp = (tchunkptr)p;\n            insert_large_chunk(fm, tp, psize);\n            check_free_chunk(fm, p);\n            fm->release_checks.pstore(fm->release_checks.pload()-1);\n            if (fm->release_checks.pload()== 0)\n              release_unused_segments(fm);\n          }\n          goto postaction;\n        }\n      }\n    erroraction:\n      USAGE_ERROR_ACTION(fm, p);\n    postaction:\n      POSTACTION(fm);\n    }\n  }\n}\n\nvoid* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {\n  void* mem;\n  size_t req = 0;\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  if (n_elements != 0) {\n    req = n_elements * elem_size;\n    if (((n_elements | elem_size) & ~(size_t)0xffff) &&\n        (req / n_elements != elem_size))\n      req = MAX_SIZE_T; /* force downstream failure on overflow */\n  }\n  mem = internal_malloc(ms, req);\n  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))\n    memset(mem, 0, req);\n  return mem;\n}\n\nvoid* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem == 0) {\n    mem = mspace_malloc(msp, bytes);\n  }\n  else if (bytes >= MAX_REQUEST) {\n    MALLOC_FAILURE_ACTION;\n  }\n#ifdef REALLOC_ZERO_BYTES_FREES\n  else if (bytes == 0) {\n    mspace_free(msp, oldmem);\n  }\n#endif /* REALLOC_ZERO_BYTES_FREES */\n  else {\n    size_t nb = request2size(bytes);\n    mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n    mstate m = (mstate)msp;\n#else /* FOOTERS */\n    mstate m = get_mstate_for(oldp);\n    if (!ok_magic(m)) {\n      USAGE_ERROR_ACTION(m, oldmem);\n      return 0;\n    }\n#endif /* FOOTERS */\n    if (!PREACTION(m)) {\n      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);\n      POSTACTION(m);\n      if (newp != 0) {\n        check_inuse_chunk(m, newp);\n        mem = chunk2mem(newp);\n      }\n      else {\n        mem = mspace_malloc(m, bytes);\n        if (mem != 0) {\n          size_t oc = chunksize(oldp) - overhead_for(oldp);\n          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);\n          mspace_free(m, oldmem);\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) {\n  void* mem = 0;\n  if (oldmem != 0) {\n    if (bytes >= MAX_REQUEST) {\n      MALLOC_FAILURE_ACTION;\n    }\n    else {\n      size_t nb = request2size(bytes);\n      mchunkptr oldp = mem2chunk(oldmem);\n#if ! FOOTERS\n      mstate m = (mstate)msp;\n#else /* FOOTERS */\n      mstate m = get_mstate_for(oldp);\n      (void)msp; /* placate people compiling -Wunused */\n      if (!ok_magic(m)) {\n        USAGE_ERROR_ACTION(m, oldmem);\n        return 0;\n      }\n#endif /* FOOTERS */\n      if (!PREACTION(m)) {\n        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);\n        POSTACTION(m);\n        if (newp == oldp) {\n          check_inuse_chunk(m, newp);\n          mem = oldmem;\n        }\n      }\n    }\n  }\n  return mem;\n}\n\nvoid* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  if (alignment <= MALLOC_ALIGNMENT)\n    return mspace_malloc(msp, bytes);\n  return internal_memalign(ms, alignment, bytes);\n}\n\nvoid** mspace_independent_calloc(mspace msp, size_t n_elements,\n                                 size_t elem_size, void* chunks[]) {\n  size_t sz = elem_size; /* serves as 1-element array */\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  return ialloc(ms, n_elements, &sz, 3, chunks);\n}\n\nvoid** mspace_independent_comalloc(mspace msp, size_t n_elements,\n                                   size_t sizes[], void* chunks[]) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n    return 0;\n  }\n  return ialloc(ms, n_elements, sizes, 0, chunks);\n}\n\nsize_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) {\n  return internal_bulk_free((mstate)msp, array, nelem);\n}\n\n#if MALLOC_INSPECT_ALL\nvoid mspace_inspect_all(mspace msp,\n                        void(*handler)(void *start,\n                                       void *end,\n                                       size_t used_bytes,\n                                       void* callback_arg),\n                        void* arg) {\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    if (!PREACTION(ms)) {\n      internal_inspect_all(ms, handler, arg);\n      POSTACTION(ms);\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n}\n#endif /* MALLOC_INSPECT_ALL */\n\nint mspace_trim(mspace msp, size_t pad) {\n  int result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    if (!PREACTION(ms)) {\n      result = sys_trim(ms, pad);\n      POSTACTION(ms);\n    }\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\n#if !NO_MALLOC_STATS\nvoid mspace_malloc_stats(mspace msp) {\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    internal_malloc_stats(ms);\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n}\n#endif /* NO_MALLOC_STATS */\n\nsize_t mspace_footprint(mspace msp) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    result = ms->footprint;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\nsize_t mspace_max_footprint(mspace msp) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    result = ms->max_footprint;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\nsize_t mspace_footprint_limit(mspace msp) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    size_t maf = ms->footprint_limit;\n    result = (maf == 0) ? MAX_SIZE_T : maf;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\nsize_t mspace_set_footprint_limit(mspace msp, size_t bytes) {\n  size_t result = 0;\n  mstate ms = (mstate)msp;\n  if (ok_magic(ms)) {\n    if (bytes == 0)\n      result = granularity_align(1); /* Use minimal size */\n    if (bytes == MAX_SIZE_T)\n      result = 0;                    /* disable */\n    else\n      result = granularity_align(bytes);\n    ms->footprint_limit = result;\n  }\n  else {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return result;\n}\n\n#if !NO_MALLINFO\nstruct mallinfo mspace_mallinfo(mspace msp) {\n  mstate ms = (mstate)msp;\n  if (!ok_magic(ms)) {\n    USAGE_ERROR_ACTION(ms,ms);\n  }\n  return internal_mallinfo(ms);\n}\n#endif /* NO_MALLINFO */\n\nsize_t mspace_usable_size(const void* mem) {\n  if (mem != 0) {\n    mchunkptr p = mem2chunk(mem);\n    if (is_inuse(p))\n      return chunksize(p) - overhead_for(p);\n  }\n  return 0;\n}\n\nint mspace_mallopt(int param_number, int value) {\n  return change_mparam(param_number, value);\n}\n\n#endif /* MSPACES */\n\n\n/* -------------------- Alternative MORECORE functions ------------------- */\n\n/*\n  Guidelines for creating a custom version of MORECORE:\n\n  * For best performance, MORECORE should allocate in multiples of pagesize.\n  * MORECORE may allocate more memory than requested. (Or even less,\n      but this will usually result in a malloc failure.)\n  * MORECORE must not allocate memory when given argument zero, but\n      instead return one past the end address of memory from previous\n      nonzero call.\n  * For best performance, consecutive calls to MORECORE with positive\n      arguments should return increasing addresses, indicating that\n      space has been contiguously extended.\n  * Even though consecutive calls to MORECORE need not return contiguous\n      addresses, it must be OK for malloc'ed chunks to span multiple\n      regions in those cases where they do happen to be contiguous.\n  * MORECORE need not handle negative arguments -- it may instead\n      just return MFAIL when given negative arguments.\n      Negative arguments are always multiples of pagesize. MORECORE\n      must not misinterpret negative args as large positive unsigned\n      args. You can suppress all such calls from even occurring by defining\n      MORECORE_CANNOT_TRIM,\n\n  As an example alternative MORECORE, here is a custom allocator\n  kindly contributed for pre-OSX macOS.  It uses virtually but not\n  necessarily physically contiguous non-paged memory (locked in,\n  present and won't get swapped out).  You can use it by uncommenting\n  this section, adding some #includes, and setting up the appropriate\n  defines above:\n\n      #define MORECORE osMoreCore\n\n  There is also a shutdown routine that should somehow be called for\n  cleanup upon program exit.\n\n  #define MAX_POOL_ENTRIES 100\n  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)\n  static int next_os_pool;\n  void *our_os_pools[MAX_POOL_ENTRIES];\n\n  void *osMoreCore(int size)\n  {\n    void *ptr = 0;\n    static void *sbrk_top = 0;\n\n    if (size > 0)\n    {\n      if (size < MINIMUM_MORECORE_SIZE)\n         size = MINIMUM_MORECORE_SIZE;\n      if (CurrentExecutionLevel() == kTaskLevel)\n         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);\n      if (ptr == 0)\n      {\n        return (void *) MFAIL;\n      }\n      // save ptrs so they can be freed during cleanup\n      our_os_pools[next_os_pool] = ptr;\n      next_os_pool++;\n      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);\n      sbrk_top = (char *) ptr + size;\n      return ptr;\n    }\n    else if (size < 0)\n    {\n      // we don't currently support shrink behavior\n      return (void *) MFAIL;\n    }\n    else\n    {\n      return sbrk_top;\n    }\n  }\n\n  // cleanup any allocated memory pools\n  // called as last thing before shutting down driver\n\n  void osCleanupMem(void)\n  {\n    void **ptr;\n\n    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)\n      if (*ptr)\n      {\n         PoolDeallocate(*ptr);\n         *ptr = 0;\n      }\n  }\n\n*/\n\n\n/* -----------------------------------------------------------------------\nHistory:\n    v2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea\n      * fix bad comparison in dlposix_memalign\n      * don't reuse adjusted asize in sys_alloc\n      * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion\n      * reduce compiler warnings -- thanks to all who reported/suggested these\n\n    v2.8.5 Sun May 22 10:26:02 2011  Doug Lea  (dl at gee)\n      * Always perform unlink checks unless INSECURE\n      * Add posix_memalign.\n      * Improve realloc to expand in more cases; expose realloc_in_place.\n        Thanks to Peter Buhr for the suggestion.\n      * Add footprint_limit, inspect_all, bulk_free. Thanks\n        to Barry Hayes and others for the suggestions.\n      * Internal refactorings to avoid calls while holding locks\n      * Use non-reentrant locks by default. Thanks to Roland McGrath\n        for the suggestion.\n      * Small fixes to mspace_destroy, reset_on_error.\n      * Various configuration extensions/changes. Thanks\n         to all who contributed these.\n\n    V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu)\n      * Update Creative Commons URL\n\n    V2.8.4 Wed May 27 09:56:23 2009  Doug Lea  (dl at gee)\n      * Use zeros instead of prev foot for is_mmapped\n      * Add mspace_track_large_chunks; thanks to Jean Brouwers\n      * Fix set_inuse in internal_realloc; thanks to Jean Brouwers\n      * Fix insufficient sys_alloc padding when using 16byte alignment\n      * Fix bad error check in mspace_footprint\n      * Adaptations for ptmalloc; thanks to Wolfram Gloger.\n      * Reentrant spin locks; thanks to Earl Chew and others\n      * Win32 improvements; thanks to Niall Douglas and Earl Chew\n      * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options\n      * Extension hook in malloc_state\n      * Various small adjustments to reduce warnings on some compilers\n      * Various configuration extensions/changes for more platforms. Thanks\n         to all who contributed these.\n\n    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)\n      * Add max_footprint functions\n      * Ensure all appropriate literals are size_t\n      * Fix conditional compilation problem for some #define settings\n      * Avoid concatenating segments with the one provided\n        in create_mspace_with_base\n      * Rename some variables to avoid compiler shadowing warnings\n      * Use explicit lock initialization.\n      * Better handling of sbrk interference.\n      * Simplify and fix segment insertion, trimming and mspace_destroy\n      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x\n      * Thanks especially to Dennis Flanagan for help on these.\n\n    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)\n      * Fix memalign brace error.\n\n    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)\n      * Fix improper #endif nesting in C++\n      * Add explicit casts needed for C++\n\n    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)\n      * Use trees for large bins\n      * Support mspaces\n      * Use segments to unify sbrk-based and mmap-based system allocation,\n        removing need for emulation on most platforms without sbrk.\n      * Default safety checks\n      * Optional footer checks. Thanks to William Robertson for the idea.\n      * Internal code refactoring\n      * Incorporate suggestions and platform-specific changes.\n        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,\n        Aaron Bachmann,  Emery Berger, and others.\n      * Speed up non-fastbin processing enough to remove fastbins.\n      * Remove useless cfree() to avoid conflicts with other apps.\n      * Remove internal memcpy, memset. Compilers handle builtins better.\n      * Remove some options that no one ever used and rename others.\n\n    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)\n      * Fix malloc_state bitmap array misdeclaration\n\n    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)\n      * Allow tuning of FIRST_SORTED_BIN_SIZE\n      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.\n      * Better detection and support for non-contiguousness of MORECORE.\n        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger\n      * Bypass most of malloc if no frees. Thanks To Emery Berger.\n      * Fix freeing of old top non-contiguous chunk im sysmalloc.\n      * Raised default trim and map thresholds to 256K.\n      * Fix mmap-related #defines. Thanks to Lubos Lunak.\n      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.\n      * Branch-free bin calculation\n      * Default trim and mmap thresholds now 256K.\n\n    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)\n      * Introduce independent_comalloc and independent_calloc.\n        Thanks to Michael Pachos for motivation and help.\n      * Make optional .h file available\n      * Allow > 2GB requests on 32bit systems.\n      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.\n        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,\n        and Anonymous.\n      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for\n        helping test this.)\n      * memalign: check alignment arg\n      * realloc: don't try to shift chunks backwards, since this\n        leads to  more fragmentation in some programs and doesn't\n        seem to help in any others.\n      * Collect all cases in malloc requiring system memory into sysmalloc\n      * Use mmap as backup to sbrk\n      * Place all internal state in malloc_state\n      * Introduce fastbins (although similar to 2.5.1)\n      * Many minor tunings and cosmetic improvements\n      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK\n      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS\n        Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.\n      * Include errno.h to support default failure action.\n\n    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)\n      * return null for negative arguments\n      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>\n         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'\n          (e.g. WIN32 platforms)\n         * Cleanup header file inclusion for WIN32 platforms\n         * Cleanup code to avoid Microsoft Visual C++ compiler complaints\n         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing\n           memory allocation routines\n         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)\n         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to\n           usage of 'assert' in non-WIN32 code\n         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to\n           avoid infinite loop\n      * Always call 'fREe()' rather than 'free()'\n\n    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)\n      * Fixed ordering problem with boundary-stamping\n\n    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)\n      * Added pvalloc, as recommended by H.J. Liu\n      * Added 64bit pointer support mainly from Wolfram Gloger\n      * Added anonymously donated WIN32 sbrk emulation\n      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen\n      * malloc_extend_top: fix mask error that caused wastage after\n        foreign sbrks\n      * Add linux mremap support code from HJ Liu\n\n    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)\n      * Integrated most documentation with the code.\n      * Add support for mmap, with help from\n        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).\n      * Use last_remainder in more cases.\n      * Pack bins using idea from  colin@nyx10.cs.du.edu\n      * Use ordered bins instead of best-fit threshhold\n      * Eliminate block-local decls to simplify tracing and debugging.\n      * Support another case of realloc via move into top\n      * Fix error occuring when initial sbrk_base not word-aligned.\n      * Rely on page size for units instead of SBRK_UNIT to\n        avoid surprises about sbrk alignment conventions.\n      * Add mallinfo, mallopt. Thanks to Raymond Nijssen\n        (raymond@es.ele.tue.nl) for the suggestion.\n      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.\n      * More precautions for cases where other routines call sbrk,\n        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).\n      * Added macros etc., allowing use in linux libc from\n        H.J. Lu (hjl@gnu.ai.mit.edu)\n      * Inverted this history list\n\n    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)\n      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.\n      * Removed all preallocation code since under current scheme\n        the work required to undo bad preallocations exceeds\n        the work saved in good cases for most test programs.\n      * No longer use return list or unconsolidated bins since\n        no scheme using them consistently outperforms those that don't\n        given above changes.\n      * Use best fit for very large chunks to prevent some worst-cases.\n      * Added some support for debugging\n\n    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)\n      * Removed footers when chunks are in use. Thanks to\n        Paul Wilson (wilson@cs.texas.edu) for the suggestion.\n\n    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)\n      * Added malloc_trim, with help from Wolfram Gloger\n        (wmglo@Dent.MED.Uni-Muenchen.DE).\n\n    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)\n\n    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)\n      * realloc: try to expand in both directions\n      * malloc: swap order of clean-bin strategy;\n      * realloc: only conditionally expand backwards\n      * Try not to scavenge used bins\n      * Use bin counts as a guide to preallocation\n      * Occasionally bin return list chunks in first scan\n      * Add a few optimizations from colin@nyx10.cs.du.edu\n\n    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)\n      * faster bin computation & slightly different binning\n      * merged all consolidations to one part of malloc proper\n         (eliminating old malloc_find_space & malloc_clean_bin)\n      * Scan 2 returns chunks (not just 1)\n      * Propagate failure in realloc if malloc returns 0\n      * Add stuff to allow compilation on non-ANSI compilers\n          from kpv@research.att.com\n\n    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)\n      * removed potential for odd address access in prev_chunk\n      * removed dependency on getpagesize.h\n      * misc cosmetics and a bit more internal documentation\n      * anticosmetics: mangled names in macros to evade debugger strangeness\n      * tested on sparc, hp-700, dec-mips, rs6000\n          with gcc & native cc (hp, dec only) allowing\n          Detlefs & Zorn comparison study (in SIGPLAN Notices.)\n\n    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)\n      * Based loosely on libg++-1.2X malloc. (It retains some of the overall\n         structure of old version,  but most details differ.)\n\n*/\n}\n"
  },
  {
    "path": "ptms/rwlocks/CRWWP.hpp",
    "content": "/******************************************************************************\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of Concurrency Freaks nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************\n */\n\n#ifndef _CRWWP_H_\n#define _CRWWP_H_\n\n#include <atomic>\n#include <stdexcept>\n#include <cstdint>\n#include <thread>\n\n\n// Pause to prevent excess processor bus usage\n#if defined( __sparc )\n#define Pause() __asm__ __volatile__ ( \"rd %ccr,%g0\" )\n#elif defined( __i386 ) || defined( __x86_64 )\n#define Pause() __asm__ __volatile__ ( \"pause\" : : : )\n#else\n#define Pause() std::this_thread::yield();\n#endif\n\n\n\n\n/**\n * <h1> C-RW-WP </h1>\n *\n * A C-RW-WP reader-writer lock with writer preference and using a\n * Ticket Lock as Cohort.\n * This is starvation-free for writers and for readers, but readers may be\n * starved by writers.\n *\n * C-RW-WP paper:         http://dl.acm.org/citation.cfm?id=2442532\n *\n * <p>\n * @author Pedro Ramalhete\n * @author Andreia Correia\n */\nclass CRWWP {\n\nprivate:\n    class TicketLock {\n        alignas(128) std::atomic<uint64_t> ticket {0};\n        alignas(128) std::atomic<uint64_t> grant {0};\n    public:\n        bool isLocked() { return grant.load(std::memory_order_acquire) != ticket.load(std::memory_order_acquire); }\n        void lock() {\n            auto tkt = ticket.fetch_add(1);\n            while (tkt != grant.load(std::memory_order_acquire)) Pause();\n        }\n        void unlock() {\n            auto tkt = grant.load(std::memory_order_relaxed);\n            grant.store(tkt+1, std::memory_order_release);\n        }\n    };\n\n    class RIAtomicCounterArray {\n    private:\n        static const int MAX_THREADS = 64;\n        static const int CLPAD = (128/sizeof(std::atomic<uint64_t>));\n        static const int COUNTER_SIZE = 3*MAX_THREADS; // Alternatively, use std::thread::hardware_concurrency()\n        std::hash<std::thread::id> hashFunc {};\n        alignas(128) std::atomic<uint64_t> counters[COUNTER_SIZE*CLPAD] ;\n    public:\n        RIAtomicCounterArray() {\n            for (int i=0; i < COUNTER_SIZE; i++) {\n                counters[i*CLPAD].store(0, std::memory_order_relaxed);\n            }\n        }\n        void arrive(const int notused=0) noexcept {\n            const uint64_t tid = hashFunc(std::this_thread::get_id());\n            const int icounter = (int)(tid % COUNTER_SIZE);\n            counters[icounter*CLPAD].fetch_add(1);\n        }\n        void depart(const int notused=0) noexcept {\n            const uint64_t tid = hashFunc(std::this_thread::get_id());\n            const int icounter = (int)(tid % COUNTER_SIZE);\n            counters[icounter*CLPAD].fetch_add(-1);\n        }\n        bool isEmpty(void) noexcept {\n            for (int i = 0; i < COUNTER_SIZE; i++) {\n                if (counters[i*CLPAD].load(std::memory_order_acquire) > 0) return false;\n            }\n            return true;\n        }\n    };\n\n    static const int MAX_THREADS = 128;\n    //static const int LOCKED = 1;\n    //static const int UNLOCKED = 0;\n    const int maxThreads;\n    RIAtomicCounterArray ri {};\n    //alignas(128) std::atomic<int> cohort { UNLOCKED };\n    TicketLock cohort {};\n\npublic:\n    CRWWP(const int maxThreads=MAX_THREADS) : maxThreads{maxThreads} { }\n\n    std::string className() { return \"C-RW-WP\"; }\n\n    void exclusiveLock() {\n        cohort.lock();\n        while (!ri.isEmpty()) Pause();\n    }\n\n    void exclusiveUnlock() {\n        cohort.unlock();\n    }\n\n    void sharedLock() {\n        while (true) {\n            ri.arrive();\n            if (!cohort.isLocked()) break;\n            ri.depart();\n            while (cohort.isLocked()) Pause();\n        }\n    }\n\n    void sharedUnlock() {\n        ri.depart();\n    }\n};\n\n#endif /* _CRWWP_H_ */\n"
  },
  {
    "path": "ptms/rwlocks/CRWWP_SpinLock.hpp",
    "content": "/******************************************************************************\n * Copyright (c) 2014-2017, Pedro Ramalhete, Andreia Correia\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of Concurrency Freaks nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************\n */\n\n#ifndef _CRWWP_Spin_H_\n#define _CRWWP_Spin_H_\n\n#include <atomic>\n#include <stdexcept>\n#include <cstdint>\n#include <thread>\n#include \"../../common/ThreadRegistry.hpp\"\n\n\n// Pause to prevent excess processor bus usage\n#if defined( __sparc )\n#define Pause() __asm__ __volatile__ ( \"rd %ccr,%g0\" )\n#elif defined( __i386 ) || defined( __x86_64 )\n#define Pause() __asm__ __volatile__ ( \"pause\" : : : )\n#else\n#define Pause() std::this_thread::yield();\n#endif\n\n\n\n\n/**\n * <h1> C-RW-WP </h1>\n *\n * A C-RW-WP reader-writer lock with writer preference and using a\n * spin Lock as Cohort.\n *\n * C-RW-WP paper:         http://dl.acm.org/citation.cfm?id=2442532\n *\n * <p>\n * @author Pedro Ramalhete\n * @author Andreia Correia\n */\nclass CRWWPSpinLock {\n\nprivate:\n    class SpinLock {\n        alignas(128) std::atomic<int> writers {0};\n    public:\n        bool isLocked() { return (writers.load()==1); }\n        void lock() {\n            while (!tryLock()) Pause();\n        }\n        bool tryLock() {\n            if(writers.load()==1)return false;\n            int tmp = 0;\n            return writers.compare_exchange_strong(tmp,1);\n        }\n        void unlock() {\n            writers.store(0, std::memory_order_release);\n        }\n    };\n\n    class RIStaticPerThread {\n    private:\n        static const uint64_t NOT_READING = 0;\n        static const uint64_t READING = 1;\n        static const int CLPAD = 128/sizeof(uint64_t);\n        static const int MAX_THREADS = 128;\n        const int maxThreads;\n        alignas(128) std::atomic<uint64_t>* states;\n\n    public:\n        RIStaticPerThread(int maxThreads=MAX_THREADS) : maxThreads{maxThreads} {\n            states = new std::atomic<uint64_t>[maxThreads*CLPAD];\n            for (int tid = 0; tid < maxThreads; tid++) {\n                states[tid*CLPAD].store(NOT_READING, std::memory_order_relaxed);\n            }\n        }\n\n        ~RIStaticPerThread() {\n            delete[] states;\n        }\n\n        inline void arrive(const int tid) noexcept {\n            states[tid*CLPAD].store(READING);\n        }\n\n        inline void depart(const int tid) noexcept {\n            states[tid*CLPAD].store(NOT_READING, std::memory_order_release);\n        }\n\n        inline bool isEmpty() noexcept {\n            const int maxTid = ThreadRegistry::getMaxThreads();\n            for (int tid = 0; tid < maxTid; tid++) {\n                if (states[tid*CLPAD].load() != NOT_READING) return false;\n            }\n            return true;\n        }\n    };\n\n    static const int MAX_THREADS = 128;\n    //static const int LOCKED = 1;\n    //static const int UNLOCKED = 0;\n    const int maxThreads;\n    RIStaticPerThread ri {};\n    //alignas(128) std::atomic<int> cohort { UNLOCKED };\n    SpinLock splock {};\n\npublic:\n    CRWWPSpinLock(const int maxThreads=MAX_THREADS) : maxThreads{maxThreads} { }\n\n    std::string className() { return \"C-RW-WP-SpinLock\"; }\n\n    void exclusiveLock() {\n        splock.lock();\n        while (!ri.isEmpty()) Pause();\n    }\n\n    bool tryExclusiveLock() {\n        return splock.tryLock();\n    }\n\n    void exclusiveUnlock() {\n        splock.unlock();\n    }\n\n    void sharedLock(const int tid) {\n        while (true) {\n            ri.arrive(tid);\n            if (!splock.isLocked()) break;\n            ri.depart(tid);\n            while (splock.isLocked()) Pause();\n        }\n    }\n\n    void sharedUnlock(const int tid) {\n        ri.depart(tid);\n    }\n\n    void waitForReaders(){\n        while (!ri.isEmpty()) {} // spin waiting for readers\n    }\n};\n\n#endif /* _CRWWP_H_ */\n"
  },
  {
    "path": "stms/CRWWPSTM.hpp",
    "content": "/******************************************************************************\r\n * Copyright (c) 2017-2019, Pedro Ramalhete, Andreia Correia\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *     * Redistributions of source code must retain the above copyright\r\n *       notice, this list of conditions and the following disclaimer.\r\n *     * Redistributions in binary form must reproduce the above copyright\r\n *       notice, this list of conditions and the following disclaimer in the\r\n *       documentation and/or other materials provided with the distribution.\r\n *     * Neither the name of Concurrency Freaks nor the\r\n *       names of its contributors may be used to endorse or promote products\r\n *       derived from this software without specific prior written permission.\r\n\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\r\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n ******************************************************************************\r\n */\r\n\r\n#ifndef _C_RW_WP_TRANSACTIONAL_MEMORY_H_\r\n#define _C_RW_WP_TRANSACTIONAL_MEMORY_H_\r\n\r\n#include <atomic>\r\n#include <thread>\r\n#include <cassert>\r\n#include <functional>\r\n\r\n/* <h1> C-RW-WP Software Transactional Memory </h1>\r\n *\r\n * This is a Transactional Memory that uses C-RW-WP plus Flat-Combining.\r\n * It is blocking but with starvation-freedom.\r\n *\r\n * Transactions are irrevocable, therefore we don't provide an API for\r\n * aborting transactions.\r\n *\r\n * We have put everything in this header so that the end-user can include a\r\n * single header and gets a working Software Transaction Memory.\r\n * It isn't pretty, but it makes life easier for application developers.\r\n * And yes, it's kind of silly to make an STM out of a global lock, but we did\r\n * it to have a \"baseline\" against which to compare other STMs.\r\n *\r\n * C-RW-WP paper:                            http://dl.acm.org/citation.cfm?id=2442532\r\n * Flat Combining paper:                     http://dl.acm.org/citation.cfm?id=1810540\r\n * A post about C-RW-WP with Flat Combining: http://concurrencyfreaks.com/2017/07/left-right-and-c-rw-wp-with-flat.html\r\n *\r\n * We have the following classes in this file:\r\n * tmtype<T>         -> Annotation for TM types (not really needed but useful for the benchmarks)\r\n * CRWWPTM           -> The singleton TM\r\n *\r\n * How to use this TM:\r\n * crwwptm::tmtype<UserObject> obj {};\r\n * crwwptm::writeTx([&obj] () {obj.mutative_method()} );\r\n * crwwptm::readTx([&obj] () {obj.non_mutative_method()} );\r\n *\r\n * @author Pedro Ramalhete\r\n * @author Andreia Correia\r\n */\r\nnamespace crwwpstm {\r\n\r\n\r\n// Needed by the TM benchmarks and tests infrastructure\r\ntemplate<typename T>\r\nstruct tmtype {\r\n    T val {};\r\n\r\n    tmtype() { }\r\n\r\n    tmtype(T initVal) : val{initVal} {}\r\n\r\n    // Casting operator\r\n    operator T() {\r\n        return load();\r\n    }\r\n\r\n    // Prefix increment operator: ++x\r\n    void operator++ () {\r\n        store(load()+1);\r\n    }\r\n\r\n    // Prefix decrement operator: --x\r\n    void operator-- () {\r\n        store(load()-1);\r\n    }\r\n\r\n    void operator++ (int) {\r\n        store(load()+1);\r\n    }\r\n\r\n    void operator-- (int) {\r\n        store(load()-1);\r\n    }\r\n\r\n    // Equals operator: first downcast to T and then compare\r\n    bool operator == (const T& otherval) const {\r\n        return load() == otherval;\r\n    }\r\n\r\n    // Difference operator: first downcast to T and then compare\r\n    bool operator != (const T& otherval) const {\r\n        return load() != otherval;\r\n    }\r\n\r\n    // Operator arrow ->\r\n    T operator->() {\r\n        return load();\r\n    }\r\n\r\n    // Copy constructor\r\n    tmtype<T>(const tmtype<T>& other) {\r\n        store(other.load());\r\n    }\r\n\r\n    // Assignment operator from an tmtype\r\n    tmtype<T>& operator=(const tmtype<T>& other) {\r\n        store(other.load());\r\n        return *this;\r\n    }\r\n\r\n    // Assignment operator from a value\r\n    tmtype<T>& operator=(T value) {\r\n        store(value);\r\n        return *this;\r\n    }\r\n\r\n    inline void store(T newVal) {\r\n        val = newVal;\r\n    }\r\n\r\n    inline T load() const {\r\n        return val;\r\n    }\r\n};\r\n\r\n\r\n// Needed by the TM benchmarks and tests infrastructure\r\nstruct tmbase { };\r\n\r\n\r\n//\r\n// Thread Registry stuff\r\n//\r\nextern void thread_registry_deregister_thread(const int tid);\r\n\r\n// An helper class to do the checkin and checkout of the thread registry\r\nstruct ThreadCheckInCheckOut {\r\n    static const int NOT_ASSIGNED = -1;\r\n    int tid { NOT_ASSIGNED };\r\n    ~ThreadCheckInCheckOut() {\r\n        if (tid == NOT_ASSIGNED) return;\r\n        thread_registry_deregister_thread(tid);\r\n    }\r\n};\r\n\r\nextern thread_local ThreadCheckInCheckOut tl_gc_tcico;\r\n\r\n// Forward declaration of global/singleton instance\r\nclass ThreadRegistry;\r\nextern ThreadRegistry gThreadRegistry;\r\n\r\n/*\r\n * <h1> Registry for threads </h1>\r\n *\r\n * This is singleton type class that allows assignement of a unique id to each thread.\r\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\r\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\r\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\r\n * corresponding slot to be used by a later thread.\r\n * RomulusLR relies on this to work properly.\r\n */\r\nclass ThreadRegistry {\r\npublic:\r\n    static const int                    REGISTRY_MAX_THREADS = 128;\r\n\r\nprivate:\r\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\r\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\r\n\r\npublic:\r\n    ThreadRegistry() {\r\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            usedTID[it].store(false, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    // Progress Condition: wait-free bounded (by the number of threads)\r\n    int register_thread_new(void) {\r\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\r\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\r\n            bool unused = false;\r\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\r\n            // Increase the current maximum to cover our thread id\r\n            int curMax = maxTid.load();\r\n            while (curMax <= tid) {\r\n                maxTid.compare_exchange_strong(curMax, tid+1);\r\n                curMax = maxTid.load();\r\n            }\r\n            tl_gc_tcico.tid = tid;\r\n            return tid;\r\n        }\r\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\r\n        assert(false);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void deregister_thread(const int tid) {\r\n        usedTID[tid].store(false, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    static inline uint64_t getMaxThreads(void) {\r\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    static inline int getTID(void) {\r\n        int tid = tl_gc_tcico.tid;\r\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\r\n        return gThreadRegistry.register_thread_new();\r\n    }\r\n};\r\n\r\n// Forward declaration to be able to have static methods for updateTx() and readTx()\r\nclass CRWWPSTM;\r\nextern CRWWPSTM gCRWWPSTM;\r\n\r\n\r\nclass CRWWPSTM {\r\n\r\nprivate:\r\n    class RIStaticPerThread {\r\n    private:\r\n        static const uint64_t NOT_READING = 0;\r\n        static const uint64_t READING = 1;\r\n        static const int CLPAD = 128/sizeof(uint64_t);\r\n        const int maxThreads;\r\n        alignas(128) std::atomic<uint64_t>* states;\r\n\r\n    public:\r\n        RIStaticPerThread(int maxThreads) : maxThreads{maxThreads} {\r\n            states = new std::atomic<uint64_t>[maxThreads*CLPAD];\r\n            for (int tid = 0; tid < maxThreads; tid++) {\r\n                states[tid*CLPAD].store(NOT_READING, std::memory_order_relaxed);\r\n            }\r\n        }\r\n\r\n        ~RIStaticPerThread() {\r\n            delete[] states;\r\n        }\r\n\r\n        inline void arrive(const int tid) noexcept {\r\n            states[tid*CLPAD].store(READING);\r\n        }\r\n\r\n        inline void depart(const int tid) noexcept {\r\n            states[tid*CLPAD].store(NOT_READING, std::memory_order_release);\r\n        }\r\n\r\n        inline bool isEmpty() noexcept {\r\n            for (int tid = 0; tid < ThreadRegistry::getMaxThreads(); tid++) {\r\n                if (states[tid*CLPAD].load() != NOT_READING) return false;\r\n            }\r\n            return true;\r\n        }\r\n    };\r\n\r\n    static const int CLPAD = 128/sizeof(uintptr_t);\r\n    static const int MAX_THREADS = 1024;\r\n    static const int LOCKED = 1;\r\n    static const int UNLOCKED = 0;\r\n    // Stuff use by the Flat Combining mechanism\r\n    alignas(128) std::atomic< std::function<uint64_t()>* >* fc;\r\n    alignas(128) uint64_t* results;\r\n    alignas(128) std::atomic<int> cohort { UNLOCKED };\r\n    RIStaticPerThread ri { MAX_THREADS };\r\n\r\npublic:\r\n    CRWWPSTM(const int maxThreads=0) {\r\n        fc = new std::atomic< std::function<uint64_t()>* >[MAX_THREADS*CLPAD];\r\n        results = new uint64_t[MAX_THREADS*CLPAD];\r\n        for (int i = 0; i < MAX_THREADS; i++) {\r\n            fc[i*CLPAD].store(nullptr, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    ~CRWWPSTM() {\r\n        delete[] fc;\r\n        delete[] results;\r\n    }\r\n\r\n    static std::string className() { return \"CRWWPSTM\"; }\r\n\r\n    template<typename R, typename F> static R updateTx(F&& func) { return gCRWWPSTM.ns_updateTx<R>(func); }\r\n    template<typename R, typename F> static R readTx(F&& func) { return gCRWWPSTM.ns_readTx<R>(func); }\r\n    template<typename F> static void updateTx(F&& func) { gCRWWPSTM.ns_updateTx(func); }\r\n    template<typename F> static void readTx(F&& func) { gCRWWPSTM.ns_readTx(func); }\r\n\r\n\r\n    // Progress: Blocking (starvation-free)\r\n    template<typename R, typename F> R ns_updateTx(F&& mutativeFunc) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        std::function<R()> uf = {mutativeFunc}; // Use a stack allocated std::function instead of heap allocated\r\n        std::function<uint64_t()>* myfunc = (std::function<uint64_t()>*)&uf;\r\n        // Add our mutation to the array of flat combining\r\n        fc[tid*CLPAD].store(myfunc, std::memory_order_release);\r\n        // Lock writersMutex\r\n        while (true) {\r\n            int unlocked = UNLOCKED;\r\n            if (cohort.load() == UNLOCKED &&\r\n                cohort.compare_exchange_strong(unlocked, LOCKED)) break;\r\n            // Check if another thread executed my mutation\r\n            if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) return (R)(results[tid*CLPAD]);\r\n            std::this_thread::yield();\r\n        }\r\n        // Wait for all the readers to depart\r\n        while (!ri.isEmpty()) {\r\n            // Check if another thread executed my mutation\r\n            if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) {\r\n                cohort.store(UNLOCKED, std::memory_order_release);\r\n                return (R)results[tid*CLPAD];\r\n            }\r\n            // spin\r\n        }\r\n        // Save a local copy of the flat combining array\r\n        bool somethingToDo = false;\r\n        const int maxThreads = ThreadRegistry::getMaxThreads();\r\n        std::function<uint64_t()>* lfc[maxThreads];\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            lfc[i] = fc[i*CLPAD].load(std::memory_order_acquire);\r\n            if (lfc[i] != nullptr) somethingToDo = true;\r\n        }\r\n        // Check if there is at least one operation to apply\r\n        if (somethingToDo) {\r\n            // For each mutation in the flat combining array, apply it in the order\r\n            // of the array, save the result, and set the entry in the array to nullptr\r\n            for (int i = 0; i < maxThreads; i++) {\r\n                auto mutation = fc[i*CLPAD].load(std::memory_order_acquire);\r\n                if (mutation == nullptr) continue;\r\n                results[i*CLPAD] = (uint64_t)((*mutation)());\r\n                fc[i*CLPAD].store(nullptr, std::memory_order_release);\r\n            }\r\n        }\r\n        // unlock()\r\n        cohort.store(UNLOCKED, std::memory_order_release);\r\n        return (R)(results[tid*CLPAD]);\r\n    }\r\n\r\n    // Progress: Blocking (starvation-free)\r\n    template<typename F> void ns_updateTx(F&& mutativeFunc) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        std::function<void()> vf {mutativeFunc};  // Use a stack allocated std::function instead of heap allocated\r\n        std::function<uint64_t()>* myfunc = (std::function<uint64_t()>*)&vf;\r\n        // Add our mutation to the array of flat combining\r\n        fc[tid*CLPAD].store(myfunc);\r\n        // Lock writersMutex\r\n        while (true) {\r\n            int unlocked = UNLOCKED;\r\n            if (cohort.load() == UNLOCKED &&\r\n                cohort.compare_exchange_strong(unlocked, LOCKED)) break;\r\n            // Check if another thread executed my mutation\r\n            if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) return;\r\n            std::this_thread::yield();\r\n        }\r\n        // Wait for all the readers to depart\r\n        while (!ri.isEmpty()) {\r\n            // Check if another thread executed my mutation\r\n            if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) {\r\n                cohort.store(UNLOCKED, std::memory_order_release);\r\n                return;\r\n            }\r\n            // spin\r\n        }\r\n        // Save a local copy of the flat combining array\r\n        bool somethingToDo = false;\r\n        const int maxThreads = ThreadRegistry::getMaxThreads();\r\n        std::function<uint64_t()>* lfc[maxThreads];\r\n        for (int i = 0; i < maxThreads; i++) {\r\n            lfc[i] = fc[i*CLPAD].load(std::memory_order_acquire);\r\n            if (lfc[i] != nullptr) somethingToDo = true;\r\n        }\r\n        // Check if there is at least one operation to apply\r\n        if (somethingToDo) {\r\n            // For each mutation in the flat combining array, apply it in the order\r\n            // of the array, save the result, and set the entry in the array to nullptr\r\n            for (int i = 0; i < maxThreads; i++) {\r\n                auto mutation = fc[i*CLPAD].load(std::memory_order_acquire);\r\n                if (mutation == nullptr) continue;\r\n                results[i*CLPAD] = (uint64_t)((*mutation)());\r\n                fc[i*CLPAD].store(nullptr, std::memory_order_release);\r\n            }\r\n        }\r\n        // unlock()\r\n        cohort.store(UNLOCKED, std::memory_order_release);\r\n    }\r\n\r\n    // Progress: Blocking (starvation-free)\r\n    template<typename R, typename F> R ns_readTx(F&& readFunc) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        bool announced = false;\r\n        std::function<uint64_t()> myfunc = readFunc;\r\n        // lock()\r\n        while (true) {\r\n            ri.arrive(tid);\r\n            if (cohort.load() == UNLOCKED) break;\r\n            ri.depart(tid);\r\n            if (!announced) {\r\n                // Put my operation in the flat combining array for a Writer to do it\r\n                fc[tid*CLPAD].store(&myfunc, std::memory_order_release);\r\n                announced = true;\r\n            }\r\n            // If a Writer set our entry to nullptr then the result is ready\r\n            while (cohort.load() == LOCKED) {\r\n                if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) {\r\n                    return (R)(results[tid*CLPAD]);\r\n                }\r\n                std::this_thread::yield();  // pause()\r\n            }\r\n        }\r\n        // Execute our read-only function\r\n        R result = readFunc();\r\n        if (announced) fc[tid*CLPAD].store(nullptr, std::memory_order_relaxed);\r\n        // unlock()\r\n        ri.depart(tid);\r\n        return result;\r\n    }\r\n\r\n    template<typename F> void ns_readTx(F&& readFunc) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        bool announced = false;\r\n        std::function<void()> myvoidfunc = readFunc;\r\n        std::function<uint64_t()> *myfunc = (std::function<uint64_t()>*)&myvoidfunc;\r\n        // lock()\r\n        while (true) {\r\n            ri.arrive(tid);\r\n            if (cohort.load() == UNLOCKED) break;\r\n            ri.depart(tid);\r\n            if (!announced) {\r\n                // Put my operation in the flat combining array for a Writer to do it\r\n                fc[tid*CLPAD].store(myfunc, std::memory_order_release);\r\n                announced = true;\r\n            }\r\n            // If a Writer set our entry to nullptr then the result is ready\r\n            while (cohort.load() == LOCKED) {\r\n                if (fc[tid*CLPAD].load(std::memory_order_acquire) == nullptr) {\r\n                    return;\r\n                }\r\n                std::this_thread::yield();  // pause()\r\n            }\r\n        }\r\n        // Execute our read-only function\r\n        readFunc();\r\n        if (announced) fc[tid*CLPAD].store(nullptr, std::memory_order_relaxed);\r\n        // unlock()\r\n        ri.depart(tid);\r\n    }\r\n\r\n\r\n    template <typename T, typename... Args>\r\n    T* tmNew(Args&&... args) {\r\n        return new T(std::forward<Args>(args)...);\r\n    }\r\n\r\n    template<typename T>\r\n    void tmDelete(T* obj) {\r\n        delete obj;\r\n    }\r\n\r\n    // We snap a tmbase at the beginning of the allocation\r\n    static void* tmMalloc(size_t size) {\r\n        uint8_t* ptr = (uint8_t*)std::malloc(size+sizeof(tmbase));\r\n        return ptr + sizeof(tmbase);\r\n    }\r\n\r\n    // We assume there is a tmbase allocated in the beginning of the allocation\r\n    static void tmFree(void* obj) {\r\n        if (obj == nullptr) return;\r\n        uint8_t* ptr = (uint8_t*)obj - sizeof(tmbase);\r\n        std::free(ptr);  // Outside a transaction, just free the object\r\n    }\r\n\r\n};\r\n\r\n\r\nextern CRWWPSTM gCRWWPSTM;\r\n\r\n\r\n\r\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gCRWWPSTM.updateTx<R>(func); }\r\ntemplate<typename R, typename F> static R readTx(F&& func) { return gCRWWPSTM.readTx<R>(func); }\r\ntemplate<typename F> static void updateTx(F&& func) { gCRWWPSTM.updateTx(func); }\r\ntemplate<typename F> static void readTx(F&& func) { gCRWWPSTM.readTx(func); }\r\ntemplate<typename T, typename... Args> static T* tmNew(Args&&... args) { return gCRWWPSTM.tmNew<T>(args...); }\r\ntemplate<typename T> static void tmDelete(T* obj) { gCRWWPSTM.tmDelete<T>(obj); }\r\ninline void* tmMalloc(size_t size) { return CRWWPSTM::tmMalloc(size); }\r\ninline void* tmFree(void* obj) { CRWWPSTM::tmFree(obj); }\r\n\r\n\r\n\r\n//\r\n// Place these in a .cpp if you include this header in multiple files\r\n//\r\nCRWWPSTM gCRWWPSTM {};\r\n// Global/singleton to hold all the thread registry functionality\r\nThreadRegistry gThreadRegistry {};\r\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\r\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\r\nthread_local ThreadCheckInCheckOut tl_gc_tcico {};\r\n// Helper function for thread de-registration\r\nvoid thread_registry_deregister_thread(const int tid) {\r\n    gThreadRegistry.deregister_thread(tid);\r\n}\r\n\r\n} // end of namespace crwwp\r\n\r\n#endif /* _C_RW_WP_TRANSACTIONAL_MEMORY_H_ */\r\n"
  },
  {
    "path": "stms/ESTM.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _ELASTIC_STM_TRANSACTIONAL_MEMORY_WRAPPER_H_\r\n#define _ELASTIC_STM_TRANSACTIONAL_MEMORY_WRAPPER_H_\r\n\r\n#include <atomic>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <vector>\r\n#include <functional>\r\n\r\n\r\nnamespace estm {\r\n\r\n// Compile with explicit calls to ESTM\r\n#include \"estm-0.3.0/include/stm.h\"\r\n#include \"estm-0.3.0/include/mod_mem.h\"\r\n\r\n\r\nstruct tmbase {\r\n};\r\n\r\n\r\n//\r\n// Thread Registry stuff\r\n//\r\nextern void thread_registry_deregister_thread(const int tid);\r\n\r\n// An helper class to do the checkin and checkout of the thread registry\r\nstruct ThreadCheckInCheckOut {\r\n    static const int NOT_ASSIGNED = -1;\r\n    int tid { NOT_ASSIGNED };\r\n    ~ThreadCheckInCheckOut() {\r\n        if (tid == NOT_ASSIGNED) return;\r\n        thread_registry_deregister_thread(tid);\r\n    }\r\n};\r\n\r\nextern thread_local ThreadCheckInCheckOut tl_gc_tcico;\r\n\r\n// Forward declaration of global/singleton instance\r\nclass ThreadRegistry;\r\nextern ThreadRegistry gThreadRegistry;\r\n\r\n/*\r\n * <h1> Registry for threads </h1>\r\n *\r\n * This is singleton type class that allows assignement of a unique id to each thread.\r\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\r\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\r\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\r\n * corresponding slot to be used by a later thread.\r\n * RomulusLR relies on this to work properly.\r\n */\r\nclass ThreadRegistry {\r\npublic:\r\n    static const int                    REGISTRY_MAX_THREADS = 128;\r\n\r\nprivate:\r\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\r\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\r\n\r\npublic:\r\n    ThreadRegistry() {\r\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            usedTID[it].store(false, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    // Progress Condition: wait-free bounded (by the number of threads)\r\n    int register_thread_new(void) {\r\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\r\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\r\n            bool unused = false;\r\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\r\n            // Increase the current maximum to cover our thread id\r\n            int curMax = maxTid.load();\r\n            while (curMax <= tid) {\r\n                maxTid.compare_exchange_strong(curMax, tid+1);\r\n                curMax = maxTid.load();\r\n            }\r\n            tl_gc_tcico.tid = tid;\r\n            return tid;\r\n        }\r\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\r\n        assert(false);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void deregister_thread(const int tid) {\r\n        stm_exit_thread();    // Needed by ESTM\r\n        usedTID[tid].store(false, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    static inline uint64_t getMaxThreads(void) {\r\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    static inline int getTID(void) {\r\n        int tid = tl_gc_tcico.tid;\r\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\r\n        stm_init_thread();   // Needed by TinySTM\r\n        return gThreadRegistry.register_thread_new();\r\n    }\r\n};\r\n\r\n\r\n\r\nclass ESTM;\r\nextern ESTM gESTM;\r\n\r\nclass ESTM {\r\n\r\nprivate:\r\n    // Maximum number of participating threads\r\n    static const uint64_t MAX_THREADS = 128;\r\n\r\npublic:\r\n    ESTM(unsigned int maxThreads=MAX_THREADS) {\r\n        stm_init();\r\n        mod_mem_init();\r\n    }\r\n\r\n    ~ESTM() {\r\n        stm_exit();\r\n    }\r\n\r\n    static std::string className() { return \"ESTM\"; }\r\n\r\n    template<typename R, class F>\r\n    static R updateTx(F&& func) {\r\n        ThreadRegistry::getTID();\r\n        sigjmp_buf *_e = stm_get_env();\r\n        sigsetjmp(*_e, 0);\r\n        stm_start(_e, 0, NL);\r\n        R retval = func();\r\n        stm_commit();\r\n        return retval;\r\n    }\r\n\r\n    template<class F>\r\n    static void updateTx(F&& func) {\r\n        ThreadRegistry::getTID();\r\n        sigjmp_buf *_e = stm_get_env();\r\n        sigsetjmp(*_e, 0);\r\n        stm_start(_e, 0, NL);\r\n        func();\r\n        stm_commit();\r\n    }\r\n\r\n    template<typename R, class F>\r\n    static R readTx(F&& func) {\r\n        ThreadRegistry::getTID();\r\n        sigjmp_buf *_e = stm_get_env();\r\n        sigsetjmp(*_e, 0);\r\n        stm_start(_e, 0, NL);\r\n        R retval = func();\r\n        stm_commit();\r\n        return retval;\r\n    }\r\n\r\n    template<class F>\r\n    static void readTx(F&& func) {\r\n        ThreadRegistry::getTID();\r\n        sigjmp_buf *_e = stm_get_env();\r\n        sigsetjmp(*_e, 0);\r\n        stm_start(_e, 0, NL);\r\n        func();\r\n        stm_commit();\r\n    }\r\n\r\n    template <typename T, typename... Args>\r\n    static T* tmNew(Args&&... args) {\r\n        void* addr = stm_malloc(sizeof(T));\r\n        assert(addr != NULL);\r\n        T* ptr = new (addr) T(std::forward<Args>(args)...);\r\n        return ptr;\r\n    }\r\n\r\n    template<typename T>\r\n    static void tmDelete(T* obj) {\r\n        if (obj == nullptr) return;\r\n        obj->~T();\r\n        // Reset memory block to avoid allocator metadata corruption\r\n        // TODO: be careful with the last word, the object better be a word multiple otherwise this can corrupt data from the next object\r\n        stm_word_t* wptr = (stm_word_t *)obj;\r\n        for (int i = 0; i < sizeof(T)/sizeof(stm_word_t) ;i++, wptr++) stm_store(wptr, 0);\r\n        stm_free(obj, sizeof(T));\r\n    }\r\n\r\n    static void* tmMalloc(size_t size) {\r\n        return stm_malloc(size);\r\n    }\r\n\r\n    static void tmFree(void* obj) {\r\n        stm_free(obj, 0); // TODO: is it ok to pass zero here?\r\n    }\r\n};\r\n\r\n\r\n\r\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\r\ntemplate<typename T>\r\nstruct tmtype {\r\n    T val {};\r\n\r\n    tmtype() { }\r\n\r\n    tmtype(T initVal) : val{initVal} {}\r\n\r\n    // Casting operator\r\n    operator T() {\r\n        return load();\r\n    }\r\n\r\n    // Prefix increment operator: ++x\r\n    void operator++ () {\r\n        store(load()+1);\r\n    }\r\n\r\n    // Prefix decrement operator: --x\r\n    void operator-- () {\r\n        store(load()-1);\r\n    }\r\n\r\n    void operator++ (int) {\r\n        store(load()+1);\r\n    }\r\n\r\n    void operator-- (int) {\r\n        store(load()-1);\r\n    }\r\n\r\n    // Equals operator: first downcast to T and then compare\r\n    bool operator == (const T& otherval) const {\r\n        return load() == otherval;\r\n    }\r\n\r\n    // Difference operator: first downcast to T and then compare\r\n    bool operator != (const T& otherval) const {\r\n        return load() != otherval;\r\n    }\r\n\r\n    // Relational operators\r\n    bool operator < (const T& rhs) {\r\n        return load() < rhs;\r\n    }\r\n    bool operator > (const T& rhs) {\r\n        return load() > rhs;\r\n    }\r\n    bool operator <= (const T& rhs) {\r\n        return load() <= rhs;\r\n    }\r\n    bool operator >= (const T& rhs) {\r\n        return load() >= rhs;\r\n    }\r\n\r\n    // Operator arrow ->\r\n    T operator->() {\r\n        return load();\r\n    }\r\n\r\n    // Copy constructor\r\n    tmtype<T>(const tmtype<T>& other) {\r\n        store(other.load());\r\n    }\r\n\r\n    // Assignment operator from an tmtype\r\n    tmtype<T>& operator=(const tmtype<T>& other) {\r\n        store(other.load());\r\n        return *this;\r\n    }\r\n\r\n    // Assignment operator from a value\r\n    tmtype<T>& operator=(T value) {\r\n        store(value);\r\n        return *this;\r\n    }\r\n\r\n    inline void store(T newVal) {\r\n        stm_store((stm_word_t *)&val, (stm_word_t)newVal);\r\n    }\r\n\r\n    // Meant to be called when know we're the only ones touching\r\n    // these contents, for example, in the constructor of an object, before\r\n    // making the object visible to other threads.\r\n    inline void isolated_store(T newVal) {\r\n        val = newVal;\r\n    }\r\n\r\n    inline T load() const {\r\n        return (T)stm_load((stm_word_t *)&val);\r\n    }\r\n};\r\n\r\nextern ESTM gESTM;\r\n\r\n// Wrapper methods to the global TM instance. The user should use these:\r\ntemplate<typename R, typename F> R updateTx(F&& mutativeFunc) { return gESTM.updateTx<R>(mutativeFunc); }\r\ntemplate<typename R, typename F> R readTx(F&& readFunc) { return gESTM.readTx<R>(readFunc); }\r\ntemplate<typename F> void updateTx(F&& mutativeFunc) { gESTM.updateTx(mutativeFunc); }\r\ntemplate<typename F> void readTx(F&& readFunc) { gESTM.readTx(readFunc); }\r\n\r\n// Wrapper to not do any transaction\r\ntemplate<typename R, typename Func>\r\nR notx(const int tid, Func&& func) {\r\n    return func();\r\n}\r\n\r\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return gESTM.tmNew<T>(args...); }\r\ntemplate<typename T> void tmDelete(T* obj) { gESTM.tmDelete<T>(obj); }\r\nstatic void* tmMalloc(size_t size) { return stm_malloc(size); }\r\nstatic void tmFree(void* obj) { stm_free(obj, 0); } // TODO: is it ok to pass zero here?\r\n\r\nstatic int getTID(void) { return ThreadRegistry::getTID(); }\r\n\r\n\r\n//\r\n// Place these in a .cpp if you include this header in multiple files\r\n//\r\nESTM gESTM {};\r\n// Global/singleton to hold all the thread registry functionality\r\nThreadRegistry gThreadRegistry {};\r\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\r\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\r\nthread_local ThreadCheckInCheckOut tl_gc_tcico {};\r\n// Helper function for thread de-registration\r\nvoid thread_registry_deregister_thread(const int tid) {\r\n    gThreadRegistry.deregister_thread(tid);\r\n}\r\n\r\n\r\n\r\n}\r\n\r\n#endif /* _ELASTIC_STM_TRANSACTIONAL_MEMORY_WRAPPER_H_ */\r\n"
  },
  {
    "path": "stms/OneFileLF.hpp",
    "content": "/*\r\n * Copyright 2017-2019\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_WITH_HAZARD_ERAS_H_\r\n#define _ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_WITH_HAZARD_ERAS_H_\r\n\r\n#include <atomic>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <vector>\r\n#include <functional>\r\n#include <cstring>\r\n#include <cstdint>   // Needed by uint64_t\r\n\r\n// Please keep this file in sync (as much as possible) with ptms/POneFileLF.hpp\r\n\r\nnamespace oflf {\r\n\r\n//\r\n// User configurable variables.\r\n// Feel free to change these if you need larger transactions, more allocations per transacation, or more threads.\r\n//\r\n\r\n// Maximum number of registered threads that can execute transactions\r\nstatic const int REGISTRY_MAX_THREADS = 128;\r\n// Maximum number of stores in the WriteSet per transaction\r\nstatic const uint64_t TX_MAX_STORES = 10*1024;\r\n// Number of buckets in the hashmap of the WriteSet.\r\nstatic const uint64_t HASH_BUCKETS = 1024;\r\n// Maximum number of allocations in one transaction\r\nstatic const uint64_t TX_MAX_ALLOCS = 10*1024;\r\n// Maximum number of deallocations in one transaction\r\nstatic const uint64_t TX_MAX_RETIRES = 10*1024;\r\n\r\n\r\n\r\n// DCAS / CAS2 macro\r\n#define DCAS(ptr, o1, o2, n1, n2)                               \\\r\n({                                                              \\\r\n    char __ret;                                                 \\\r\n    __typeof__(o2) __junk;                                      \\\r\n    __typeof__(*(ptr)) __old1 = (o1);                           \\\r\n    __typeof__(o2) __old2 = (o2);                               \\\r\n    __typeof__(*(ptr)) __new1 = (n1);                           \\\r\n    __typeof__(o2) __new2 = (n2);                               \\\r\n    asm volatile(\"lock cmpxchg16b %2;setz %1\"                   \\\r\n                   : \"=d\"(__junk), \"=a\"(__ret), \"+m\" (*ptr)     \\\r\n                   : \"b\"(__new1), \"c\"(__new2),                  \\\r\n                     \"a\"(__old1), \"d\"(__old2));                 \\\r\n    __ret; })\r\n\r\n\r\n// Functions to convert between a transaction identifier (uint64_t) and a pair of {sequence,index}\r\nstatic inline uint64_t seqidx2trans(uint64_t seq, uint64_t idx) {\r\n    return (seq << 10) | idx;\r\n}\r\nstatic inline uint64_t trans2seq(uint64_t trans) {\r\n    return trans >> 10;\r\n}\r\nstatic inline uint64_t trans2idx(uint64_t trans) {\r\n    return trans & 0x3FF; // 10 bits\r\n}\r\n\r\n\r\n//\r\n// Thread Registry stuff\r\n//\r\nextern void thread_registry_deregister_thread(const int tid);\r\n\r\n// An helper class to do the checkin and checkout of the thread registry\r\nstruct ThreadCheckInCheckOut {\r\n    static const int NOT_ASSIGNED = -1;\r\n    int tid { NOT_ASSIGNED };\r\n    ~ThreadCheckInCheckOut() {\r\n        if (tid == NOT_ASSIGNED) return;\r\n        thread_registry_deregister_thread(tid);\r\n    }\r\n};\r\n\r\nextern thread_local ThreadCheckInCheckOut tl_tcico;\r\n\r\n// Forward declaration of global/singleton instance\r\nclass ThreadRegistry;\r\nextern ThreadRegistry gThreadRegistry;\r\n\r\n/*\r\n * <h1> Registry for threads </h1>\r\n *\r\n * This is singleton type class that allows assignement of a unique id to each thread.\r\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\r\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\r\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\r\n * corresponding slot to be used by a later thread.\r\n */\r\nclass ThreadRegistry {\r\nprivate:\r\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\r\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\r\n\r\npublic:\r\n    ThreadRegistry() {\r\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            usedTID[it].store(false, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    int register_thread_new(void) {\r\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\r\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\r\n            bool unused = false;\r\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\r\n            // Increase the current maximum to cover our thread id\r\n            int curMax = maxTid.load();\r\n            while (curMax <= tid) {\r\n                maxTid.compare_exchange_strong(curMax, tid+1);\r\n                curMax = maxTid.load();\r\n            }\r\n            tl_tcico.tid = tid;\r\n            return tid;\r\n        }\r\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\r\n        assert(false);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void deregister_thread(const int tid) {\r\n        usedTID[tid].store(false, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    static inline uint64_t getMaxThreads(void) {\r\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    static inline int getTID(void) {\r\n        int tid = tl_tcico.tid;\r\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\r\n        return gThreadRegistry.register_thread_new();\r\n    }\r\n};\r\n\r\n\r\n// Each object tracked by Hazard Eras needs to have tmbase as one of its base classes.\r\nstruct tmbase {\r\n    uint64_t newEra_ {0};        // Filled by tmNew() or tmMalloc()\r\n    uint64_t delEra_ {0};        // Filled by tmDelete() or tmFree()\r\n};\r\n\r\n\r\n// One entry in the log of allocations (not used for retires like in the WF version).\r\n// In case the transactions aborts, we can rollback our allocations, hiding the type information inside the lambda.\r\n// Sure, we could keep everything in std::function, but this uses less memory.\r\nstruct Deletable {\r\n    void* obj {nullptr};         // Pointer to object to be deleted\r\n    void (*reclaim)(void*);      // A wrapper to keep the type of the underlying object\r\n};\r\n\r\n\r\n// This is a specialized implementation of Hazard Eras meant to be used in the OneFile STM.\r\n// Hazard Eras is a lock-free memory reclamation technique described here:\r\n// https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf\r\n// https://dl.acm.org/citation.cfm?id=3087588\r\n//\r\n// We're using OneFileLF::curTx.seq as the global era.\r\nclass HazardErasOF {\r\nprivate:\r\n    static const uint64_t                    NOERA = 0;\r\n    static const int                         CLPAD = 128/sizeof(std::atomic<uint64_t>);\r\n    static const int                         THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    alignas(128) std::atomic<uint64_t>*      he;\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<tmbase*>        retiredList[REGISTRY_MAX_THREADS*CLPAD];\r\n\r\npublic:\r\n    HazardErasOF() {\r\n        he = new std::atomic<uint64_t>[REGISTRY_MAX_THREADS*CLPAD];\r\n        for (unsigned it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            he[it*CLPAD].store(NOERA, std::memory_order_relaxed);\r\n            retiredList[it*CLPAD].reserve(REGISTRY_MAX_THREADS);  // We pre-reserve one object per thread, should be enough to start\r\n        }\r\n    }\r\n\r\n    ~HazardErasOF() {\r\n        // Clear the objects in the retired lists\r\n        for (unsigned it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            for (unsigned iret = 0; iret < retiredList[it*CLPAD].size(); iret++) {\r\n                tmbase* del = retiredList[it*CLPAD][iret];\r\n                std::free(del);\r\n                // No need to call destructor because it was already executed as part of the transaction\r\n            }\r\n        }\r\n        delete[] he;\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void clear(const int tid) {\r\n        he[tid*CLPAD].store(NOERA, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void set(uint64_t trans, const int tid) {\r\n        he[tid*CLPAD].store(trans2seq(trans));\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void addToRetiredList(tmbase* newdel, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(newdel);\r\n    }\r\n\r\n    /**\r\n     * Progress condition: bounded wait-free\r\n     *\r\n     * Attemps to delete the no-longer-in-use objects in the retired list.\r\n     * We need to pass the currEra coming from the seq of the currTx so that\r\n     * the objects from the current transaction don't get deleted.\r\n     *\r\n     * TODO: consider using erase() with std::remove_if()\r\n     */\r\n    void clean(uint64_t curEra, const int tid) {\r\n        if (retiredList[tid*CLPAD].size() < THRESHOLD_R) return;\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            tmbase* del = retiredList[tid*CLPAD][iret];\r\n            if (canDelete(curEra, del)) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                std::free(del);\r\n                // No need to call destructor because it was executed as part of the transaction\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    inline bool canDelete(uint64_t curEra, tmbase* del) {\r\n        // We can't delete objects from the current transaction\r\n        if (del->delEra_ == curEra) return false;\r\n        for (unsigned it = 0; it < ThreadRegistry::getMaxThreads(); it++) {\r\n            const auto era = he[it*CLPAD].load(std::memory_order_acquire);\r\n            if (era == NOERA || era < del->newEra_ || era > del->delEra_) continue;\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n};\r\n\r\n\r\n// We need to split the contents from the methods due to compilation dependencies\r\ntemplate<typename T> struct tmtypebase {\r\n    // Stores the actual value as an atomic\r\n    alignas(16) std::atomic<uint64_t>  val;\r\n    // Lets hope this comes immediately after 'val' in memory mapping, otherwise the DCAS() will fail\r\n    alignas(8)  std::atomic<uint64_t>  seq {1};\r\n};\r\n\r\n\r\n// A single entry in the write-set\r\nstruct WriteSetEntry {\r\n    void*          addr {nullptr};  // Address of value+sequence to change\r\n    uint64_t       val;             // Desired value to change to\r\n    WriteSetEntry* next {nullptr};  // Pointer to next node in the (intrusive) hash map\r\n};\r\n\r\nextern thread_local bool tl_is_read_only;\r\n\r\n\r\n// The write-set is a log of the words modified during the transaction.\r\n// This log is an array with an intrusive hashmap of size HASH_BUCKETS.\r\nstruct WriteSet {\r\n    static const uint64_t MAX_ARRAY_LOOKUP = 30;  // Beyond this, it seems to be faster to use the hashmap\r\n    WriteSetEntry*        buckets[HASH_BUCKETS];  // Intrusive HashMap for fast lookup in large(r) transactions\r\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\r\n    WriteSetEntry         log[TX_MAX_STORES];     // Redo log of stores\r\n\r\n    WriteSet() {\r\n        numStores = 0;\r\n        for (unsigned i = 0; i < HASH_BUCKETS; i++) buckets[i] = &log[TX_MAX_STORES-1];\r\n    }\r\n\r\n    // Each address on a different bucket\r\n    inline uint64_t hash(const void* addr) const {\r\n        return (((uint64_t)addr) >> 3) % HASH_BUCKETS;\r\n    }\r\n\r\n    // Adds a modification to the redo log\r\n    inline void addOrReplace(void* addr, uint64_t val) {\r\n        if (tl_is_read_only) tl_is_read_only = false;\r\n        const uint64_t hashAddr = hash(addr);\r\n        if (numStores < MAX_ARRAY_LOOKUP) {\r\n            // Lookup in array\r\n            for (unsigned int idx = 0; idx < numStores; idx++) {\r\n                if (log[idx].addr == addr) {\r\n                    log[idx].val = val;\r\n                    return;\r\n                }\r\n            }\r\n        } else {\r\n            // Lookup in hashmap\r\n            WriteSetEntry* be = buckets[hash(addr)];\r\n            if (be < &log[numStores]) {\r\n                while (be != nullptr) {\r\n                    if (be->addr == addr) {\r\n                        be->val = val;\r\n                        return;\r\n                    }\r\n                    be = be->next;\r\n                }\r\n            }\r\n        }\r\n        // Add to array\r\n        WriteSetEntry* e = &log[numStores++];\r\n        assert(numStores < TX_MAX_STORES);\r\n        e->addr = addr;\r\n        e->val = val;\r\n        // Add to hashmap\r\n        WriteSetEntry* be = buckets[hashAddr];\r\n        // Clear if entry is from previous tx\r\n        e->next = (be < e && hash(be->addr) == hashAddr) ? be : nullptr;\r\n        buckets[hashAddr] = e;\r\n    }\r\n\r\n    // Does a lookup on the WriteSet for an addr.\r\n    // If the numStores is lower than MAX_ARRAY_LOOKUP, the lookup is done on the log, otherwise, the lookup is done on the hashmap.\r\n    // If it's not in the write-set, return lval.\r\n    inline uint64_t lookupAddr(const void* addr, uint64_t lval) {\r\n        if (numStores < MAX_ARRAY_LOOKUP) {\r\n            // Lookup in array\r\n            for (unsigned int idx = 0; idx < numStores; idx++) {\r\n                if (log[idx].addr == addr) return log[idx].val;\r\n            }\r\n        } else {\r\n            // Lookup in hashmap\r\n            const uint64_t hashAddr = hash(addr);\r\n            WriteSetEntry* be = buckets[hashAddr];\r\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\r\n                while (be != nullptr) {\r\n                    if (be->addr == addr) return be->val;\r\n                    be = be->next;\r\n                }\r\n            }\r\n        }\r\n        return lval;\r\n    }\r\n\r\n    // Assignment operator, used when making a copy of a WriteSet to help another thread\r\n    WriteSet& operator = (const WriteSet &other) {\r\n        numStores = other.numStores;\r\n        for (uint64_t i = 0; i < numStores; i++) log[i] = other.log[i];\r\n        return *this;\r\n    }\r\n\r\n    // Applies all entries in the log as DCASes.\r\n    // Seq must match for DCAS to succeed. This method is on the \"hot-path\".\r\n    inline void apply(uint64_t seq, const int tid) {\r\n        for (uint64_t i = 0; i < numStores; i++) {\r\n            // Use an heuristic to give each thread 8 consecutive DCAS to apply\r\n            WriteSetEntry& e = log[(tid*8 + i) % numStores];\r\n            tmtypebase<uint64_t>* tmte = (tmtypebase<uint64_t>*)e.addr;\r\n            uint64_t lval = tmte->val.load(std::memory_order_acquire);\r\n            uint64_t lseq = tmte->seq.load(std::memory_order_acquire);\r\n            if (lseq < seq) DCAS((uint64_t*)e.addr, lval, lseq, e.val, seq);\r\n        }\r\n    }\r\n};\r\n\r\n\r\n// Forward declaration\r\nstruct OpData;\r\n// This is used by addOrReplace() to know which OpData instance to use for the current transaction\r\nextern thread_local OpData* tl_opdata;\r\n\r\n\r\n// Its purpose is to hold thread-local data\r\nstruct OpData {\r\n    uint64_t              curTx {0};                   // Used during a transaction to keep the value of currTx read in beginTx() (owner thread only)\r\n    std::atomic<uint64_t> request {0};                 // Can be moved to CLOSED by other threads, using a CAS\r\n    uint64_t              nestedTrans {0};             // Thread-local: Number of nested transactions\r\n    uint64_t              numRetires {0};              // Number of calls to retire() in this transaction (owner thread only)\r\n    tmbase*               rlog[TX_MAX_RETIRES];        // List of retired objects during the transaction (owner thread only)\r\n    uint64_t              numAllocs {0};               // Number of calls to tmNew() in this transaction (owner thread only)\r\n    Deletable             alog[TX_MAX_ALLOCS];         // List of newly allocated objects during the transaction (owner thread only)\r\n};\r\n\r\n\r\n// Used to identify aborted transactions\r\nstruct AbortedTx {};\r\nstatic constexpr AbortedTx AbortedTxException {};\r\n\r\nclass OneFileLF;\r\nextern OneFileLF gOFLF;\r\n\r\n\r\n/**\r\n * <h1> One-File STM (Lock-Free) </h1>\r\n *\r\n * OneFile is a Software Transacional Memory with lock-free progress, meant to\r\n * implement lock-free data structures. It has integrated lock-free memory\r\n * reclamation using Hazard Eras: https://dl.acm.org/citation.cfm?id=3087588\r\n *\r\n * OneFile is a word-based STM and it uses double-compare-and-swap (DCAS).\r\n *\r\n * Right now it has several limitations, some will be fixed in the future, some may be hard limitations of this approach:\r\n * - We can't have stack allocated tmtype<> variables. For example, we can't created inside a transaction \"tmtpye<uint64_t> tmp = a;\",\r\n *   it will give weird errors because of stack allocation.\r\n * - We need DCAS but it can be emulated with LL/SC or even with single-word CAS\r\n *   if we do redirection to a (lock-free) pool with SeqPtrs;\r\n */\r\nclass OneFileLF {\r\nprivate:\r\n    static const bool                    debug = false;\r\n    HazardErasOF                         he {};\r\n    OpData                              *opData;\r\n\r\npublic:\r\n    std::atomic<uint64_t>                pad0[16];  // two cache lines of padding, before and after curTx\r\n    std::atomic<uint64_t>                curTx {seqidx2trans(1,0)};\r\n    std::atomic<uint64_t>                pad1[15];\r\n    WriteSet                            *writeSets;                    // Two write-sets for each thread\r\n\r\n    OneFileLF() {\r\n        opData = new OpData[REGISTRY_MAX_THREADS];\r\n        writeSets = new WriteSet[REGISTRY_MAX_THREADS];\r\n    }\r\n\r\n    ~OneFileLF() {\r\n        delete[] opData;\r\n        delete[] writeSets;\r\n    }\r\n\r\n    static std::string className() { return \"OneFileSTM-LF\"; }\r\n\r\n    // Progress Condition: lock-free\r\n    // The while-loop retarts only if there was at least one other thread completing a transaction\r\n    void beginTx(OpData& myopd, const int tid) {\r\n        tl_is_read_only = true;\r\n        // Clear the logs of the previous transaction\r\n        deleteAllocsFromLog(myopd);\r\n        myopd.numRetires = 0;\r\n        while (true) {\r\n            myopd.curTx = curTx.load(std::memory_order_acquire);\r\n            helpApply(myopd.curTx, tid);\r\n            // Reset the write-set after (possibly) helping another transaction complete\r\n            writeSets[tid].numStores = 0;\r\n            // Use HE to protect the objects we're going to access during the simulation\r\n            he.set(myopd.curTx, tid);\r\n            // Start over if there is already a new transaction\r\n            if (myopd.curTx == curTx.load(std::memory_order_acquire)) return;\r\n        }\r\n    }\r\n\r\n    // Progress condition: wait-free population-oblivious\r\n    // Attempts to publish our write-set (commit the transaction) and then applies the write-set.\r\n    // Returns true if my transaction was committed.\r\n    inline bool commitTx(OpData& myopd, const int tid) {\r\n        // If it's a read-only transaction, then commit immediately\r\n        if (writeSets[tid].numStores == 0 && myopd.numRetires == 0) return true;\r\n        // Give up if the currTx has changed sinced our transaction started\r\n        if (myopd.curTx != curTx.load(std::memory_order_acquire)) return false;\r\n        // Move our request to OPEN, using the sequence of the previous transaction +1\r\n        uint64_t seq = trans2seq(myopd.curTx);\r\n        uint64_t newTx = seqidx2trans(seq+1,tid);\r\n        myopd.request.store(newTx, std::memory_order_release);\r\n        // Attempt to CAS currTx to our OpDesc instance (tid) incrementing the seq in it\r\n        uint64_t lcurrTx = myopd.curTx;\r\n        if (debug) printf(\"tid=%i  attempting CAS on curTx from (%ld,%ld) to (%ld,%ld)\\n\", tid, trans2seq(lcurrTx), trans2idx(lcurrTx), seq+1, (uint64_t)tid);\r\n        if (!curTx.compare_exchange_strong(lcurrTx, newTx)) return false;\r\n        // Execute each store in the write-set using DCAS() and close the request\r\n        helpApply(newTx, tid);\r\n        retireRetiresFromLog(myopd, tid);\r\n        myopd.numAllocs = 0;\r\n        if (debug) printf(\"Committed transaction (%ld,%ld) with %ld stores\\n\", seq+1, (uint64_t)tid, writeSets[tid].numStores);\r\n        return true;\r\n    }\r\n\r\n    // Same as beginTx/endTx transaction, but with lambdas, and it handles AbortedTx exceptions\r\n    template<typename R, typename F> R transaction(F&& func) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        OpData& myopd = opData[tid];\r\n        if (myopd.nestedTrans > 0) return func();\r\n        ++myopd.nestedTrans;\r\n        tl_opdata = &myopd;\r\n        R retval {};\r\n        while (true) {\r\n            beginTx(myopd, tid);\r\n            try {\r\n                retval = func();\r\n            } catch (AbortedTx&) {\r\n                continue;\r\n            }\r\n            if (commitTx(myopd, tid)) break;\r\n        }\r\n        tl_opdata = nullptr;\r\n        --myopd.nestedTrans;\r\n        he.clear(tid);\r\n        return retval;\r\n    }\r\n\r\n    // Same as above, but returns void\r\n    template<typename F> void transaction(F&& func) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        OpData& myopd = opData[tid];\r\n        if (myopd.nestedTrans > 0) {\r\n            func();\r\n            return;\r\n        }\r\n        ++myopd.nestedTrans;\r\n        tl_opdata = &myopd;\r\n        while (true) {\r\n            beginTx(myopd, tid);\r\n            try {\r\n                func();\r\n            } catch (AbortedTx&) {\r\n                continue;\r\n            }\r\n            if (commitTx(myopd, tid)) break;\r\n        }\r\n        tl_opdata = nullptr;\r\n        --myopd.nestedTrans;\r\n        he.clear(tid);\r\n    }\r\n\r\n    // It's silly that these have to be static, but we need them for the (SPS) benchmarks due to templatization\r\n    template<typename R, typename F> static R updateTx(F&& func) { return gOFLF.transaction<R>(func); }\r\n    template<typename R, typename F> static R readTx(F&& func) { return gOFLF.transaction<R>(func); }\r\n    template<typename F> static void updateTx(F&& func) { gOFLF.transaction(func); }\r\n    template<typename F> static void readTx(F&& func) { gOFLF.transaction(func); }\r\n\r\n    // When inside a transaction, the user can't call \"new\" directly because if\r\n    // the transaction fails, it would leak the memory of these allocations.\r\n    // Instead, we provide an allocator that keeps pointers to these objects\r\n    // in a log, and in the event of a failed commit of the transaction, it will\r\n    // delete the objects so that there are no leaks.\r\n    // TODO: Add static_assert to check if T is of tmbase\r\n    template <typename T, typename... Args> static T* tmNew(Args&&... args) {\r\n        T* ptr = (T*)std::malloc(sizeof(T));\r\n        new (ptr) T(std::forward<Args>(args)...);  // new placement\r\n        ptr->newEra_ = trans2seq(gOFLF.curTx.load(std::memory_order_acquire));\r\n        OpData* myopd = tl_opdata;\r\n        if (myopd != nullptr) {\r\n            assert(myopd->numAllocs != TX_MAX_ALLOCS);\r\n            Deletable& del = myopd->alog[myopd->numAllocs++];\r\n            del.obj = ptr;\r\n            // This func ptr to a lambda gives us a way to call the destructor\r\n            // when a transaction aborts.\r\n            del.reclaim = [](void* obj) { static_cast<T*>(obj)->~T(); std::free(obj); };\r\n        }\r\n        return ptr;\r\n    }\r\n\r\n    // The user can not directly delete objects in the transaction because the\r\n    // transaction may fail and needs to be retried and other threads may be\r\n    // using those objects.\r\n    // Instead, it has to call retire() for the objects it intends to delete.\r\n    // The retire() puts the objects in the rlog, and only when the transaction\r\n    // commits, the objects are put in the Hazard Eras retired list.\r\n    // The del.delEra is filled in retireRetiresFromLog().\r\n    // TODO: Add static_assert to check if T is of tmbase\r\n    template<typename T> static void tmDelete(T* obj) {\r\n        if (obj == nullptr) return;\r\n        obj->~T(); // Execute destructor as part of the current transaction\r\n        OpData* myopd = tl_opdata;\r\n        if (myopd == nullptr) {\r\n            std::free(obj);  // Outside a transaction, just delete the object\r\n            return;\r\n        }\r\n        assert(myopd->numRetires != TX_MAX_RETIRES);\r\n        myopd->rlog[myopd->numRetires++] = obj;\r\n    }\r\n\r\n    // We snap a tmbase at the beginning of the allocation\r\n    static void* tmMalloc(size_t size) {\r\n        uint8_t* ptr = (uint8_t*)std::malloc(size+sizeof(tmbase));\r\n        // We must reset the contents to zero to guarantee that if any tmtypes are allocated inside, their 'seq' will be zero\r\n        std::memset(ptr+sizeof(tmbase), 0, size);\r\n        ((tmbase*)ptr)->newEra_ = trans2seq(gOFLF.curTx.load(std::memory_order_acquire));\r\n        OpData* myopd = tl_opdata;\r\n        if (myopd != nullptr) {\r\n            assert(myopd->numAllocs != TX_MAX_ALLOCS);\r\n            Deletable& del = myopd->alog[myopd->numAllocs++];\r\n            del.obj = ptr;\r\n            del.reclaim = [](void* obj) { std::free(obj); };\r\n        }\r\n        return ptr + sizeof(tmbase);\r\n    }\r\n\r\n    // We assume there is a tmbase allocated in the beginning of the allocation\r\n    static void tmFree(void* obj) {\r\n        if (obj == nullptr) return;\r\n        OpData* myopd = tl_opdata;\r\n        uint8_t* ptr = (uint8_t*)obj - sizeof(tmbase);\r\n        if (myopd == nullptr) {\r\n            std::free(ptr);  // Outside a transaction, just free the object\r\n            return;\r\n        }\r\n        assert(myopd->numRetires != TX_MAX_RETIRES);\r\n        myopd->rlog[myopd->numRetires++] = (tmbase*)ptr;\r\n    }\r\n\r\nprivate:\r\n    // Progress condition: wait-free population oblivious\r\n    void helpApply(uint64_t lcurTx, const uint64_t tid) {\r\n        const uint64_t idx = trans2idx(lcurTx);\r\n        const uint64_t seq = trans2seq(lcurTx);\r\n        OpData& opd = opData[idx];\r\n        // Nothing to apply unless the request matches the curTx\r\n        if (lcurTx != opd.request.load(std::memory_order_acquire)) return;\r\n        if (idx != tid) {\r\n            // Make a copy of the write-set and check if it is consistent\r\n            writeSets[tid] = writeSets[idx];\r\n            // Use HE to protect the objects the transaction touches\r\n            he.set(lcurTx, tid);\r\n            if (lcurTx != curTx.load()) return;\r\n            // The published era is now protecting all objects alive in the transaction lcurTx\r\n            if (lcurTx != opd.request.load(std::memory_order_acquire)) return;\r\n        }\r\n        if (debug) printf(\"Applying %ld stores in write-set\\n\", writeSets[tid].numStores);\r\n        writeSets[tid].apply(seq, tid);\r\n        const uint64_t newReq = seqidx2trans(seq+1,idx);\r\n        if (idx == tid) {\r\n            opd.request.store(newReq, std::memory_order_release);\r\n        } else {\r\n            if (opd.request.load(std::memory_order_acquire) == lcurTx) {\r\n                opd.request.compare_exchange_strong(lcurTx, newReq);\r\n            }\r\n        }\r\n    }\r\n\r\n    // This is called when the transaction fails, to undo all the allocations done during the transaction\r\n     void deleteAllocsFromLog(OpData& myopd) {\r\n        for (unsigned i = 0; i < myopd.numAllocs; i++) {\r\n            myopd.alog[i].reclaim(myopd.alog[i].obj);\r\n        }\r\n        myopd.numAllocs = 0;\r\n    }\r\n\r\n    // My transaction was successful, it's my duty to cleanup any retired objects.\r\n    // This is called by the owner thread when the transaction succeeds, to pass\r\n    // the retired objects to Hazard Eras. We can't delete the objects\r\n    // immediately because there might be other threads trying to apply our log\r\n    // which may (or may not) contain addresses inside the objects in this list.\r\n    void retireRetiresFromLog(OpData& myopd, const int tid) {\r\n        uint64_t lseq = trans2seq(curTx.load(std::memory_order_acquire));\r\n        // First, add all the objects to the list of retired/zombies\r\n        for (unsigned i = 0; i < myopd.numRetires; i++) {\r\n            myopd.rlog[i]->delEra_ = lseq;\r\n            he.addToRetiredList(myopd.rlog[i], tid);\r\n        }\r\n        // Second, start a cleaning phase, scanning to see which objects can be removed\r\n        he.clean(lseq, tid);\r\n        myopd.numRetires = 0;\r\n    }\r\n};\r\n\r\n\r\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\r\ntemplate<typename T> struct tmtype : tmtypebase<T> {\r\n\r\n    tmtype() { }\r\n\r\n    tmtype(T initVal) { isolated_store(initVal); }\r\n\r\n    // Casting operator\r\n    operator T() { return pload(); }\r\n\r\n    // Prefix increment operator: ++x\r\n    void operator++ () { pstore(pload()+1); }\r\n    // Prefix decrement operator: --x\r\n    void operator-- () { pstore(pload()-1); }\r\n    void operator++ (int) { pstore(pload()+1); }\r\n    void operator-- (int) { pstore(pload()-1); }\r\n\r\n    // Equals operator: first downcast to T and then compare\r\n    bool operator == (const T& otherval) const { return pload() == otherval; }\r\n\r\n    // Difference operator: first downcast to T and then compare\r\n    bool operator != (const T& otherval) const { return pload() != otherval; }\r\n\r\n    // Relational operators\r\n    bool operator < (const T& rhs) { return pload() < rhs; }\r\n    bool operator > (const T& rhs) { return pload() > rhs; }\r\n    bool operator <= (const T& rhs) { return pload() <= rhs; }\r\n    bool operator >= (const T& rhs) { return pload() >= rhs; }\r\n\r\n    // Operator arrow ->\r\n    T operator->() { return pload(); }\r\n\r\n    // Copy constructor\r\n    tmtype<T>(const tmtype<T>& other) { pstore(other.pload()); }\r\n\r\n    // Assignment operator from an tmtype\r\n    tmtype<T>& operator=(const tmtype<T>& other) {\r\n        pstore(other.pload());\r\n        return *this;\r\n    }\r\n\r\n    // Assignment operator from a value\r\n    tmtype<T>& operator=(T value) {\r\n        pstore(value);\r\n        return *this;\r\n    }\r\n\r\n    // Operator &\r\n    T* operator&() {\r\n        return (T*)this;\r\n    }\r\n\r\n    // Meant to be called when know we're the only ones touching\r\n    // these contents, for example, in the constructor of an object, before\r\n    // making the object visible to other threads.\r\n    inline void isolated_store(T newVal) {\r\n        tmtypebase<T>::val.store((uint64_t)newVal, std::memory_order_relaxed);\r\n    }\r\n\r\n    // We don't need to check currTx here because we're not de-referencing\r\n    // the val. It's only after a load() that the val may be de-referenced\r\n    // (in user code), therefore we do the check on load() only.\r\n    inline void pstore(T newVal) {\r\n        OpData* const myopd = tl_opdata;\r\n        if (myopd == nullptr) { // Looks like we're outside a transaction\r\n            tmtypebase<T>::val.store((uint64_t)newVal, std::memory_order_relaxed);\r\n        } else {\r\n            gOFLF.writeSets[tl_tcico.tid].addOrReplace(this, (uint64_t)newVal);\r\n        }\r\n    }\r\n\r\n    // We have to check if there is a new ongoing transaction and if so, abort\r\n    // this execution immediately for two reasons:\r\n    // 1. Memory Reclamation: the val we're returning may be a pointer to an\r\n    // object that has since been retired and deleted, therefore we can't allow\r\n    // user code to de-reference it;\r\n    // 2. Invariant Conservation: The val we're reading may be from a newer\r\n    // transaction, which implies that it may break an invariant in the user code.\r\n    // See examples of invariant breaking in this post:\r\n    // http://concurrencyfreaks.com/2013/11/stampedlocktryoptimisticread-and.html\r\n    inline T pload() const {\r\n        T lval = (T)tmtypebase<T>::val.load(std::memory_order_acquire);\r\n        if (tl_opdata == nullptr) return lval;\r\n        uint64_t lseq = tmtypebase<T>::seq.load(std::memory_order_acquire);\r\n        if (lseq > trans2seq(tl_opdata->curTx)) throw AbortedTxException;\r\n        if (tl_is_read_only) return lval;\r\n        return (T)gOFLF.writeSets[tl_tcico.tid].lookupAddr(this, (uint64_t)lval);\r\n    }\r\n};\r\n\r\n\r\n//\r\n// Wrapper methods to the global TM instance. The user should use these:\r\n//\r\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gOFLF.transaction<R>(func); }\r\ntemplate<typename R, typename F> static R readTx(F&& func) { return gOFLF.transaction<R>(func); }\r\ntemplate<typename F> static void updateTx(F&& func) { gOFLF.transaction(func); }\r\ntemplate<typename F> static void readTx(F&& func) { gOFLF.transaction(func); }\r\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return OneFileLF::tmNew<T>(args...); }\r\ntemplate<typename T> void tmDelete(T* obj) { OneFileLF::tmDelete<T>(obj); }\r\ninline void* tmMalloc(size_t size) { return OneFileLF::tmMalloc(size); }\r\ninline void tmFree(void* obj) { OneFileLF::tmFree(obj); }\r\n\r\n\r\n//\r\n// Place these in a .cpp if you include this header from different files (compilation units)\r\n//\r\nOneFileLF gOFLF {};\r\nthread_local OpData* tl_opdata {nullptr};\r\n// Global/singleton to hold all the thread registry functionality\r\nThreadRegistry gThreadRegistry {};\r\n// During a transaction, this is true up until the first store()\r\nthread_local bool tl_is_read_only {false};\r\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\r\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\r\nthread_local ThreadCheckInCheckOut tl_tcico {};\r\n// Helper function for thread de-registration\r\nvoid thread_registry_deregister_thread(const int tid) {\r\n    gThreadRegistry.deregister_thread(tid);\r\n}\r\n\r\n\r\n} // ... and all this with less than 800 lines of code  :)\r\n\r\n#endif /* _ONE_FILE_LOCK_FREE_TRANSACTIONAL_MEMORY_WITH_HAZARD_ERAS_H_ */\r\n"
  },
  {
    "path": "stms/OneFileWF.hpp",
    "content": "/*\r\n * Copyright 2017-2019\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _ONE_FILE_WAIT_FREE_TRANSACTIONAL_MEMORY_WITH_HAZARD_ERAS_H_\r\n#define _ONE_FILE_WAIT_FREE_TRANSACTIONAL_MEMORY_WITH_HAZARD_ERAS_H_\r\n\r\n#include <atomic>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <vector>\r\n#include <functional>\r\n#include <cstring>\r\n\r\n// Please keep this file in sync (as much as possible) with ptms/POneFileWF.hpp\r\n\r\nnamespace ofwf {\r\n\r\n//\r\n// User configurable variables.\r\n// Feel free to change these if you need larger transactions, more allocations per transacation, or more threads.\r\n//\r\n\r\n// Maximum number of registered threads that can execute transactions\r\nstatic const int REGISTRY_MAX_THREADS = 128;\r\n// Maximum number of stores in the WriteSet per transaction\r\nstatic const uint64_t TX_MAX_STORES = 40*1024;\r\n// Number of buckets in the hashmap of the WriteSet.\r\nstatic const uint64_t HASH_BUCKETS = 1024;\r\n// Maximum number of allocations in one transaction\r\nstatic const uint64_t TX_MAX_ALLOCS = 10*1024;\r\n// Maximum number of deallocations in one transaction\r\nstatic const uint64_t TX_MAX_RETIRES = 10*1024;\r\n\r\n\r\n\r\n// DCAS / CAS2 macro\r\n#define DCAS(ptr, o1, o2, n1, n2)                               \\\r\n({                                                              \\\r\n    char __ret;                                                 \\\r\n    __typeof__(o2) __junk;                                      \\\r\n    __typeof__(*(ptr)) __old1 = (o1);                           \\\r\n    __typeof__(o2) __old2 = (o2);                               \\\r\n    __typeof__(*(ptr)) __new1 = (n1);                           \\\r\n    __typeof__(o2) __new2 = (n2);                               \\\r\n    asm volatile(\"lock cmpxchg16b %2;setz %1\"                   \\\r\n                   : \"=d\"(__junk), \"=a\"(__ret), \"+m\" (*ptr)     \\\r\n                   : \"b\"(__new1), \"c\"(__new2),                  \\\r\n                     \"a\"(__old1), \"d\"(__old2));                 \\\r\n    __ret; })\r\n\r\n\r\n// Functions to convert between a transaction identifier (uint64_t) and a pair of {sequence,index}\r\nstatic inline uint64_t seqidx2trans(uint64_t seq, uint64_t idx) {\r\n    return (seq << 10) | idx;\r\n}\r\nstatic inline uint64_t trans2seq(uint64_t trans) {\r\n    return trans >> 10;\r\n}\r\nstatic inline uint64_t trans2idx(uint64_t trans) {\r\n    return trans & 0x3FF; // 10 bits\r\n}\r\n\r\n\r\n//\r\n// Thread Registry stuff\r\n//\r\nextern void thread_registry_deregister_thread(const int tid);\r\n\r\n// An helper class to do the checkin and checkout of the thread registry\r\nstruct ThreadCheckInCheckOut {\r\n    static const int NOT_ASSIGNED = -1;\r\n    int tid { NOT_ASSIGNED };\r\n    ~ThreadCheckInCheckOut() {\r\n        if (tid == NOT_ASSIGNED) return;\r\n        thread_registry_deregister_thread(tid);\r\n    }\r\n};\r\n\r\nextern thread_local ThreadCheckInCheckOut tl_tcico;\r\n\r\n// Forward declaration of global/singleton instance\r\nclass ThreadRegistry;\r\nextern ThreadRegistry gThreadRegistry;\r\n\r\n/*\r\n * <h1> Registry for threads </h1>\r\n *\r\n * This is singleton type class that allows assignement of a unique id to each thread.\r\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\r\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\r\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\r\n * corresponding slot to be used by a later thread.\r\n */\r\nclass ThreadRegistry {\r\nprivate:\r\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\r\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\r\n\r\npublic:\r\n    ThreadRegistry() {\r\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            usedTID[it].store(false, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    int register_thread_new(void) {\r\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\r\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\r\n            bool unused = false;\r\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\r\n            // Increase the current maximum to cover our thread id\r\n            int curMax = maxTid.load();\r\n            while (curMax <= tid) {\r\n                maxTid.compare_exchange_strong(curMax, tid+1);\r\n                curMax = maxTid.load();\r\n            }\r\n            tl_tcico.tid = tid;\r\n            return tid;\r\n        }\r\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\r\n        assert(false);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void deregister_thread(const int tid) {\r\n        usedTID[tid].store(false, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    static inline uint64_t getMaxThreads(void) {\r\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    static inline int getTID(void) {\r\n        int tid = tl_tcico.tid;\r\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\r\n        return gThreadRegistry.register_thread_new();\r\n    }\r\n};\r\n\r\n\r\n// Each object tracked by Hazard Eras needs to have tmbase as one of its base classes.\r\nstruct tmbase {\r\n    uint64_t newEra_ {0};        // Filled by tmNew() or tmMalloc()\r\n    uint64_t delEra_ {0};        // Filled by tmDelete() or tmFree()\r\n};\r\n\r\n\r\n// One entry in the log of allocations (not used for retires like in the WF version).\r\n// In case the transactions aborts, we can rollback our allocations, hiding the type information inside the lambda.\r\n// Sure, we could keep everything in std::function, but this uses less memory.\r\nstruct Deletable {\r\n    void* obj {nullptr};         // Pointer to object to be deleted\r\n    void (*reclaim)(void*);      // A wrapper to keep the type of the underlying object\r\n};\r\n\r\n\r\n// A wrapper to std::function so that we can track it with Hazard Eras\r\nstruct TransFunc : public tmbase {\r\n    std::function<uint64_t()> func;\r\n    template<typename F> TransFunc(F&& f) : func{f} { }\r\n};\r\n\r\n\r\n// This is a specialized implementation of Hazard Eras meant to be used in the OneFile STM.\r\n// Hazard Eras is a lock-free memory reclamation technique described here:\r\n// https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/hazarderas-2017.pdf\r\n// https://dl.acm.org/citation.cfm?id=3087588\r\n//\r\n// We're using OF::curTx.seq as the global era.\r\n//\r\n// This implementation is different from the lock-free OneFile STM because we need\r\n// to track the lifetime of the std::function objects where the lambdas are put.\r\nclass HazardErasOF {\r\nprivate:\r\n    static const uint64_t                    NOERA = 0;\r\n    static const int                         CLPAD = 128/sizeof(std::atomic<uint64_t>);\r\n    static const int                         THRESHOLD_R = 0; // This is named 'R' in the HP paper\r\n    const unsigned int                       maxThreads;\r\n    alignas(128) std::atomic<uint64_t>*      he;\r\n    // It's not nice that we have a lot of empty vectors, but we need padding to avoid false sharing\r\n    alignas(128) std::vector<tmbase*>        retiredList[REGISTRY_MAX_THREADS*CLPAD];\r\n    alignas(128) std::vector<TransFunc*>   retiredListTx[REGISTRY_MAX_THREADS*CLPAD];\r\n\r\npublic:\r\n    HazardErasOF(unsigned int maxThreads=REGISTRY_MAX_THREADS) : maxThreads{maxThreads} {\r\n        he = new std::atomic<uint64_t>[REGISTRY_MAX_THREADS*CLPAD];\r\n        for (unsigned it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            he[it*CLPAD].store(NOERA, std::memory_order_relaxed);\r\n            retiredList[it*CLPAD].reserve(REGISTRY_MAX_THREADS);  // We pre-reserve one object per thread, should be enough to start\r\n            retiredListTx[it*CLPAD].reserve(REGISTRY_MAX_THREADS);\r\n        }\r\n    }\r\n\r\n    ~HazardErasOF() {\r\n        // Clear the objects in the retired lists\r\n        for (unsigned it = 0; it < maxThreads; it++) {\r\n            for (unsigned iret = 0; iret < retiredList[it*CLPAD].size(); iret++) {\r\n                tmbase* del = retiredList[it*CLPAD][iret];\r\n                std::free(del);\r\n                // No need to call destructor because it was already executed as part of the transaction\r\n            }\r\n            for (unsigned iret = 0; iret < retiredListTx[it*CLPAD].size(); iret++) {\r\n                TransFunc* tx = retiredListTx[it*CLPAD][iret];\r\n                delete tx;\r\n            }\r\n        }\r\n        delete[] he;\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void clear(const int tid) {\r\n        he[tid*CLPAD].store(NOERA, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void set(uint64_t trans, const int tid) {\r\n        he[tid*CLPAD].store(trans2seq(trans));\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void addToRetiredList(tmbase* newdel, const int tid) {\r\n        retiredList[tid*CLPAD].push_back(newdel);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void addToRetiredListTx(TransFunc* tx, const int tid) {\r\n        retiredListTx[tid*CLPAD].push_back(tx);\r\n    }\r\n\r\n    /**\r\n     * Progress condition: bounded wait-free\r\n     *\r\n     * Attemps to delete the no-longer-in-use objects in the retired list.\r\n     * We need to pass the currEra coming from the seq of the currTx so that\r\n     * the objects from the current transaction don't get deleted.\r\n     *\r\n     * TODO: consider using erase() with std::remove_if()\r\n     */\r\n    void clean(uint64_t curEra, const int tid) {\r\n        if (retiredList[tid*CLPAD].size() < THRESHOLD_R) return;\r\n        for (unsigned iret = 0; iret < retiredList[tid*CLPAD].size();) {\r\n            tmbase* del = retiredList[tid*CLPAD][iret];\r\n            if (canDelete(curEra, del)) {\r\n                retiredList[tid*CLPAD].erase(retiredList[tid*CLPAD].begin() + iret);\r\n                std::free(del);\r\n                // No need to call destructor because it was executed as part of the transaction\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n        for (unsigned iret = 0; iret < retiredListTx[tid*CLPAD].size();) {\r\n            TransFunc* tx = retiredListTx[tid*CLPAD][iret];\r\n            if (canDelete(curEra, tx)) {\r\n                retiredListTx[tid*CLPAD].erase(retiredListTx[tid*CLPAD].begin() + iret);\r\n                delete tx;\r\n                continue;\r\n            }\r\n            iret++;\r\n        }\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    inline bool canDelete(uint64_t curEra, tmbase* del) {\r\n        // We can't delete objects from the current transaction\r\n        if (del->delEra_ == curEra) return false;\r\n        for (unsigned it = 0; it < ThreadRegistry::getMaxThreads(); it++) {\r\n            const auto era = he[it*CLPAD].load(std::memory_order_acquire);\r\n            if (era == NOERA || era < del->newEra_ || era > del->delEra_) continue;\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n};\r\n\r\n\r\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\r\ntemplate<typename T> struct tmtype {\r\n    // Stores the actual value as an atomic\r\n    alignas(16) std::atomic<uint64_t>  val;\r\n    // Lets hope this comes immediately after 'val' in memory mapping, otherwise the DCAS() will fail\r\n    alignas(8)  std::atomic<uint64_t>  seq {1};\r\n\r\n    tmtype() { }\r\n\r\n    tmtype(T initVal) { isolated_store(initVal); }\r\n\r\n    // Casting operator\r\n    operator T() { return pload(); }\r\n\r\n    // Prefix increment operator: ++x\r\n    void operator++ () { pstore(pload()+1); }\r\n    // Prefix decrement operator: --x\r\n    void operator-- () { pstore(pload()-1); }\r\n    void operator++ (int) { pstore(pload()+1); }\r\n    void operator-- (int) { pstore(pload()-1); }\r\n\r\n    // Equals operator: first downcast to T and then compare\r\n    bool operator == (const T& otherval) const { return pload() == otherval; }\r\n\r\n    // Difference operator: first downcast to T and then compare\r\n    bool operator != (const T& otherval) const { return pload() != otherval; }\r\n\r\n    // Relational operators\r\n    bool operator < (const T& rhs) { return pload() < rhs; }\r\n    bool operator > (const T& rhs) { return pload() > rhs; }\r\n    bool operator <= (const T& rhs) { return pload() <= rhs; }\r\n    bool operator >= (const T& rhs) { return pload() >= rhs; }\r\n\r\n    // Operator arrow ->\r\n    T operator->() { return pload(); }\r\n\r\n    // Copy constructor\r\n    tmtype<T>(const tmtype<T>& other) { pstore(other.pload()); }\r\n\r\n    // Assignment operator from an tmtype\r\n    tmtype<T>& operator=(const tmtype<T>& other) {\r\n        pstore(other.pload());\r\n        return *this;\r\n    }\r\n\r\n    // Assignment operator from a value\r\n    tmtype<T>& operator=(T value) {\r\n        pstore(value);\r\n        return *this;\r\n    }\r\n\r\n    // Operator &\r\n    T* operator&() {\r\n        return (T*)this;\r\n    }\r\n\r\n    // Meant to be called when know we're the only ones touching\r\n    // these contents, for example, in the constructor of an object, before\r\n    // making the object visible to other threads.\r\n    inline void isolated_store(T newVal) {\r\n        val.store((uint64_t)newVal, std::memory_order_relaxed);\r\n    }\r\n\r\n    // Used only internally to initialize the operations[] array\r\n    inline void operationsInit() {\r\n        val.store((uint64_t)nullptr, std::memory_order_relaxed);\r\n        seq.store(0, std::memory_order_relaxed);\r\n    }\r\n\r\n    // Used only internally to initialize the results[] array\r\n    inline void resultsInit() {\r\n        val.store(0, std::memory_order_relaxed);\r\n        seq.store(1, std::memory_order_relaxed);\r\n    }\r\n\r\n    // Used only internally by updateTx() to determine if the request is opened or not\r\n    inline uint64_t getSeq() const {\r\n        return seq.load(std::memory_order_acquire);\r\n    }\r\n\r\n    // Used only internally by updateTx()\r\n    inline void rawStore(T& newVal, uint64_t lseq) {\r\n        val.store((uint64_t)newVal, std::memory_order_relaxed);\r\n        seq.store(lseq, std::memory_order_release);\r\n    }\r\n\r\n    // Methods that are defined later because they have compilation dependencies on gOFWF\r\n    inline T pload() const;\r\n    inline bool rawLoad(T& keepVal, uint64_t& keepSeq);\r\n    inline void pstore(T newVal);\r\n};\r\n\r\n\r\n// A single entry in the write-set\r\nstruct WriteSetEntry {\r\n    void*          addr {nullptr};  // Address of value+sequence to change\r\n    uint64_t       val;             // Desired value to change to\r\n    WriteSetEntry* next {nullptr};  // Pointer to next node in the (intrusive) hash map\r\n};\r\n\r\nextern thread_local bool tl_is_read_only;\r\n\r\n\r\n// The write-set is a log of the words modified during the transaction.\r\n// This log is an array with an intrusive hashmap of size HASH_BUCKETS.\r\nstruct WriteSet {\r\n    static const uint64_t MAX_ARRAY_LOOKUP = 30;  // Beyond this, it seems to be faster to use the hashmap\r\n    WriteSetEntry*        buckets[HASH_BUCKETS];  // Intrusive HashMap for fast lookup in large(r) transactions\r\n    uint64_t              numStores {0};          // Number of stores in the writeSet for the current transaction\r\n    WriteSetEntry         log[TX_MAX_STORES];     // Redo log of stores\r\n\r\n    WriteSet() {\r\n        numStores = 0;\r\n        for (unsigned i = 0; i < HASH_BUCKETS; i++) buckets[i] = &log[TX_MAX_STORES-1];\r\n    }\r\n\r\n    // Each address on a different bucket\r\n    inline uint64_t hash(const void* addr) const {\r\n        return (((uint64_t)addr) >> 3) % HASH_BUCKETS;\r\n    }\r\n\r\n    // Adds a modification to the redo log\r\n    inline void addOrReplace(void* addr, uint64_t val) {\r\n        if (tl_is_read_only) tl_is_read_only = false;\r\n        const uint64_t hashAddr = hash(addr);\r\n        if (numStores < MAX_ARRAY_LOOKUP) {\r\n            // Lookup in array\r\n            for (unsigned int idx = 0; idx < numStores; idx++) {\r\n                if (log[idx].addr == addr) {\r\n                    log[idx].val = val;\r\n                    return;\r\n                }\r\n            }\r\n        } else {\r\n            // Lookup in hashmap\r\n            WriteSetEntry* be = buckets[hashAddr];\r\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\r\n                while (be != nullptr) {\r\n                    if (be->addr == addr) {\r\n                        be->val = val;\r\n                        return;\r\n                    }\r\n                    be = be->next;\r\n                }\r\n            }\r\n        }\r\n        // Add to array\r\n        WriteSetEntry* e = &log[numStores++];\r\n        assert(numStores < TX_MAX_STORES);\r\n        e->addr = addr;\r\n        e->val = val;\r\n        // Add to hashmap\r\n        WriteSetEntry* be = buckets[hashAddr];\r\n        // Clear if entry is from previous tx\r\n        e->next = (be < e && hash(be->addr) == hashAddr) ? be : nullptr;\r\n        buckets[hashAddr] = e;\r\n    }\r\n\r\n    // Does a lookup on the WriteSet for an addr.\r\n    // If the numStores is lower than MAX_ARRAY_LOOKUP, the lookup is done on the log, otherwise, the lookup is done on the hashmap.\r\n    // If it's not in the write-set, return lval.\r\n    inline uint64_t lookupAddr(const void* addr, uint64_t lval) {\r\n        if (numStores < MAX_ARRAY_LOOKUP) {\r\n            // Lookup in array\r\n            for (unsigned int idx = 0; idx < numStores; idx++) {\r\n                if (log[idx].addr == addr) return log[idx].val;\r\n            }\r\n        } else {\r\n            // Lookup in hashmap\r\n            const uint64_t hashAddr = hash(addr);\r\n            WriteSetEntry* be = buckets[hashAddr];\r\n            if (be < &log[numStores] && hash(be->addr) == hashAddr) {\r\n                while (be != nullptr) {\r\n                    if (be->addr == addr) return be->val;\r\n                    be = be->next;\r\n                }\r\n            }\r\n        }\r\n        return lval;\r\n    }\r\n\r\n    // Assignment operator, used when making a copy of a WriteSet to help another thread\r\n    WriteSet& operator = (const WriteSet &other) {\r\n        numStores = other.numStores;\r\n        for (uint64_t i = 0; i < numStores; i++) log[i] = other.log[i];\r\n        return *this;\r\n    }\r\n\r\n    // Applies all entries in the log as DCASes.\r\n    // Seq must match for DCAS to succeed. This method is on the \"hot-path\".\r\n    inline void apply(uint64_t seq, const int tid) {\r\n        for (uint64_t i = 0; i < numStores; i++) {\r\n            // Use an heuristic to give each thread 8 consecutive DCAS to apply\r\n            WriteSetEntry& e = log[(tid*8 + i) % numStores];\r\n            tmtype<uint64_t>* tmte = (tmtype<uint64_t>*)e.addr;\r\n            uint64_t lval = tmte->val.load(std::memory_order_acquire);\r\n            uint64_t lseq = tmte->seq.load(std::memory_order_acquire);\r\n            if (lseq < seq) DCAS((uint64_t*)e.addr, lval, lseq, e.val, seq);\r\n        }\r\n    }\r\n};\r\n\r\n\r\n// Forward declaration\r\nstruct OpData;\r\n// This is used by addOrReplace() to know which OpData instance to use for the current transaction\r\nextern thread_local OpData* tl_opdata;\r\n\r\n\r\n// ts purpose is to hold thread-local data\r\nstruct OpData {\r\n    uint64_t              curTx {0};                   // Used during a transaction to keep the value of currTx read in beginTx() (owner thread only)\r\n    std::atomic<uint64_t> request {0};                 // Can be moved to CLOSED by other threads, using a CAS\r\n    uint64_t              nestedTrans {0};             // Thread-local: Number of nested transactions\r\n    uint64_t              numRetires {0};              // Number of calls to retire() in this transaction (owner thread only)\r\n    tmbase*               rlog[TX_MAX_RETIRES];        // List of retired objects during the transaction (owner thread only)\r\n    uint64_t              numAllocs {0};               // Number of calls to tmNew() in this transaction (owner thread only)\r\n    Deletable             alog[TX_MAX_ALLOCS];         // List of newly allocated objects during the transaction (owner thread only)\r\n};\r\n\r\n\r\n// Used to identify aborted transactions\r\nstruct AbortedTx {};\r\nstatic constexpr AbortedTx AbortedTxException {};\r\n\r\nclass OneFileWF;\r\nextern OneFileWF gOFWF;\r\n\r\n\r\n/**\r\n * <h1> OneFile STM (Wait-Free) </h1>\r\n *\r\n * OneFile is a Software Transacional Memory with wait-free progress, meant to\r\n * implement wait-free data structures. It has integrated wait-free memory\r\n * reclamation using Hazard Eras: https://dl.acm.org/citation.cfm?id=3087588\r\n *\r\n * OneFile is a word-based STM and it uses double-compare-and-swap (DCAS).\r\n *\r\n * Right now it has several limitations, some will be fixed in the future, some may be hard limitations of this approach:\r\n * - We can't have stack allocated tmtype<> variables. For example, we can't created inside a transaction \"tmtpye<uint64_t> tmp = a;\",\r\n *   it will give weird errors because of stack allocation.\r\n * - We need DCAS but it can be emulated with LL/SC or even with single-word CAS\r\n *   if we do redirection to a (lock-free) pool with SeqPtrs;\r\n */\r\nclass OneFileWF {\r\nprivate:\r\n    static const bool                    debug = false;\r\n    HazardErasOF                         he {REGISTRY_MAX_THREADS};\r\n    OpData                              *opData;\r\n    // Maximum number of times a reader will fail a transaction before turning into an updateTx()\r\n    static const int                     MAX_READ_TRIES = 4;\r\n    // Member variables for wait-free consensus\r\n    tmtype<TransFunc*>*                  operations;  // We've tried adding padding here but it didn't make a difference\r\n    tmtype<uint64_t>*                    results;\r\npublic:\r\n    std::atomic<uint64_t>                pad0[16];  // two cache lines of padding, before and after curTx\r\n    std::atomic<uint64_t>                curTx {seqidx2trans(1,0)};\r\n    std::atomic<uint64_t>                pad1[15];\r\n    WriteSet                            *writeSets;                    // Two write-sets for each thread\r\n\r\n    OneFileWF() {\r\n        opData = new OpData[REGISTRY_MAX_THREADS];\r\n        writeSets = new WriteSet[REGISTRY_MAX_THREADS];\r\n        operations = new tmtype<TransFunc*>[REGISTRY_MAX_THREADS];\r\n        for (unsigned i = 0; i < REGISTRY_MAX_THREADS; i++) operations[i].operationsInit();\r\n        results = new tmtype<uint64_t>[REGISTRY_MAX_THREADS];\r\n        for (unsigned i = 0; i < REGISTRY_MAX_THREADS; i++) results[i].resultsInit();\r\n    }\r\n\r\n    ~OneFileWF() {\r\n        delete[] opData;\r\n        delete[] writeSets;\r\n        delete[] operations;\r\n        delete[] results;\r\n    }\r\n\r\n    static std::string className() { return \"OneFileSTM-WF\"; }\r\n\r\n    // Progress condition: wait-free population-oblivious\r\n    // Attempts to publish our write-set (commit the transaction) and then applies the write-set.\r\n    // Returns true if my transaction was committed.\r\n    inline bool commitTx(OpData& myopd, const int tid) {\r\n        // If it's a read-only transaction, then commit immediately\r\n        if (writeSets[tid].numStores == 0 && myopd.numRetires == 0) return true;\r\n        // Give up if the curTx has changed sinced our transaction started\r\n        if (myopd.curTx != curTx.load(std::memory_order_acquire)) return false;\r\n        // Move our request to OPEN, using the sequence of the previous transaction +1\r\n        uint64_t seq = trans2seq(myopd.curTx);\r\n        uint64_t newTx = seqidx2trans(seq+1,tid);\r\n        myopd.request.store(newTx, std::memory_order_release);\r\n        // Attempt to CAS curTx to our OpData instance (tid) incrementing the seq in it\r\n        uint64_t lcurTx = myopd.curTx;\r\n        if (debug) printf(\"tid=%i  attempting CAS on curTx from (%ld,%ld) to (%ld,%ld)\\n\", tid, trans2seq(lcurTx), trans2idx(lcurTx), seq+1, (uint64_t)tid);\r\n        if (!curTx.compare_exchange_strong(lcurTx, newTx)) return false;\r\n        // Execute each store in the write-set using DCAS() and close the request\r\n        helpApply(newTx, tid);\r\n        retireRetiresFromLog(myopd, tid);\r\n        myopd.numAllocs = 0;\r\n        if (debug) printf(\"Committed transaction (%ld,%ld) with %ld stores\\n\", seq+1, (uint64_t)tid, writeSets[tid].numStores);\r\n        return true;\r\n    }\r\n\r\n    // Progress condition: wait-free (bounded by the number of threads)\r\n    // Applies a mutative transaction or gets another thread with an ongoing\r\n    // transaction to apply it.\r\n    // If three 'seq' have passed since the transaction when we published our\r\n    // function, then the worst-case scenario is: the first transaction does not\r\n    // see our function; the second transaction transforms our function\r\n    // but doesn't apply the corresponding write-set; the third transaction\r\n    // guarantees that the log of the second transaction is applied.\r\n    inline void innerUpdateTx(OpData& myopd, TransFunc* funcptr, const int tid) {\r\n        ++myopd.nestedTrans;\r\n        if (debug) printf(\"updateTx(tid=%d)\\n\", tid);\r\n        // We need an era from before the 'funcptr' is announced, so as to protect it\r\n        uint64_t firstEra = trans2seq(curTx.load(std::memory_order_acquire));\r\n        operations[tid].rawStore(funcptr, results[tid].getSeq());\r\n        tl_opdata = &myopd;\r\n        // Check 3x for the completion of our operation because we don't have a fence\r\n        // on operations[tid].rawStore(), otherwise it would be just 2x.\r\n        for (int iter = 0; iter < 4; iter++) {\r\n            // An update transaction is read-only until it does the first store()\r\n            tl_is_read_only = true;\r\n            // Clear the logs of the previous transaction\r\n            deleteAllocsFromLog(myopd);\r\n            writeSets[tid].numStores = 0;\r\n            myopd.numRetires = 0;\r\n            myopd.curTx = curTx.load(std::memory_order_acquire);\r\n            // Optimization: if my request is answered, then my tx is committed\r\n            if (results[tid].getSeq() > operations[tid].getSeq()) break;\r\n            helpApply(myopd.curTx, tid);\r\n            // Reset the write-set after (possibly) helping another transaction complete\r\n            writeSets[tid].numStores = 0;\r\n            // Use HE to protect the objects we're going to access during the transform phase\r\n            he.set(myopd.curTx, tid);\r\n            if (myopd.curTx != curTx.load()) continue;\r\n            try {\r\n                if (!transformAll(myopd.curTx, tid)) continue;\r\n            } catch (AbortedTx&) {\r\n                continue;\r\n            }\r\n            if (commitTx(myopd, tid)) break;\r\n        }\r\n        deleteAllocsFromLog(myopd);\r\n        tl_opdata = nullptr;\r\n        --myopd.nestedTrans;\r\n        he.clear(tid);\r\n        retireMyFunc(tid, funcptr, firstEra);\r\n    }\r\n\r\n    // Update transaction with non-void return value\r\n    template<typename R, class F> static R updateTx(F&& func) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        OpData& myopd = gOFWF.opData[tid];\r\n        if (myopd.nestedTrans > 0) return func();\r\n        // Copy the lambda to a std::function<> and announce a request with the pointer to it\r\n        gOFWF.innerUpdateTx(myopd, new TransFunc([func] () { return (uint64_t)func(); }), tid);\r\n        return (R)gOFWF.results[tid].pload();\r\n    }\r\n\r\n    // Update transaction with void return value\r\n    template<class F> static void updateTx(F&& func) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        OpData& myopd = gOFWF.opData[tid];\r\n        if (myopd.nestedTrans > 0) {\r\n            func();\r\n            return;\r\n        }\r\n        // Copy the lambda to a std::function<> and announce a request with the pointer to it\r\n        gOFWF.innerUpdateTx(myopd, new TransFunc([func] () { func(); return 0; }), tid);\r\n    }\r\n\r\n    // Progress condition: wait-free (bounded by the number of threads + MAX_READ_TRIES)\r\n    template<typename R, class F> R readTransaction(F&& func) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        OpData& myopd = opData[tid];\r\n        if (myopd.nestedTrans > 0) return func();\r\n        ++myopd.nestedTrans;\r\n        tl_opdata = &myopd;\r\n        tl_is_read_only = true;\r\n        if (debug) printf(\"readTx(tid=%d)\\n\", tid);\r\n        R retval {};\r\n        writeSets[tid].numStores = 0;\r\n        myopd.numAllocs = 0;\r\n        myopd.numRetires = 0;\r\n        for (int iter = 0; iter < MAX_READ_TRIES; iter++) {\r\n            myopd.curTx = curTx.load(std::memory_order_acquire);\r\n            helpApply(myopd.curTx, tid);\r\n            // Use HE to protect the objects we're going to access during the simulation\r\n            he.set(myopd.curTx, tid);\r\n            // Reset the write-set after (possibly) helping another transaction complete\r\n            writeSets[tid].numStores = 0;\r\n            if (myopd.curTx != curTx.load()) continue;\r\n            try {\r\n                retval = func();\r\n            } catch (AbortedTx&) {\r\n                continue;\r\n            }\r\n            --myopd.nestedTrans;\r\n            tl_opdata = nullptr;\r\n            he.clear(tid);\r\n            return retval;\r\n        }\r\n        if (debug) printf(\"readTx() executed MAX_READ_TRIES, posing as updateTx()\\n\");\r\n        --myopd.nestedTrans;\r\n        // Tried too many times unsucessfully, pose as an updateTx()\r\n        return updateTx<R>(func);\r\n    }\r\n\r\n    template<typename R, typename F> static R readTx(F&& func) { return gOFWF.readTransaction<R>(func); }\r\n    //template<typename F> static void readTx(F&& func) { gOFWF.readTransaction(func); }\r\n\r\n    // When inside a transaction, the user can't call \"new\" directly because if\r\n    // the transaction fails, it would leak the memory of these allocations.\r\n    // Instead, we provide an allocator that keeps pointers to these objects\r\n    // in a log, and in the event of a failed commit of the transaction, it will\r\n    // delete the objects so that there are no leaks.\r\n    // TODO: Add static_assert to check if T is of tmbase\r\n    template <typename T, typename... Args> static T* tmNew(Args&&... args) {\r\n        T* ptr = (T*)std::malloc(sizeof(T));\r\n        new (ptr) T(std::forward<Args>(args)...);  // new placement\r\n        ptr->newEra_ = trans2seq(gOFWF.curTx.load(std::memory_order_acquire));\r\n        OpData* myopd = tl_opdata;\r\n        if (myopd != nullptr) {\r\n            assert(myopd->numAllocs != TX_MAX_ALLOCS);\r\n            Deletable& del = myopd->alog[myopd->numAllocs++];\r\n            del.obj = ptr;\r\n            // This func ptr to a lambda gives us a way to call the destructor\r\n            // when a transaction aborts.\r\n            del.reclaim = [](void* obj) { static_cast<T*>(obj)->~T(); std::free(obj); };\r\n        }\r\n        return ptr;\r\n    }\r\n\r\n    // The user can not directly delete objects in the transaction because the\r\n    // transaction may fail and needs to be retried and other threads may be\r\n    // using those objects.\r\n    // Instead, it has to call retire() for the objects it intends to delete.\r\n    // The retire() puts the objects in the rlog, and only when the transaction\r\n    // commits, the objects are put in the Hazard Eras retired list.\r\n    // The del.delEra is filled in retireRetiresFromLog().\r\n    // TODO: Add static_assert to check if T is of tmbase\r\n    template<typename T> static void tmDelete(T* obj) {\r\n        if (obj == nullptr) return;\r\n        obj->~T(); // Execute destructor as part of the current transaction\r\n        OpData* myopd = tl_opdata;\r\n        if (myopd == nullptr) {\r\n            std::free(obj);  // Outside a transaction, just delete the object\r\n            return;\r\n        }\r\n        assert(myopd->numRetires != TX_MAX_RETIRES);\r\n        myopd->rlog[myopd->numRetires++] = obj;\r\n    }\r\n\r\n    // We snap a tmbase at the beginning of the allocation\r\n    static void* tmMalloc(size_t size) {\r\n        uint8_t* ptr = (uint8_t*)std::malloc(size+sizeof(tmbase));\r\n        // We must reset the contents to zero to guarantee that if any tmtypes are allocated inside, their 'seq' will be zero\r\n        std::memset(ptr+sizeof(tmbase), 0, size);\r\n        ((tmbase*)ptr)->newEra_ = trans2seq(gOFWF.curTx.load(std::memory_order_acquire));\r\n        OpData* myopd = tl_opdata;\r\n        if (myopd != nullptr) {\r\n            assert(myopd->numAllocs != TX_MAX_ALLOCS);\r\n            Deletable& del = myopd->alog[myopd->numAllocs++];\r\n            del.obj = ptr;\r\n            del.reclaim = [](void* obj) { std::free(obj); };\r\n        }\r\n        return ptr + sizeof(tmbase);\r\n    }\r\n\r\n    // We assume there is a tmbase allocated in the beginning of the allocation\r\n    static void tmFree(void* obj) {\r\n        if (obj == nullptr) return;\r\n        OpData* myopd = tl_opdata;\r\n        uint8_t* ptr = (uint8_t*)obj - sizeof(tmbase);\r\n        if (myopd == nullptr) {\r\n            std::free(ptr);  // Outside a transaction, just free the object\r\n            return;\r\n        }\r\n        assert(myopd->numRetires != TX_MAX_RETIRES);\r\n        myopd->rlog[myopd->numRetires++] = (tmbase*)ptr;\r\n    }\r\n\r\nprivate:\r\n    // Progress condition: wait-free population oblivious\r\n    inline void helpApply(uint64_t lcurTx, const uint64_t tid) {\r\n        const uint64_t idx = trans2idx(lcurTx);\r\n        const uint64_t seq = trans2seq(lcurTx);\r\n        OpData& opd = opData[idx];\r\n        // Nothing to apply unless the request matches the curTx\r\n        if (lcurTx != opd.request.load(std::memory_order_acquire)) return;\r\n        if (idx != tid) {\r\n            // Make a copy of the write-set and check if it is consistent\r\n            writeSets[tid] = writeSets[idx];\r\n            // Use HE to protect the objects the transaction touches\r\n            he.set(lcurTx, tid);\r\n            if (lcurTx != curTx.load()) return;\r\n            // The published era is now protecting all objects alive in the transaction lcurTx\r\n            if (lcurTx != opd.request.load(std::memory_order_acquire)) return;\r\n        }\r\n        if (debug) printf(\"Applying %ld stores in write-set\\n\", writeSets[tid].numStores);\r\n        writeSets[tid].apply(seq, tid);\r\n        const uint64_t newReq = seqidx2trans(seq+1,idx);\r\n        if (idx == tid) {\r\n            opd.request.store(newReq, std::memory_order_release);\r\n        } else {\r\n            if (opd.request.load(std::memory_order_acquire) == lcurTx) {\r\n                opd.request.compare_exchange_strong(lcurTx, newReq);\r\n            }\r\n        }\r\n    }\r\n\r\n    // This is called when the transaction fails, to undo all the allocations done during the transaction\r\n     void deleteAllocsFromLog(OpData& myopd) {\r\n        for (unsigned i = 0; i < myopd.numAllocs; i++) {\r\n            myopd.alog[i].reclaim(myopd.alog[i].obj);\r\n        }\r\n        myopd.numAllocs = 0;\r\n    }\r\n\r\n    // My transaction was successful, it's my duty to cleanup any retired objects.\r\n    // This is called by the owner thread when the transaction succeeds, to pass\r\n    // the retired objects to Hazard Eras. We can't delete the objects\r\n    // immediately because there might be other threads trying to apply our log\r\n    // which may (or may not) contain addresses inside the objects in this list.\r\n    void retireRetiresFromLog(OpData& myopd, const int tid) {\r\n        uint64_t lseq = trans2seq(curTx.load(std::memory_order_acquire));\r\n        // First, add all the objects to the list of retired/zombies\r\n        for (unsigned i = 0; i < myopd.numRetires; i++) {\r\n            myopd.rlog[i]->delEra_ = lseq;\r\n            he.addToRetiredList(myopd.rlog[i], tid);\r\n        }\r\n        // Second, start a cleaning phase, scanning to see which objects can be removed\r\n        he.clean(lseq, tid);\r\n        myopd.numRetires = 0;\r\n    }\r\n\r\n\r\n    inline void retireMyFunc(const int tid, TransFunc* myfunc, uint64_t firstEra) {\r\n        myfunc->newEra_ = firstEra;\r\n        myfunc->delEra_ = trans2seq(curTx.load(std::memory_order_acquire))+1; // Do we really need the +1 ?\r\n        he.addToRetiredListTx(myfunc, tid);\r\n    }\r\n\r\n    // Aggregate all the functions of the different thread's writeTransaction()\r\n    // and transform them into to a single log (the current thread's log).\r\n    // Returns true if all active TransFunc were transformed\r\n    inline bool transformAll(const uint64_t lcurrTx, const int tid) {\r\n        for (unsigned i = 0; i < ThreadRegistry::getMaxThreads(); i++) {\r\n            // Check if the operation of thread i has been applied (has a matching result)\r\n            TransFunc* txfunc;\r\n            uint64_t res, operationsSeq, resultSeq;\r\n            if (!operations[i].rawLoad(txfunc, operationsSeq)) continue;\r\n            if (!results[i].rawLoad(res, resultSeq)) continue;\r\n            if (resultSeq > operationsSeq) continue;\r\n            // Operation has not yet been applied, check that transaction identifier has not changed\r\n            if (lcurrTx != curTx.load(std::memory_order_acquire)) return false;\r\n            // Apply the operation of thread i and save result in results[i],\r\n            // with this store being part of the transaction itself.\r\n            results[i] = txfunc->func();\r\n        }\r\n        return true;\r\n    }\r\n};\r\n\r\n\r\n//\r\n// Wrapper methods to the global TM instance. The user should use these:\r\n//\r\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gOFWF.updateTx<R>(func); }\r\ntemplate<typename R, typename F> static R readTx(F&& func) { return gOFWF.readTx<R>(func); }\r\ntemplate<typename F> static void updateTx(F&& func) { gOFWF.updateTx(func); }\r\ntemplate<typename F> static void readTx(F&& func) { gOFWF.readTx(func); }\r\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return OneFileWF::tmNew<T>(args...); }\r\ntemplate<typename T> void tmDelete(T* obj) { OneFileWF::tmDelete<T>(obj); }\r\ninline void* tmMalloc(size_t size) { return OneFileWF::tmMalloc(size); }\r\ninline void tmFree(void* obj) { OneFileWF::tmFree(obj); }\r\n\r\n\r\n// We have to check if there is a new ongoing transaction and if so, abort\r\n// this execution immediately for two reasons:\r\n// 1. Memory Reclamation: the val we're returning may be a pointer to an\r\n// object that has since been retired and deleted, therefore we can't allow\r\n// user code to de-reference it;\r\n// 2. Invariant Conservation: The val we're reading may be from a newer\r\n// transaction, which implies that it may break an invariant in the user code.\r\n// See examples of invariant breaking in this post:\r\n// http://concurrencyfreaks.com/2013/11/stampedlocktryoptimisticread-and.html\r\ntemplate<typename T> inline T tmtype<T>::pload() const {\r\n    T lval = (T)val.load(std::memory_order_acquire);\r\n    OpData* const myopd = tl_opdata;\r\n    if (myopd == nullptr) return lval;\r\n    uint64_t lseq = seq.load(std::memory_order_acquire);\r\n    if (lseq > trans2seq(myopd->curTx)) throw AbortedTxException;\r\n    if (tl_is_read_only) return lval;\r\n    return (T)gOFWF.writeSets[tl_tcico.tid].lookupAddr(this, (uint64_t)lval);\r\n}\r\n\r\n// This method is meant to be used by the internal consensus mechanism, not by the user.\r\n// Returns true if the 'val' and 'seq' placed in 'keepVal' and 'keepSeq'\r\n// are consistent, i.e. linearizabile. We need to use acquire-loads to keep\r\n// order and re-check the 'seq' to make sure it corresponds to the 'val' we're returning.\r\ntemplate<typename T> inline bool tmtype<T>::rawLoad(T& keepVal, uint64_t& keepSeq) {\r\n    keepSeq = seq.load(std::memory_order_acquire);\r\n    keepVal = (T)val.load(std::memory_order_acquire);\r\n    return (keepSeq == seq.load(std::memory_order_acquire));\r\n}\r\n\r\n// We don't need to check currTx here because we're not de-referencing\r\n// the val. It's only after a load() that the val may be de-referenced\r\n// (in user code), therefore we do the check on load() only.\r\ntemplate<typename T> inline void tmtype<T>::pstore(T newVal) {\r\n    if (tl_opdata == nullptr) { // Looks like we're outside a transaction\r\n        val.store((uint64_t)newVal, std::memory_order_relaxed);\r\n    } else {\r\n        gOFWF.writeSets[tl_tcico.tid].addOrReplace(this, (uint64_t)newVal);\r\n    }\r\n}\r\n\r\n\r\n//\r\n// Place these in a .cpp if you include this header from multiple files (compilation units)\r\n//\r\nOneFileWF gOFWF {};\r\nthread_local OpData* tl_opdata {nullptr};\r\n// Global/singleton to hold all the thread registry functionality\r\nThreadRegistry gThreadRegistry {};\r\n// During a transaction, this is true up until the first store()\r\nthread_local bool tl_is_read_only {false};\r\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\r\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\r\nthread_local ThreadCheckInCheckOut tl_tcico {};\r\n// Helper function for thread de-registration\r\nvoid thread_registry_deregister_thread(const int tid) {\r\n    gThreadRegistry.deregister_thread(tid);\r\n}\r\n\r\n} // wait-free transactions with wait-free memory reclamation, and it's all less than 1000 lines of code  :)\r\n#endif /* _ONE_FILE_WAIT_FREE_TRANSACTIONAL_MEMORY_WITH_HAZARD_ERAS_H_ */\r\n"
  },
  {
    "path": "stms/TinySTM.hpp",
    "content": "/*\r\n * Copyright 2017-2018\r\n *   Andreia Correia <andreia.veiga@unine.ch>\r\n *   Pedro Ramalhete <pramalhe@gmail.com>\r\n *   Pascal Felber <pascal.felber@unine.ch>\r\n *   Nachshon Cohen <nachshonc@gmail.com>\r\n *\r\n * This work is published under the MIT license. See LICENSE.txt\r\n */\r\n#ifndef _TINY_STM_TRANSACTIONAL_MEMORY_WRAPPER_H_\r\n#define _TINY_STM_TRANSACTIONAL_MEMORY_WRAPPER_H_\r\n\r\n#include <atomic>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <vector>\r\n#include <functional>\r\n\r\n\r\nnamespace tinystm {\r\n\r\n// Compile with explicit calls to TinySTM\r\n#include \"tinystm/include/stm.h\"\r\n#include \"tinystm/include/mod_mem.h\"\r\n#include \"tinystm/include/mod_ab.h\"\r\n\r\n\r\nstruct tmbase {\r\n};\r\n\r\n\r\n//\r\n// Thread Registry stuff\r\n//\r\nextern void thread_registry_deregister_thread(const int tid);\r\n\r\n// An helper class to do the checkin and checkout of the thread registry\r\nstruct ThreadCheckInCheckOut {\r\n    static const int NOT_ASSIGNED = -1;\r\n    int tid { NOT_ASSIGNED };\r\n    ~ThreadCheckInCheckOut() {\r\n        if (tid == NOT_ASSIGNED) return;\r\n        thread_registry_deregister_thread(tid);\r\n    }\r\n};\r\n\r\nextern thread_local ThreadCheckInCheckOut tl_gc_tcico;\r\n\r\n// Forward declaration of global/singleton instance\r\nclass ThreadRegistry;\r\nextern ThreadRegistry gThreadRegistry;\r\n\r\n/*\r\n * <h1> Registry for threads </h1>\r\n *\r\n * This is singleton type class that allows assignement of a unique id to each thread.\r\n * The first time a thread calls ThreadRegistry::getTID() it will allocate a free slot in 'usedTID[]'.\r\n * This tid wil be saved in a thread-local variable of the type ThreadCheckInCheckOut which\r\n * upon destruction of the thread will call the destructor of ThreadCheckInCheckOut and free the\r\n * corresponding slot to be used by a later thread.\r\n * RomulusLR relies on this to work properly.\r\n */\r\nclass ThreadRegistry {\r\npublic:\r\n    static const int                    REGISTRY_MAX_THREADS = 128;\r\n\r\nprivate:\r\n    alignas(128) std::atomic<bool>      usedTID[REGISTRY_MAX_THREADS];   // Which TIDs are in use by threads\r\n    alignas(128) std::atomic<int>       maxTid {-1};                     // Highest TID (+1) in use by threads\r\n\r\npublic:\r\n    ThreadRegistry() {\r\n        for (int it = 0; it < REGISTRY_MAX_THREADS; it++) {\r\n            usedTID[it].store(false, std::memory_order_relaxed);\r\n        }\r\n    }\r\n\r\n    // Progress Condition: wait-free bounded (by the number of threads)\r\n    int register_thread_new(void) {\r\n        for (int tid = 0; tid < REGISTRY_MAX_THREADS; tid++) {\r\n            if (usedTID[tid].load(std::memory_order_acquire)) continue;\r\n            bool unused = false;\r\n            if (!usedTID[tid].compare_exchange_strong(unused, true)) continue;\r\n            // Increase the current maximum to cover our thread id\r\n            int curMax = maxTid.load();\r\n            while (curMax <= tid) {\r\n                maxTid.compare_exchange_strong(curMax, tid+1);\r\n                curMax = maxTid.load();\r\n            }\r\n            tl_gc_tcico.tid = tid;\r\n            return tid;\r\n        }\r\n        std::cout << \"ERROR: Too many threads, registry can only hold \" << REGISTRY_MAX_THREADS << \" threads\\n\";\r\n        assert(false);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    inline void deregister_thread(const int tid) {\r\n        stm_exit_thread();    // Needed by TinySTM\r\n        usedTID[tid].store(false, std::memory_order_release);\r\n    }\r\n\r\n    // Progress condition: wait-free population oblivious\r\n    static inline uint64_t getMaxThreads(void) {\r\n        return gThreadRegistry.maxTid.load(std::memory_order_acquire);\r\n    }\r\n\r\n    // Progress condition: wait-free bounded (by the number of threads)\r\n    static inline int getTID(void) {\r\n        int tid = tl_gc_tcico.tid;\r\n        if (tid != ThreadCheckInCheckOut::NOT_ASSIGNED) return tid;\r\n        stm_init_thread();   // Needed by TinySTM\r\n        return gThreadRegistry.register_thread_new();\r\n    }\r\n};\r\n\r\n\r\n\r\nclass TinySTM;\r\nextern TinySTM gTinySTM;\r\n\r\nclass TinySTM {\r\n\r\nprivate:\r\n    // Maximum number of participating threads\r\n    static const uint64_t MAX_THREADS = 128;\r\n\r\npublic:\r\n    TinySTM(unsigned int maxThreads=MAX_THREADS) {\r\n        stm_init();\r\n        mod_mem_init(0);\r\n        mod_ab_init(0, NULL);\r\n    }\r\n\r\n    ~TinySTM() {\r\n        stm_exit();\r\n    }\r\n\r\n    static std::string className() { return \"TinySTM\"; }\r\n\r\n    template<typename R, class F>\r\n    static R updateTx(F&& func) {\r\n        const unsigned int tid = ThreadRegistry::getTID();\r\n        R retval{};\r\n        stm_tx_attr_t _a = {{.id = (unsigned int)tid, .read_only = false}};\r\n        sigjmp_buf *_e = stm_start(_a);\r\n        sigsetjmp(*_e, 0);\r\n        retval = func();\r\n        stm_commit();\r\n        return retval;\r\n    }\r\n\r\n    template<class F>\r\n    static void updateTx(F&& func) {\r\n        const unsigned int tid = ThreadRegistry::getTID();\r\n        stm_tx_attr_t _a = {{.id = (unsigned int)tid, .read_only = false}};\r\n        sigjmp_buf *_e = stm_start(_a);\r\n        sigsetjmp(*_e, 0);\r\n        func();\r\n        stm_commit();\r\n    }\r\n\r\n    template<typename R, class F>\r\n    static R readTx(F&& func) {\r\n        const unsigned int tid = ThreadRegistry::getTID();\r\n        R retval{};\r\n        stm_tx_attr_t _a = {{.id = (unsigned int)tid, .read_only = true}};\r\n        sigjmp_buf *_e = stm_start(_a);\r\n        sigsetjmp(*_e, 0);\r\n        retval = func();\r\n        stm_commit();\r\n        return retval;\r\n    }\r\n\r\n    template<class F>\r\n    static void readTx(F&& func) {\r\n        const int tid = ThreadRegistry::getTID();\r\n        stm_tx_attr_t _a = {{.id = (unsigned int)tid, .read_only = true}};\r\n        sigjmp_buf *_e = stm_start(_a);\r\n        sigsetjmp(*_e, 0);\r\n        func();\r\n        stm_commit();\r\n    }\r\n\r\n    template <typename T, typename... Args>\r\n    static T* tmNew(Args&&... args) {\r\n        void* addr = stm_malloc(sizeof(T));\r\n        assert(addr != NULL);\r\n        T* ptr = new (addr) T(std::forward<Args>(args)...);\r\n        return ptr;\r\n    }\r\n\r\n    template<typename T>\r\n    static void tmDelete(T* obj) {\r\n        if (obj == nullptr) return;\r\n        obj->~T();\r\n        stm_free(obj, sizeof(T));\r\n    }\r\n\r\n    static void* tmMalloc(size_t size) {\r\n        return stm_malloc(size);\r\n    }\r\n\r\n    static void tmFree(void* obj) {\r\n        stm_free(obj, 0);\r\n    }\r\n};\r\n\r\n\r\n\r\n// T is typically a pointer to a node, but it can be integers or other stuff, as long as it fits in 64 bits\r\ntemplate<typename T>\r\nstruct tmtype {\r\n    T val {};\r\n\r\n    tmtype() { }\r\n\r\n    tmtype(T initVal) : val{initVal} {}\r\n\r\n    // Casting operator\r\n    operator T() {\r\n        return load();\r\n    }\r\n\r\n    // Prefix increment operator: ++x\r\n    void operator++ () {\r\n        store(load()+1);\r\n    }\r\n\r\n    // Prefix decrement operator: --x\r\n    void operator-- () {\r\n        store(load()-1);\r\n    }\r\n\r\n    void operator++ (int) {\r\n        store(load()+1);\r\n    }\r\n\r\n    void operator-- (int) {\r\n        store(load()-1);\r\n    }\r\n\r\n    // Equals operator: first downcast to T and then compare\r\n    bool operator == (const T& otherval) const {\r\n        return load() == otherval;\r\n    }\r\n\r\n    // Difference operator: first downcast to T and then compare\r\n    bool operator != (const T& otherval) const {\r\n        return load() != otherval;\r\n    }\r\n\r\n    // Operator arrow ->\r\n    T operator->() {\r\n        return load();\r\n    }\r\n\r\n    // Copy constructor\r\n    tmtype<T>(const tmtype<T>& other) {\r\n        store(other.load());\r\n    }\r\n\r\n    // Assignment operator from an tmtype\r\n    tmtype<T>& operator=(const tmtype<T>& other) {\r\n        store(other.load());\r\n        return *this;\r\n    }\r\n\r\n    // Assignment operator from a value\r\n    tmtype<T>& operator=(T value) {\r\n        store(value);\r\n        return *this;\r\n    }\r\n\r\n    inline void store(T newVal) {\r\n        stm_store((stm_word_t *)&val, (stm_word_t)newVal);\r\n    }\r\n\r\n    // Meant to be called when know we're the only ones touching\r\n    // these contents, for example, in the constructor of an object, before\r\n    // making the object visible to other threads.\r\n    inline void isolated_store(T newVal) {\r\n        val = newVal;\r\n    }\r\n\r\n    inline T load() const {\r\n        return (T)stm_load((stm_word_t *)&val);\r\n    }\r\n};\r\n\r\nextern TinySTM gTinySTM;\r\n\r\n\r\n// Wrapper to not do any transaction\r\ntemplate<typename R, typename Func>\r\nR notx(Func&& func) {\r\n    return func();\r\n}\r\n\r\ntemplate<typename R, typename F> static R updateTx(F&& func) { return gTinySTM.updateTx<R>(func); }\r\ntemplate<typename R, typename F> static R readTx(F&& func) { return gTinySTM.readTx<R>(func); }\r\ntemplate<typename F> static void updateTx(F&& func) { gTinySTM.updateTx(func); }\r\ntemplate<typename F> static void readTx(F&& func) { gTinySTM.readTx(func); }\r\ntemplate<typename T, typename... Args> T* tmNew(Args&&... args) { return gTinySTM.tmNew<T>(args...); }\r\ntemplate<typename T>void tmDelete(T* obj) { gTinySTM.tmDelete<T>(obj); }\r\nstatic void* tmMalloc(size_t size) { return TinySTM::tmMalloc(size); }\r\nstatic void tmFree(void* obj) { TinySTM::tmFree(obj); }\r\n\r\nstatic int getTID(void) { return ThreadRegistry::getTID(); }\r\n\r\n\r\n//\r\n// Place these in a .cpp if you include this header in multiple files\r\n//\r\nTinySTM gTinySTM {};\r\n// Global/singleton to hold all the thread registry functionality\r\nThreadRegistry gThreadRegistry {};\r\n// This is where every thread stores the tid it has been assigned when it calls getTID() for the first time.\r\n// When the thread dies, the destructor of ThreadCheckInCheckOut will be called and de-register the thread.\r\nthread_local ThreadCheckInCheckOut tl_gc_tcico {};\r\n// Helper function for thread de-registration\r\nvoid thread_registry_deregister_thread(const int tid) {\r\n    gThreadRegistry.deregister_thread(tid);\r\n}\r\n\r\n\r\n\r\n}\r\n\r\n#endif /* _TINY_STM_TRANSACTIONAL_MEMORY_WRAPPER_H_ */\r\n"
  },
  {
    "path": "stms/estm-0.3.0/.gitignore",
    "content": "lib/libstm.a\nsrc/*.o\n"
  },
  {
    "path": "stms/estm-0.3.0/AUTHORS",
    "content": "ESTM is maintained by:\n\n    Vincent Gramoli (vincent.gramoli@sydney.edu.au)\n\nThe following people have contributed to ESTM:\n\n    Normal transactions (tinystm): Pascal Felber, Patrick Marlier\n"
  },
  {
    "path": "stms/estm-0.3.0/COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "stms/estm-0.3.0/Makefile",
    "content": "include Makefile.in\n\nCFLAGS += -std=gnu89 -Wno-sequence-point\nCFLAGS += -I$(SRCDIR) \nCFLAGS += $(DEFINES) \nMODULES := $(patsubst %.c,%.o,$(wildcard $(SRCDIR)/mod_*.c))\n\n.PHONY:\tall clean\n\nall:\t$(TMLIB)\n\n$(TMLIB):\t$(SRCDIR)/$(TM).o $(SRCDIR)/wrappers.o $(SRCDIR)/gc.o $(MODULES)\n\t@mkdir -p lib\n\t$(AR) cru $@ $^\n\nclean:\n\trm -f $(TMLIB) $(SRCDIR)/*.o\n"
  },
  {
    "path": "stms/estm-0.3.0/Makefile.in",
    "content": "################\n# Local settings\n################\n\n# Paths\nSOLARIS_CC ?= gcc\n\n# Version\nifeq ($(VERSION),DEBUG)\n     CFLAGS \t+= -g -DDEBUG -O0\nelse\n     CFLAGS \t+= -O3 -DNDEBUG\nendif\n\nROOT ?= .\nSBROOT ?= ../../..\nSRCDIR = $(ROOT)/src\nINCDIR = $(ROOT)/include\nLIBDIR = $(ROOT)/lib\n\n# Path to LIBATOMIC_OPS (or to gcc-specific libatomic_ops)\nifdef LIBAO_HOME\n  LIBAO_INC = $(LIBAO_HOME)/include\nelse\n  LIBAO_INC = src/atomic_ops \nendif\n\nTMLIB = $(LIBDIR)/lib$(TM).a\nTM = stm\n\n#############################\n# Platform dependent settings\n#############################\n#\n# gcc thread-local storage requires \"significant \n# support from the linker (ld), dynamic linker\n# (ld.so), and system libraries (libc.so and libpthread.so), so it is\n# not available everywhere.\" source: gcc-doc.\n\nifndef OS_NAME\n    OS_NAME = $(shell uname -s)\nendif\n\nifeq ($(OS_NAME), Darwin)\n    OS = MacOS\n    DEFINES += -UTLS\nendif\n\nifeq ($(OS_NAME), Linux)\n    OS = Linux\n    DEFINES += -DTLS\nendif\n\nifeq ($(OS_NAME), SunOS)\n    OS = Solaris\n    CC = $(SOLARIS_CC)\n    DEFINES += -DTLS\n    AR = /usr/ccs/bin/ar\nendif\n\n#################################\n# Architecture dependent settings\n#################################\n\nifndef ARCH\n    ARCH_NAME = $(shell uname -m)\nendif\n\nifeq ($(ARCH_NAME), i386)\n    ARCH = x86\n    CFLAGS += -m32\n    LDFLAGS += -m32\nendif\n\nifeq ($(ARCH_NAME), i686)\n    ARCH = x86\n    CFLAGS += -m32\n    LDFLAGS += -m32\nendif\n\nifeq ($(ARCH_NAME), x86_64)\n    ARCH = x86_64\n    CFLAGS += -m64\n    LDFLAGS += -m64\nendif\n\nifeq ($(ARCH_NAME), sun4v)\n    ARCH = sparc64\n    CFLAGS += -DSPARC=1 -DINLINED=1 -mt -fast -m64\n    LDFLAGS += -lrt -m64\nendif\n\n#################\n# Global settings\n#################\n\nCFLAGS += -Wall\nCFLAGS += -I$(LIBAO_INC) -I$(ROOT)/include\nLDFLAGS += -L$(ROOT)/lib -lstm -lpthread \n\n#################\n# MEMORY MGMT\n#################\n\nifeq ($(MALLOC), TC)\n  LDFLAGS += -ltcmalloc\n  CFLAGS += -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free\nendif\n"
  },
  {
    "path": "stms/estm-0.3.0/README",
    "content": "OVERVIEW\n--------\ne-STM is the first software transactional memory supporting elastic \ntransactions. Elastic transactions are a variant of the \ntransactional model. Upon conflict detection, an elastic \ntransaction might drop what it did so far within a separate \ntransaction that immediately commits, and initiate a new \ntransaction which might itself be elastic.\n\nElastic transactions are a complementary alternative to traditional \ntransactions, particularly appealing when implementing search \nstructures. Both forms of transactions can safely be combined \nwithin the same application. e-STM provides elastic transactions and \nthe normal transaction of tinySTM but elastic ones increase performance \nby 35% (on average). Our measurements are taken from the micro-benchmarks \navailable at http://lpd.epfl.ch/gramoli/php/estm.php\n\nINSTALL\n-------\n> make\n\nTEST\n----\nDownload microbench and set ESTMDIR env variable before \ncompiling it with e-STM using:\n\n> make estm\n\nExamples of benchmarks:\n1. If you want to execute insert/delete/search (90%/5%/5%) operations \non a skip list implementation of an integer set with an average \nsize of 1024 (-i1024) elements, using 32 threads and using \nelastic transactions for all operations (-x4)\n\n> ./bench/lf-skiplist -x4 -u10 -i1024 -r2048 -n32 \n\n32 threads execute 10% of attempted updates on 1024 elements with a range of 2048 values.\n\n2. If you want 10% effective updates (i.e., 10% of operations write to the \nmemory), then you should better use the alternate mode (-A) where the \ndelete targets the last inserted value and the effective flag (-f1)\n\n> ./bench/lf-skiplist -x4 -u10 -i1024 -r2048 -n32 -f1 -A -r2048\n\n32 threads execute 10% of effective updates on 1024 elements with a range of 2048 values.\n\ne-STM has been tested on an \n- 4 Quad-Core AMD Opteron \n\nCONTACT\n-------\nvincent.gramoli@epfl.ch\nhttp://lpd.epfl.ch/gramoli/php/estm.php\n"
  },
  {
    "path": "stms/estm-0.3.0/VERSIONS",
    "content": "[0.3.0 release]\n\n2011-07-28  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n\t* Add rotating buffer of size k \n\tfor checking the k past read accesses\n\n[0.2.8 release]\n\n2011-06-26  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n        * Add atomic_ops source code\n\t* Clean-up Makefile.in\n\n[0.2.7 release]\n\n2010-05-31  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n        * Removed dead-code\n\t* Removed stale functions (unit-l/s, set-extension...)\n\n[0.2.6 release]\n\n2010-02-23  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n        * Thread-local-storage newly enabled for compliant platform.\n\n[0.2.5 release]\n\n2009-09-29  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n        * Makefile bug about the garbage collector inclusion fixed\n\n[0.2.0 release]\n\n2009-06-19  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n        * Common interface TX_START/TX_LOAD/TX_STORE/TX_END\n\t  for any type of transactions (elastic/normal)\n\n2009-06-10  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n\t* Removed ro mode\n\n[0.1.8 release]\n\n2009-06-10  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n\t* Enhance efficiency for elastic functions.\n\t* stm_normal_load/store for normal transactions.\n\t* Removed support for stm_unit_write \n\t  (elastic_store switches to tx type to normal).\n\n[0.1.7 release]\n\n2009-05-23  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n\t* Debug of function stm_elastic_load.\n\t* Added stm_elastic_store functions.\n\n2009-05-20  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n        * Added stm_unit_load/stm_unit_write to stm.c\n\t* Upgrade normal transactions to tinySTM-v0.9.9\n\n[0.1.4 release]\n\n2008-12-01  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n\t* Added -x option for unit load/store.\n\n[0.1.0 release]\n\n2008-11-01  Vincent Gramoli  <vincent.gramoli@epfl.ch>\n\t* Initial release.\n"
  },
  {
    "path": "stms/estm-0.3.0/include/mod_local.h",
    "content": "/*\n * File:\n *   mod_local.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module for local memory accesses.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n/**\n * @file\n *   Module for local memory accesses.  Data is both written to memory\n *   and stored in an undo log.  Upon abort, modifications are reverted.\n *   Note that this module should not be used for updating shared data\n *   as there are no mechanisms to deal with concurrent accesses.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n * @date\n *   2007-2009\n */\n\n#ifndef _MOD_LOCAL_H_\n# define _MOD_LOCAL_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Transaction-local store of a word-sized value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local(TXPARAMS stm_word_t *addr, stm_word_t value);\n\n/**\n * Transaction-local store of a char value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_char(TXPARAMS char *addr, char value);\n\n/**\n * Transaction-local store of an unsigned char value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_uchar(TXPARAMS unsigned char *addr, unsigned char value);\n\n/**\n * Transaction-local store of a short value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_short(TXPARAMS short *addr, short value);\n\n/**\n * Transaction-local store of an unsigned short value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_ushort(TXPARAMS unsigned short *addr, unsigned short value);\n\n/**\n * Transaction-local store of an int value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_int(TXPARAMS int *addr, int value);\n\n/**\n * Transaction-local store of an unsigned int value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_uint(TXPARAMS unsigned int *addr, unsigned int value);\n\n/**\n * Transaction-local store of a long value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_long(TXPARAMS long *addr, long value);\n\n/**\n * Transaction-local store of an unsigned long value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_ulong(TXPARAMS unsigned long *addr, unsigned long value);\n\n/**\n * Transaction-local store of a float value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_float(TXPARAMS float *addr, float value);\n\n/**\n * Transaction-local store of a double value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_double(TXPARAMS double *addr, double value);\n\n/**\n * Transaction-local store of a pointer value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_local_ptr(TXPARAMS void **addr, void *value);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_local_init();\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_LOCAL_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/include/mod_mem.h",
    "content": "/*\n * File:\n *   mod_mem.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module for dynamic memory management.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n/**\n * @file\n *   Module for dynamic memory management.  This module provides\n *   functions for allocations and freeing memory inside transactions.\n *   A block allocated inside the transaction will be implicitly freed\n *   upon abort, and a block freed inside a transaction will only be\n *   returned to the system upon commit.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n * @date\n *   2007-2009\n */\n\n#ifndef _MOD_MEM_H_\n# define _MOD_MEM_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Allocate memory from inside a transaction.  Allocated memory is\n * implicitly freed upon abort.\n *\n * @param size\n *   Number of bytes to allocate.\n * @return\n *   Pointer to the allocated memory block.\n */\nvoid *stm_malloc(TXPARAMS size_t size);\n\n/**\n * Free memory from inside a transaction.  Freed memory is only returned\n * to the system upon commit and can optionally be overwritten (more\n * precisely, the locks protecting the memory are acquired) to prevent\n * another transaction from accessing the freed memory and observe\n * inconsistent states.\n *\n * @param addr\n *   Address of the memory block.\n * @param size\n *   Number of bytes to overwrite.\n */\nvoid stm_free(TXPARAMS void *addr, size_t size);\n\n/**\n * Free memory from inside a transaction.  Freed memory is only returned\n * to the system upon commit and can optionally be overwritten (more\n * precisely, the locks protecting the memory are acquired) to prevent\n * another transaction from accessing the freed memory and observe\n * inconsistent states.\n *\n * @param addr\n *   Address of the memory block.\n * @param idx\n *   Index of the first byte to overwrite.\n * @param size\n *   Number of bytes to overwrite.\n */\nvoid stm_free2(TXPARAMS void *addr, size_t idx, size_t size);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_mem_init();\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_MEM_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/include/mod_print.h",
    "content": "/*\n * File:\n *   mod_print.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module to test callbacks.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n/**\n * @file\n *   Module to test callbacks.  This module simply prints a message at\n *   each invocation of a callback.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n * @date\n *   2007-2009\n */\n\n#ifndef _MOD_PRINT_H_\n# define _MOD_PRINT_H_\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_print_init();\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_PRINT_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/include/mod_stats.h",
    "content": "/*\n * File:\n *   mod_stats.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module for gathering statistics about transactions.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n/**\n * @file\n *   Module for gathering statistics about transactions.  This module\n *   maintain both aggregate statistics about all threads (aggregates\n *   are updated upon thread cleanup) and per-thread statistics.  The\n *   built-in statistics of the core STM library are more efficient and\n *   detailed but this module is useful in case the library is compiled\n *   without support for statistics.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n * @date\n *   2007-2009\n */\n\n#ifndef _MOD_STATS_H_\n# define _MOD_STATS_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Get various statistics about the transactions of all threads.  See\n * the source code (mod_stats.c) for a list of supported statistics.\n *\n * @param name\n *   Name of the statistics.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   statistics.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_global_stats(const char *name, void *val);\n\n/**\n * Get various statistics about the transactions of the current thread.\n * See the source code (mod_stats.c) for a list of supported statistics.\n *\n * @param name\n *   Name of the statistics.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   statistics.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_local_stats(TXPARAMS const char *name, void *val);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_stats_init();\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_STATS_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/include/stm.h",
    "content": "/*\n * File:\n *   stm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Vincent Gramoli <vincent.gramoli@epfl.ch>\n * Description:\n *   STM functions.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n/**\n * @file\n *   STM functions.  This library contains the core functions for\n *   programming with E-STM.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Vincent Gramoli <vincent.gramoli@epfl.ch>\n * @date\n *   2007-2009\n */\n\n/**\n * @mainpage E-STM\n *\n * @section overview_sec Overview\n *\n *   E-STM is the first STM that supports elastic transactions, a new \n *   form of transactions that enhance concurrency. This distribution\n *   includes both normal transactions and elastic transactions.\n *   The normal transactions build upon TinySTM and support the same \n *   parameterizing options: write-back (lazy update), write-through \n *   (eager update), encounter-time locking (eager-acquirement), \n *   commit-time locking (lazy acquirement).\n *   TinySTM: write-back (updates are buffered until commit time),\n *   write-through (updates are directly written to memory), and\n *   commit-time locking (locks are only acquired upon commit).  The\n *   version can be selected by editing the makefile, which documents\n *   all the different compilation options.\n *\n *   E-STM compiles and runs on 32 or 64-bit architectures.\n *   Tested platforms are \n *    - SPARC Niagara 2 running SUN OS 5.10, \n *    - 1.6 Ghz Intel Core 2 Duo running Mac OS X 10.5.6, \n *    - dual quad-core Intel Xeon Server x500 series running Linux,\n *    - four quad-core AMD Opteron running Linux,\n *    - eight core Opteron running Linux.\n *\n * @section install_sec Installation\n *\n *   TinySTM requires the atomic_ops library, freely available from\n *   http://www.hpl.hp.com/research/linux/atomic_ops/.  The environment\n *   variable <c>LIBAO_HOME</c> must be set to the installation\n *   directory of atomic_ops.\n *\n *   If your system does not support GCC thread-local storage, set the\n *   environment variable <c>NOTLS</c> to a non-empty value before\n *   compilation.\n *\n *   To compile TinySTM libraries, execute <c>make</c> in the main\n *   directory.  To compile test applications, execute <c>make test</c>.\n *\n * @section contact_sec Contact\n *\n *   - E-mail : vincent.gramoli@epfl.ch\n *   - Web    : http://lpd.epfl.ch/gramoli/php/estm\n */\n\n#ifndef _STM_H_\n# define _STM_H_\n\n# include <setjmp.h>\n# include <stdint.h>\n# include <stdio.h>\n# include <stdlib.h>\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/*\n * The library does not require to pass the current transaction as a\n * parameter to the functions (the current transaction is stored in a\n * thread-local variable).  One can, however, compile the library with\n * explicit transaction parameters.  This is useful, for instance, for\n * performance on architectures that do not support TLS or for easier\n * compiler integration.\n */\n# ifdef EXPLICIT_TX_PARAMETER\nstruct stm_tx;\n#  define TXTYPE                        struct stm_tx *\n#  define TXPARAM                       struct stm_tx *tx\n#  define TXPARAMS                      struct stm_tx *tx,\n#  define TXARG                         (struct stm_tx *)tx\n#  define TXARGS                        (struct stm_tx *)tx,\nstruct stm_tx *stm_current_tx();\n# else /* ! EXPLICIT_TX_PARAMETER */\n#  define TXTYPE                        void\n#  define TXPARAM                       /* Nothing */\n#  define TXPARAMS                      /* Nothing */\n#  define TXARG                         /* Nothing */\n#  define TXARGS                        /* Nothing */\n#endif /* ! EXPLICIT_TX_PARAMETER */\n\t\t\n#define EL\t\t\t\t\t\t\t\t0\n#define NL\t\t\t\t\t\t\t\t1\n\t\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\n/**\n * Size of a word (accessible atomically) on the target architecture.\n * The library supports 32-bit and 64-bit architectures.\n */\ntypedef uintptr_t stm_word_t;\n\n/**\n * Transaction attributes specified by the application.\n */\ntypedef struct stm_tx_attr {\n  /**\n   * Application-specific identifier for the transaction.  Typically,\n   * each transactional construct (atomic block) should have a different\n   * identifier.  This identifier can be used by the infrastructure for\n   * improving performance, for instance by not scheduling together\n   * atomic blocks that have conflicted often in the past.\n   */\n  int id;\n  /**\n   * Indicates whether the transaction is read-only.  This information\n   * is used as a hint.  If a read-only transaction performs a write, it\n   * is aborted and restarted in read-write mode.  In that case, the\n   * value of the read-only flag is changed to false.\n   */\n  int ro;\n} stm_tx_attr_t;\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/**\n * Initialize the STM library.  This function must be called once, from\n * the main thread, before any access to the other functions of the\n * library.\n */\nvoid stm_init();\n\n/**\n * Clean up the STM library.  This function must be called once, from\n * the main thread, after all transactional threads have completed.\n */\nvoid stm_exit();\n\n/**\n * Initialize a transactional thread.  This function must be called once\n * from each thread that performs transactional operations, before the\n * thread calls any other functions of the library.\n */\nTXTYPE stm_init_thread();\n\n/**\n * Clean up a transactional thread.  This function must be called once\n * from each thread that performs transactional operations, upon exit.\n */\nvoid stm_exit_thread(TXPARAM);\n\t\n/**\n * Start a transaction. The transaction can be either of two types, \n * elastic or normal. If type is null, the transaction is normal.\n *\n * @param env\n *   Specifies the environment (stack context) to be used to jump back\n *   upon abort.  If null, the transaction will continue even after\n *   abort and the application should explicitely check its status.  If\n *   the transaction is nested, this parameter is ignored as an abort\n *   will restart the top-level transaction (flat nesting).\n * @param attr\n *   Specifies optional attributes associated to the transaction.  If\n *   null, the transaction uses default attributes.\n * @param type\n *   Specifies the type of the transaction. If null, the transaction is \n *   normal.\n */\nvoid stm_start(TXPARAMS sigjmp_buf *env, stm_tx_attr_t *attr, int type);\t\n\t\n/**\n * Try to commit the current transaction.  If successful, the function \n * returns 1. Otherwise, execution continues at the point specified by \n * the environment passed as parameter to stm_start() (for the outermost\n * transaction upon nesting).  If the environment was null, the function\n * returns 0 if commit is unsuccessful.\n */\nint stm_commit(TXPARAM);\n\t\n/**\n * Explicitly abort the transaction.  Execution continues at the point\n * specified by the environment passed as parameter to stm_start() (for\n * the outermost transaction upon nesting), unless the environment was\n * null.\n */\nvoid stm_abort(TXPARAM);\n\t\n/**\n * Transactional load whose execution depends on the current transaction \n * type, elastic or normal:\n * \n * Elastic transactional load.  Read the specified memory location in the\n * context of the current transaction and return its value. If not \n * preceded by a write operation in the same transaction, this operation\n * success depends only on the previous read operation (if it exists).\n * For further details about cases where an elastic transaction aborts\n * see the EPFL technical report about Elastic Transactions,\n * #LPD-REPORT-2009-002.\n *\n * Normal transactional load.  Read the specified memory location in the\n * context of the current transaction and return its value. The \n * transaction may abort while reading the memory location. Note that the \n * value returned is consistent with respect to previous reads from the \n * same transaction.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nstm_word_t stm_load(TXPARAMS volatile stm_word_t *addr);\n\t\n/**\n * Transactional store whose execution depends on the current transaction \n * type, elastic or normal:\n *\n * Elastic transactional store.  Write a word-sized value to the \n * specified memory location in the context of the current transaction.  \n * If this operation is the first write operation of the current \n * transaction, then its success depends only on the previous read \n * operation that occurred in the same transaction. See the EPFL \n * technical report about Elastic Transactions #LPD-REPORT-2009-002,\n * for further details.\n *\n * Normal transactional store.  Write a word-sized value to the \n * specified memory location in the context of the current transaction.  \n * The transaction may abort while writing to the memory location.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store(TXPARAMS volatile stm_word_t *addr, stm_word_t value);\n\n/**\n * Transactional store, writes a value to the specified memory location\n * in the context of the current transaction.  The value may be smaller\n * than a word on the target architecture, in which case a mask is used\n * to indicate the bits of the words that must be updated.  \n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n * @param mask\n *   Mask specifying the bits to be written.\n */\nvoid stm_store2(TXPARAMS volatile stm_word_t *addr, stm_word_t value, stm_word_t mask);\n\n/**\n * Check if the current transaction is still active.\n *\n * @return\n *   True (non-zero) if the transaction is active, false (zero) otherwise.\n */\nint stm_active(TXPARAM);\n\n/**\n * Check if the current transaction has aborted.\n *\n * @return\n *   True (non-zero) if the transaction has aborted, false (zero) otherwise.\n */\nint stm_aborted(TXPARAM);\n\n/**\n * Get the environment used by the current thread to jump back upon\n * abort.  This environment should be used when calling sigsetjmp()\n * before starting the transaction and passed as parameter to\n * stm_start().  If the current thread is already executing a\n * transaction, i.e., the new transaction will be nested, the function\n * returns NULL and one should not call sigsetjmp().\n *\n * @return\n *   The environment to use for saving the stack context, or NULL if the\n *   transaction is nested.\n */\nsigjmp_buf *stm_get_env(TXPARAM);\n\n/**\n * Get attributes associated with the current transactions, if any.\n * These attributes were passed as parameters when starting the\n * transaction.\n *\n * @return Attributes associated with the current transaction, or NULL\n *   if no attributes were specified when starting the transaction.\n */\nstm_tx_attr_t *stm_get_attributes(TXPARAM);\n\n/**\n * Get various statistics about the current thread/transaction.  See the\n * source code (stm.c) for a list of supported statistics.\n *\n * @param name\n *   Name of the statistics.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   statistics.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_stats(TXPARAMS const char *name, void *val);\n\n/**\n * Get various parameters of the STM library.  See the source code\n * (stm.c) for a list of supported parameters.\n *\n * @param name\n *   Name of the parameter.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   parameter.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_parameter(const char *name, void *val);\n\n/**\n * Set various parameters of the STM library.  See the source code\n * (stm.c) for a list of supported parameters.\n *\n * @param name\n *   Name of the parameter.\n * @param val\n *   Pointer to a variable that holds the new value of the parameter.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_set_parameter(const char *name, void *val);\n\n/**\n * Create a key to associate application-specific data to the current\n * thread/transaction.  This mechanism can be combined with callbacks to\n * write modules.\n *\n * @return\n *   The new key.\n */\nint stm_create_specific();\n\n/**\n * Get application-specific data associated to the current\n * thread/transaction and a given key.\n *\n * @param key\n *   Key designating the data to read.\n * @return\n *   Data stored under the given key.\n */\nvoid *stm_get_specific(TXPARAMS int key);\n\n/**\n * Set application-specific data associated to the current\n * thread/transaction and a given key.\n *\n * @param key\n *   Key designating the data to read.\n * @param data\n *   Data to store under the given key.\n */\nvoid stm_set_specific(TXPARAMS int key, void *data);\n\n/**\n * Register application-specific callbacks that are triggered when\n * particular events occur.\n *\n * @param on_thread_init\n *   Function called upon initialization of a transactional thread.\n * @param on_thread_exit\n *   Function called upon cleanup of a transactional thread.\n * @param on_start\n *   Function called upon start of a transaction.\n * @param on_commit\n *   Function called upon successful transaction commit.\n * @param on_abort\n *   Function called upon transaction abort.\n * @param arg\n *   Parameter to be passed to the callback functions.\n * @return\n *   1 if the callbacks have been successfully registered, 0 otherwise.\n */\nint stm_register(void (*on_thread_init)(TXPARAMS void *arg),\n                 void (*on_thread_exit)(TXPARAMS void *arg),\n                 void (*on_start)(TXPARAMS void *arg),\n                 void (*on_commit)(TXPARAMS void *arg),\n                 void (*on_abort)(TXPARAMS void *arg),\n                 void *arg);\n\n/**\n * Read the current value of the global clock (used for timestamps).\n * This function is useful when programming with unit loads and stores.\n *\n * @return\n *   Value of the global clock.\n */\nstm_word_t stm_get_clock();\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _STM_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/include/wrappers.h",
    "content": "/*\n * File:\n *   wrappers.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   STM wrapper functions for different data types.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n/**\n * @file\n *   STM wrapper functions for different data types.  This library\n *   defines transactional loads/store functions for unsigned data types\n *   of various sizes and for basic C data types.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n * @date\n *   2007-2009\n */\n\n#ifndef _WRAPPERS_H_\n# define _WRAPPERS_H_\n\n# include <stdint.h>\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Transactional load of an unsigned 8-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint8_t stm_load8(TXPARAMS volatile uint8_t *addr);\n\n/**\n * Transactional load of an unsigned 16-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint16_t stm_load16(TXPARAMS volatile uint16_t *addr);\n\n/**\n * Transactional load of an unsigned 32-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint32_t stm_load32(TXPARAMS volatile uint32_t *addr);\n\n/**\n * Transactional load of an unsigned 64-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint64_t stm_load64(TXPARAMS volatile uint64_t *addr);\n\n/**\n * Transactional load of a char value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nchar stm_load_char(TXPARAMS volatile char *addr);\n\n/**\n * Transactional load of an unsigned char value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned char stm_load_uchar(TXPARAMS volatile unsigned char *addr);\n\n/**\n * Transactional load of a short value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nshort stm_load_short(TXPARAMS volatile short *addr);\n\n/**\n * Transactional load of an unsigned short value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned short stm_load_ushort(TXPARAMS volatile unsigned short *addr);\n\n/**\n * Transactional load of an int value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nint stm_load_int(TXPARAMS volatile int *addr);\n\n/**\n * Transactional load of an unsigned int value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned int stm_load_uint(TXPARAMS volatile unsigned int *addr);\n\n/**\n * Transactional load of a long value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nlong stm_load_long(TXPARAMS volatile long *addr);\n\n/**\n * Transactional load of an unsigned long value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned long stm_load_ulong(TXPARAMS volatile unsigned long *addr);\n\n/**\n * Transactional load of a float value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nfloat stm_load_float(TXPARAMS volatile float *addr);\n\n/**\n * Transactional load of a double value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\ndouble stm_load_double(TXPARAMS volatile double *addr);\n\n/**\n * Transactional load of a pointer value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nvoid *stm_load_ptr(TXPARAMS volatile void **addr);\n\n/**\n * Transactional load of a memory region.  The address of the region\n * does not need to be word aligned and its size may be longer than a\n * word.  The values are copied into the provided buffer, which must be\n * allocated by the caller.\n *\n * @param addr\n *   Address of the memory location.\n * @param buf\n *   Buffer for storing the read bytes.\n * @param size\n *   Number of bytes to read.\n */\nvoid stm_load_bytes(TXPARAMS volatile uint8_t *addr, uint8_t *buf, size_t size);\n\n/**\n * Transactional store of an unsigned 8-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store8(TXPARAMS volatile uint8_t *addr, uint8_t value);\n\n/**\n * Transactional store of an unsigned 16-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store16(TXPARAMS volatile uint16_t *addr, uint16_t value);\n\n/**\n * Transactional store of an unsigned 32-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store32(TXPARAMS volatile uint32_t *addr, uint32_t value);\n\n/**\n * Transactional store of an unsigned 64-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store64(TXPARAMS volatile uint64_t *addr, uint64_t value);\n\n/**\n * Transactional store of a char value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_char(TXPARAMS volatile char *addr, char value);\n\n/**\n * Transactional store of an unsigned char value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_uchar(TXPARAMS volatile unsigned char *addr, unsigned char value);\n\n/**\n * Transactional store of a short value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_short(TXPARAMS volatile short *addr, short value);\n\n/**\n * Transactional store of an unsigned short value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_ushort(TXPARAMS volatile unsigned short *addr, unsigned short value);\n\n/**\n * Transactional store of an int value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_int(TXPARAMS volatile int *addr, int value);\n\n/**\n * Transactional store of an unsigned int value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_uint(TXPARAMS volatile unsigned int *addr, unsigned int value);\n\n/**\n * Transactional store of a long value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_long(TXPARAMS volatile long *addr, long value);\n\n/**\n * Transactional store of an unsigned long value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_ulong(TXPARAMS volatile unsigned long *addr, unsigned long value);\n\n/**\n * Transactional store of a float value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_float(TXPARAMS volatile float *addr, float value);\n\n/**\n * Transactional store of a double value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_double(TXPARAMS volatile double *addr, double value);\n\n/**\n * Transactional store of a pointer value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_ptr(TXPARAMS volatile void **addr, void *value);\n\n/**\n * Transactional store of a memory region.  The address of the region\n * does not need to be word aligned and its size may be longer than a\n * word.  The values are copied from the provided buffer.\n *\n * @param addr\n *   Address of the memory location.\n * @param buf\n *   Buffer with the bytes to write.\n * @param size\n *   Number of bytes to write.\n */\nvoid stm_store_bytes(TXPARAMS volatile uint8_t *addr, uint8_t *buf, size_t size);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _WRAPPERS_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic.h",
    "content": "/*\n * File:\n *   atomic.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Atomic operations.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#ifndef _ATOMIC_H_\n# define _ATOMIC_H_\n\n# include <atomic_ops.h>\n\ntypedef AO_t atomic_t;\n\n# ifdef NO_AO\n/* Use only for testing purposes (single thread benchmarks) */\n#  define ATOMIC_CAS_FULL(a, e, v)      (*(a) = (v), 1)\n#  define ATOMIC_FETCH_INC_FULL(a)      ((*(a))++)\n#  define ATOMIC_FETCH_DEC_FULL(a)      ((*(a))--)\n#  define ATOMIC_FETCH_ADD_FULL(a, v)   ((*(a)) += (v))\n#  define ATOMIC_LOAD_ACQ(a)            (*(a))\n#  define ATOMIC_LOAD(a)                (*(a))\n#  define ATOMIC_STORE_REL(a, v)        (*(a) = (v))\n#  define ATOMIC_STORE(a, v)            (*(a) = (v))\n#  define ATOMIC_MB_READ                /* Nothing */\n#  define ATOMIC_MB_WRITE               /* Nothing */\n#  define ATOMIC_MB_FULL                /* Nothing */\n# else /* ! NO_AO */\n#  define ATOMIC_CAS_FULL(a, e, v)      (AO_compare_and_swap_full((volatile AO_t *)(a), (AO_t)(e), (AO_t)(v)))\n#  define ATOMIC_FETCH_INC_FULL(a)      (AO_fetch_and_add1_full((volatile AO_t *)(a)))\n#  define ATOMIC_FETCH_DEC_FULL(a)      (AO_fetch_and_sub1_full((volatile AO_t *)(a)))\n#  define ATOMIC_FETCH_ADD_FULL(a, v)   (AO_fetch_and_add_full((volatile AO_t *)(a), (AO_t)(v)))\n#  ifdef SAFE\n#   define ATOMIC_LOAD_ACQ(a)           (AO_load_full((volatile AO_t *)(a)))\n#   define ATOMIC_LOAD(a)               (AO_load_full((volatile AO_t *)(a)))\n#   define ATOMIC_STORE_REL(a, v)       (AO_store_full((volatile AO_t *)(a), (AO_t)(v)))\n#   define ATOMIC_STORE(a, v)           (AO_store_full((volatile AO_t *)(a), (AO_t)(v)))\n#   define ATOMIC_MB_READ               AO_nop_full()\n#   define ATOMIC_MB_WRITE              AO_nop_full()\n#   define ATOMIC_MB_FULL               AO_nop_full()\n#  else /* ! SAFE */\n#   define ATOMIC_LOAD_ACQ(a)           (AO_load_acquire_read((volatile AO_t *)(a)))\n#   define ATOMIC_LOAD(a)               (*((volatile AO_t *)(a)))\n#   define ATOMIC_STORE_REL(a, v)       (AO_store_release((volatile AO_t *)(a), (AO_t)(v)))\n#   define ATOMIC_STORE(a, v)           (*((volatile AO_t *)(a)) = (AO_t)(v))\n#   define ATOMIC_MB_READ               AO_nop_read()\n#   define ATOMIC_MB_WRITE              AO_nop_write()\n#   define ATOMIC_MB_FULL               AO_nop_full()\n#  endif /* ! SAFE */\n# endif /* ! NO_AO */\n\n#endif /* _ATOMIC_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/AUTHORS",
    "content": "Originally written by Hans Boehm, with some platform-dependent code\nimported from the Boehm-Demers-Weiser GC, where it was contributed\nby many others.\n\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/COPYING",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year  name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/README",
    "content": "This directory contains a stripped-down (support only gcc) version of libatomic_ops by Hans Boehm.\nThe official release is available from http://www.hpl.hp.com/research/linux/atomic_ops/.\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/aligned_atomic_load_store.h",
    "content": "/*\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * Definitions for architectures on which loads and stores of AO_t are\n * atomic fo all legal alignments.\n */\n\nAO_INLINE AO_t\nAO_load(const volatile AO_t *addr)\n{\n  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);\n  /* Cast away the volatile for architectures where             */\n  /* volatile adds barrier semantics.                           */\n  return *(AO_t *)addr;\n}\n\n#define AO_HAVE_load\n\nAO_INLINE void\nAO_store(volatile AO_t *addr, AO_t new_val)\n{\n  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);\n  (*(AO_t *)addr) = new_val;\n}\n\n#define AO_HAVE_store\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/all_acquire_release_volatile.h",
    "content": "/*\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE. \n */\n\n/*\n * Describes architectures on which volatile AO_t, unsigned char, unsigned\n * short, and unsigned int loads and stores have acquire/release semantics for\n * all normally legal alignments.\n */\n//#include \"acquire_release_volatile.h\"\n//#include \"char_acquire_release_volatile.h\"\n//#include \"short_acquire_release_volatile.h\"\n//#include \"int_acquire_release_volatile.h\"\n\n/*\n * This file adds definitions appropriate for environments in which an AO_t\n * volatile load has acquire semantics, and an AO_t volatile store has release\n * semantics.  This is arguably supposed to be true with the standard Itanium\n * software conventions.\n */\n\n/*\n * Empirically gcc/ia64 does some reordering of ordinary operations around volatiles\n * even when we think it shouldn't.  Gcc 3.3 and earlier could reorder a volatile store\n * with another store.  As of March 2005, gcc pre-4 reused previously computed\n * common subexpressions across a volatile load.\n * Hence we now add compiler barriers for gcc.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE AO_t\nAO_load_acquire(const volatile AO_t *p)\n{\n  AO_t result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_load_acquire\n\nAO_INLINE void\nAO_store_release(volatile AO_t *p, AO_t val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_store_release\n\n/*\n * This file adds definitions appropriate for environments in which an unsigned char\n * volatile load has acquire semantics, and an unsigned char volatile store has release\n * semantics.  This is true with the standard Itanium ABI.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE unsigned char\nAO_char_load_acquire(const volatile unsigned char *p)\n{\n  unsigned char result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_char_load_acquire\n\nAO_INLINE void\nAO_char_store_release(volatile unsigned char *p, unsigned char val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_char_store_release\n\n/*\n * This file adds definitions appropriate for environments in which an unsigned short\n * volatile load has acquire semantics, and an unsigned short volatile store has release\n * semantics.  This is true with the standard Itanium ABI.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE unsigned short\nAO_short_load_acquire(const volatile unsigned short *p)\n{\n  unsigned short result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_short_load_acquire\n\nAO_INLINE void\nAO_short_store_release(volatile unsigned short *p, unsigned short val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_short_store_release\n\n/*\n * This file adds definitions appropriate for environments in which an unsigned\n * int volatile load has acquire semantics, and an unsigned short volatile\n * store has release semantics.  This is true with the standard Itanium ABI.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE unsigned int\nAO_int_load_acquire(const volatile unsigned int *p)\n{\n  unsigned int result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_int_load_acquire\n\nAO_INLINE void\nAO_int_store_release(volatile unsigned int *p, unsigned int val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_int_store_release\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/ao_t_is_int.h",
    "content": "/*\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * Inclusion of this file signifies that AO_t is in fact int.  Hence\n * any AO_... operations can also server as AO_int_... operations.\n * We currently define only the more important ones here, and allow for\n * the normal generalization process to define the others.\n * We should probably add others in the future.\n */\n\n#if defined(AO_HAVE_compare_and_swap_full) && \\\n    !defined(AO_HAVE_int_compare_and_swap_full)\n#  define AO_int_compare_and_swap_full(addr, old, new_val) \\\n                AO_compare_and_swap_full((volatile AO_t *)(addr), \\\n                                        (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_full\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_int_compare_and_swap_acquire)\n#  define AO_int_compare_and_swap_acquire(addr, old, new_val) \\\n                AO_compare_and_swap_acquire((volatile AO_t *)(addr), \\\n                                            (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_acquire\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_release) && \\\n    !defined(AO_HAVE_int_compare_and_swap_release)\n#  define AO_int_compare_and_swap_release(addr, old, new_val) \\\n                AO_compare_and_swap_release((volatile AO_t *)(addr), \\\n                                         (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_release\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_write) && \\\n    !defined(AO_HAVE_int_compare_and_swap_write)\n#  define AO_int_compare_and_swap_write(addr, old, new_val) \\\n                AO_compare_and_swap_write((volatile AO_t *)(addr), \\\n                                          (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_write\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_read) && \\\n    !defined(AO_HAVE_int_compare_and_swap_read)\n#  define AO_int_compare_and_swap_read(addr, old, new_val) \\\n                AO_compare_and_swap_read((volatile AO_t *)(addr), \\\n                                         (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_read\n# endif\n\n#if defined(AO_HAVE_compare_and_swap) && \\\n    !defined(AO_HAVE_int_compare_and_swap)\n#  define AO_int_compare_and_swap(addr, old, new_val) \\\n                AO_compare_and_swap((volatile AO_t *)(addr), \\\n                                    (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap\n# endif\n\n#if defined(AO_HAVE_load_acquire) && \\\n    !defined(AO_HAVE_int_load_acquire)\n#  define AO_int_load_acquire(addr) \\\n        (int)AO_load_acquire((const volatile AO_t *)(addr))\n#  define AO_HAVE_int_load_acquire\n# endif\n\n#if defined(AO_HAVE_store_release) && \\\n    !defined(AO_HAVE_int_store_release)\n#  define AO_int_store_release(addr, val) \\\n        AO_store_release((volatile AO_t *)(addr), (AO_t)(val))\n#  define AO_HAVE_int_store_release\n# endif\n\n#if defined(AO_HAVE_fetch_and_add_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add_full)\n#  define AO_int_fetch_and_add_full(addr, incr) \\\n        (int)AO_fetch_and_add_full((volatile AO_t *)(addr), (AO_t)(incr))\n#  define AO_HAVE_int_fetch_and_add_full\n# endif\n\n#if defined(AO_HAVE_fetch_and_add1_acquire) && \\\n    !defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1_acquire(addr) \\\n        (int)AO_fetch_and_add1_acquire((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_add1_acquire\n# endif\n\n#if defined(AO_HAVE_fetch_and_add1_release) && \\\n    !defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1_release(addr) \\\n        (int)AO_fetch_and_add1_release((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_add1_release\n# endif\n\n#if defined(AO_HAVE_fetch_and_sub1_acquire) && \\\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1_acquire(addr) \\\n        (int)AO_fetch_and_sub1_acquire((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_sub1_acquire\n# endif\n\n#if defined(AO_HAVE_fetch_and_sub1_release) && \\\n    !defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1_release(addr) \\\n        (int)AO_fetch_and_sub1_release((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_sub1_release\n# endif\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/atomic_ops.h",
    "content": "/*\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef ATOMIC_OPS_H\n\n#define ATOMIC_OPS_H\n\n#include <assert.h>\n#include <stddef.h>\n\n/* We define various atomic operations on memory in a           */\n/* machine-specific way.  Unfortunately, this is complicated    */\n/* by the fact that these may or may not be combined with       */\n/* various memory barriers.  Thus the actual operations we      */\n/* define have the form AO_<atomic-op>_<barrier>, for all       */\n/* plausible combinations of <atomic-op> and <barrier>.         */\n/* This of course results in a mild combinatorial explosion.    */\n/* To deal with it, we try to generate derived                  */\n/* definitions for as many of the combinations as we can, as    */\n/* automatically as possible.                                   */\n/*                                                              */\n/* Our assumption throughout is that the programmer will        */\n/* specify the least demanding operation and memory barrier     */\n/* that will guarantee correctness for the implementation.      */\n/* Our job is to find the least expensive way to implement it   */\n/* on the applicable hardware.  In many cases that will         */\n/* involve, for example, a stronger memory barrier, or a        */\n/* combination of hardware primitives.                          */\n/*                                                              */\n/* Conventions:                                                 */\n/* \"plain\" atomic operations are not guaranteed to include      */\n/* a barrier.  The suffix in the name specifies the barrier     */\n/* type.  Suffixes are:                                         */\n/* _release: Earlier operations may not be delayed past it.     */\n/* _acquire: Later operations may not move ahead of it.         */\n/* _read: Subsequent reads must follow this operation and       */\n/*        preceding reads.                                      */\n/* _write: Earlier writes precede both this operation and       */\n/*        later writes.                                         */\n/* _full: Ordered with respect to both earlier and later memops.*/\n/* _release_write: Ordered with respect to earlier writes.      */\n/* _acquire_read: Ordered with respect to later reads.          */\n/*                                                              */\n/* Currently we try to define the following atomic memory       */\n/* operations, in combination with the above barriers:          */\n/* AO_nop                                                       */\n/* AO_load                                                      */\n/* AO_store                                                     */\n/* AO_test_and_set (binary)                                     */\n/* AO_fetch_and_add                                             */\n/* AO_fetch_and_add1                                            */\n/* AO_fetch_and_sub1                                            */\n/* AO_or                                                        */\n/* AO_compare_and_swap                                          */\n/*                                                              */\n/* Note that atomicity guarantees are valid only if both        */\n/* readers and writers use AO_ operations to access the         */\n/* shared value, while ordering constraints are intended to     */\n/* apply all memory operations.  If a location can potentially  */\n/* be accessed simultaneously from multiple threads, and one of */\n/* those accesses may be a write access, then all such          */\n/* accesses to that location should be through AO_ primitives.  */\n/* However if AO_ operations enforce sufficient ordering to     */\n/* ensure that a location x cannot be accessed concurrently,    */\n/* or can only be read concurrently, then x can be accessed     */\n/* via ordinary references and assignments.                     */\n/*                                                              */\n/* Compare_and_exchange takes an address and an expected old    */\n/* value and a new value, and returns an int.  Nonzero          */\n/* indicates that it succeeded.                                 */\n/* Test_and_set takes an address, atomically replaces it by     */\n/* AO_TS_SET, and returns the prior value.                      */\n/* An AO_TS_t location can be reset with the                    */\n/* AO_CLEAR macro, which normally uses AO_store_release.        */\n/* AO_fetch_and_add takes an address and an AO_t increment      */\n/* value.  The AO_fetch_and_add1 and AO_fetch_and_sub1 variants */\n/* are provided, since they allow faster implementations on     */\n/* some hardware. AO_or atomically ors an AO_t value into a     */\n/* memory location, but does not provide access to the original.*/\n/*                                                              */\n/* We expect this list to grow slowly over time.                */\n/*                                                              */\n/* Note that AO_nop_full is a full memory barrier.              */\n/*                                                              */\n/* Note that if some data is initialized with                   */\n/*      data.x = ...; data.y = ...; ...                         */\n/*      AO_store_release_write(&data_is_initialized, 1)         */\n/* then data is guaranteed to be initialized after the test     */\n/*      if (AO_load_release_read(&data_is_initialized)) ...     */\n/* succeeds.  Furthermore, this should generate near-optimal    */\n/* code on all common platforms.                                */\n/*                                                              */\n/* All operations operate on unsigned AO_t, which               */\n/* is the natural word size, and usually unsigned long.         */\n/* It is possible to check whether a particular operation op    */\n/* is available on a particular platform by checking whether    */\n/* AO_HAVE_op is defined.  We make heavy use of these macros    */\n/* internally.                                                  */\n\n/* The rest of this file basically has three sections:          */\n/*                                                              */\n/* Some utility and default definitions.                        */\n/*                                                              */\n/* The architecture dependent section:                          */\n/* This defines atomic operations that have direct hardware     */\n/* support on a particular platform, mostly by including the    */\n/* appropriate compiler- and hardware-dependent file.           */\n/*                                                              */\n/* The synthesis section:                                       */\n/* This tries to define other atomic operations in terms of     */\n/* those that are explicitly available on the platform.         */\n/* This section is hardware independent.                        */\n/* We make no attempt to synthesize operations in ways that     */\n/* effectively introduce locks, except for the debugging/demo   */\n/* pthread-based implementation at the beginning.  A more       */\n/* realistic implementation that falls back to locks could be   */\n/* added as a higher layer.  But that would sacrifice           */\n/* usability from signal handlers.                              */\n/* The synthesis section is implemented almost entirely in      */\n/* atomic_ops_generalize.h.                                     */\n\n/* Some common defaults.  Overridden for some architectures.    */\n#define AO_t size_t\n\n/* The test_and_set primitive returns an AO_TS_VAL_t value.     */\n/* AO_TS_t is the type of an in-memory test-and-set location.   */\n\n#define AO_TS_INITIALIZER (AO_t)AO_TS_CLEAR\n\n/* Platform-dependent stuff:                                    */\n#if defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER) \\\n        || defined(__DMC__) || defined(__WATCOMC__)\n# define AO_INLINE static __inline\n#elif defined(__sun)\n# define AO_INLINE static inline\n#else\n# define AO_INLINE static\n#endif\n\n#if defined(__GNUC__) && !defined(__INTEL_COMPILER)\n# define AO_compiler_barrier() __asm__ __volatile__(\"\" : : : \"memory\")\n#elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \\\n        || defined(__WATCOMC__)\n# if defined(_AMD64_) || defined(_M_X64) || _MSC_VER >= 1400\n#   if defined(_WIN32_WCE)\n/* #     include <cmnintrin.h> */\n#   elif defined(_MSC_VER)\n#     include <intrin.h>\n#   endif\n#   pragma intrinsic(_ReadWriteBarrier)\n#   define AO_compiler_barrier() _ReadWriteBarrier()\n        /* We assume this does not generate a fence instruction.        */\n        /* The documentation is a bit unclear.                          */\n# else\n#   define AO_compiler_barrier() __asm { }\n        /* The preceding implementation may be preferable here too.     */\n        /* But the documentation warns about VC++ 2003 and earlier.     */\n# endif\n#elif defined(__INTEL_COMPILER)\n# define AO_compiler_barrier() __memory_barrier() /* Too strong? IA64-only? */\n#elif defined(_HPUX_SOURCE)\n# if defined(__ia64)\n#   include <machine/sys/inline.h>\n#   define AO_compiler_barrier() _Asm_sched_fence()\n# else\n    /* FIXME - We dont know how to do this.  This is a guess.   */\n    /* And probably a bad one.                                  */\n    static volatile int AO_barrier_dummy;\n#   define AO_compiler_barrier() AO_barrier_dummy = AO_barrier_dummy\n# endif\n#else\n  /* We conjecture that the following usually gives us the right        */\n  /* semantics or an error.                                             */\n# define AO_compiler_barrier() asm(\"\")\n#endif\n\n#if defined(AO_USE_PTHREAD_DEFS)\n# include \"atomic_ops/sysdeps/generic_pthread.h\"\n#endif /* AO_USE_PTHREAD_DEFS */\n\n#if defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS) \\\n    && !defined(__INTEL_COMPILER)\n# if defined(__i386__)\n    /* We don't define AO_USE_SYNC_CAS_BUILTIN for x86 here because     */\n    /* it might require specifying additional options (like -march)     */\n    /* or additional link libraries (if -march is not specified).       */\n#   include \"./x86.h\"\n# endif /* __i386__ */\n# if defined(__x86_64__)\n#   if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)\n      /* It is safe to use __sync CAS built-in on this architecture.    */\n#     define AO_USE_SYNC_CAS_BUILTIN\n#   endif\n#   include \"./x86_64.h\"\n# endif /* __x86_64__ */\n# if defined(__ia64__)\n#   include \"./ia64.h\"\n#   define AO_GENERALIZE_TWICE\n# endif /* __ia64__ */\n# if defined(__hppa__)\n#   include \"atomic_ops/sysdeps/gcc/hppa.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __hppa__ */\n# if defined(__alpha__)\n#   include \"atomic_ops/sysdeps/gcc/alpha.h\"\n#   define AO_GENERALIZE_TWICE\n# endif /* __alpha__ */\n# if defined(__s390__)\n#   include \"atomic_ops/sysdeps/gcc/s390.h\"\n# endif /* __s390__ */\n# if defined(__sparc__)\n#   include \"./sparc.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __sparc__ */\n# if defined(__m68k__)\n#   include \"atomic_ops/sysdeps/gcc/m68k.h\"\n# endif /* __m68k__ */\n# if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \\\n     || defined(__powerpc64__) || defined(__ppc64__)\n#   include \"./powerpc.h\"\n# endif /* __powerpc__ */\n# if defined(__arm__) && !defined(AO_USE_PTHREAD_DEFS)\n#   include \"atomic_ops/sysdeps/gcc/arm.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __arm__ */\n# if defined(__cris__) || defined(CRIS)\n#   include \"atomic_ops/sysdeps/gcc/cris.h\"\n# endif\n# if defined(__mips__)\n#   include \"atomic_ops/sysdeps/gcc/mips.h\"\n# endif /* __mips__ */\n# if defined(__sh__) || defined(SH4)\n#   include \"atomic_ops/sysdeps/gcc/sh.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __sh__ */\n#endif /* __GNUC__ && !AO_USE_PTHREAD_DEFS */\n\n#if defined(__INTEL_COMPILER) && !defined(AO_USE_PTHREAD_DEFS)\n# if defined(__ia64__)\n#   include \"./ia64.h\"\n#   define AO_GENERALIZE_TWICE\n# endif\n# if defined(__GNUC__)\n    /* Intel Compiler in GCC compatible mode */\n#   if defined(__i386__)\n#     include \"./x86.h\"\n#   endif /* __i386__ */\n#   if defined(__x86_64__)\n#     if __INTEL_COMPILER > 1110\n#       define AO_USE_SYNC_CAS_BUILTIN\n#     endif\n#     include \"./x86_64.h\"\n#   endif /* __x86_64__ */\n# endif\n#endif\n\n#if defined(_HPUX_SOURCE) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)\n# if defined(__ia64)\n#   include \"atomic_ops/sysdeps/hpc/ia64.h\"\n#   define AO_GENERALIZE_TWICE\n# else\n#   include \"atomic_ops/sysdeps/hpc/hppa.h\"\n#   define AO_CAN_EMUL_CAS\n# endif\n#endif\n\n#if defined(__sun) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)\n  /* Note: use -DAO_USE_PTHREAD_DEFS if Sun CC does not handle inline asm. */\n# if defined(__i386)\n#   include \"atomic_ops/sysdeps/sunc/x86.h\"\n# endif /* __i386 */\n# if defined(__x86_64) || defined(__amd64)\n#   include \"atomic_ops/sysdeps/sunc/x86_64.h\"\n# endif /* __x86_64 */\n#endif\n\n#if !defined(__GNUC__) && (defined(sparc) || defined(__sparc)) \\\n    && !defined(AO_USE_PTHREAD_DEFS)\n#   include \"atomic_ops/sysdeps/sunc/sparc.h\"\n#   define AO_CAN_EMUL_CAS\n#endif\n\n#if defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \\\n        || (defined(__WATCOMC__) && defined(__NT__))\n# if defined(_AMD64_) || defined(_M_X64)\n#   include \"atomic_ops/sysdeps/msftc/x86_64.h\"\n# elif defined(_M_IX86) || defined(x86)\n#   include \"atomic_ops/sysdeps/msftc/x86.h\"\n# elif defined(_M_ARM) || defined(ARM) || defined(_ARM_)\n#   include \"atomic_ops/sysdeps/msftc/arm.h\"\n# endif\n#endif\n\n#if defined(AO_REQUIRE_CAS) && !defined(AO_HAVE_compare_and_swap) \\\n    && !defined(AO_HAVE_compare_and_swap_full) \\\n    && !defined(AO_HAVE_compare_and_swap_acquire)\n# if defined(AO_CAN_EMUL_CAS)\n#   include \"atomic_ops/sysdeps/emul_cas.h\"\n# else\n#  error Cannot implement AO_compare_and_swap_full on this architecture.\n# endif\n#endif  /* AO_REQUIRE_CAS && !AO_HAVE_compare_and_swap ... */\n\n/* The most common way to clear a test-and-set location         */\n/* at the end of a critical section.                            */\n#if AO_AO_TS_T && !defined(AO_CLEAR)\n# define AO_CLEAR(addr) AO_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)\n#endif\n#if AO_CHAR_TS_T && !defined(AO_CLEAR)\n# define AO_CLEAR(addr) AO_char_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)\n#endif\n\n/*\n * The generalization section.\n * Theoretically this should repeatedly include atomic_ops_generalize.h.\n * In fact, we observe that this converges after a small fixed number\n * of iterations, usually one.\n */\n#include \"./generalize.h\"\n#ifdef AO_GENERALIZE_TWICE\n# include \"./generalize.h\"\n#endif\n\n/* For compatibility with version 0.4 and earlier       */\n#define AO_TS_T AO_TS_t\n#define AO_T AO_t\n#define AO_TS_VAL AO_TS_VAL_t\n\n#endif /* ATOMIC_OPS_H */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/generalize-small.h",
    "content": "/* char_load */\n#if defined(AO_HAVE_char_load_acquire) && !defined(AO_HAVE_char_load)\n#  define AO_char_load(addr) AO_char_load_acquire(addr)\n#  define AO_HAVE_char_load\n#endif\n\n#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_acquire)\n#  define AO_char_load_acquire(addr) AO_char_load_full(addr)\n#  define AO_HAVE_char_load_acquire\n#endif\n\n#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_read)\n#  define AO_char_load_read(addr) AO_char_load_full(addr)\n#  define AO_HAVE_char_load_read\n#endif\n\n#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_acquire)\n#  define AO_char_load_acquire_read(addr) AO_char_load_acquire(addr)\n#  define AO_HAVE_char_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_load_acquire)\n   AO_INLINE unsigned char\n   AO_char_load_acquire(const volatile unsigned char *addr)\n   {\n     unsigned char result = AO_char_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_char_load_acquire\n#endif\n\n#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_char_load_read)\n   AO_INLINE unsigned char\n   AO_char_load_read(const volatile unsigned char *addr)\n   {\n     unsigned char result = AO_char_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_char_load_read\n#endif\n\n#if defined(AO_HAVE_char_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_load_full)\n#  define AO_char_load_full(addr) (AO_nop_full(), AO_char_load_acquire(addr))\n#  define AO_HAVE_char_load_full\n#endif\n\n#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_read)\n#  define AO_char_load_acquire_read(addr) AO_char_load_read(addr)\n#  define AO_HAVE_char_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_char_load_acquire_read) && !defined(AO_HAVE_char_load)\n#  define AO_char_load(addr) AO_char_load_acquire_read(addr)\n#  define AO_HAVE_char_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_load_acquire_read)\n#    define AO_char_load_dd_acquire_read(addr) \\\n        AO_char_load_acquire_read(addr)\n#    define AO_HAVE_char_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_load)\n#    define AO_char_load_dd_acquire_read(addr) \\\n        AO_char_load(addr)\n#    define AO_HAVE_char_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* char_store */\n\n#if defined(AO_HAVE_char_store_release) && !defined(AO_HAVE_char_store)\n#  define AO_char_store(addr, val) AO_char_store_release(addr,val)\n#  define AO_HAVE_char_store\n#endif\n\n#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_release)\n#  define AO_char_store_release(addr,val) AO_char_store_full(addr,val)\n#  define AO_HAVE_char_store_release\n#endif\n\n#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_write)\n#  define AO_char_store_write(addr,val) AO_char_store_full(addr,val)\n#  define AO_HAVE_char_store_write\n#endif\n\n#if defined(AO_HAVE_char_store_release) && \\\n        !defined(AO_HAVE_char_store_release_write)\n#  define AO_char_store_release_write(addr, val) \\\n        AO_char_store_release(addr,val)\n#  define AO_HAVE_char_store_release_write\n#endif\n\n#if defined(AO_HAVE_char_store_write) && !defined(AO_HAVE_char_store)\n#  define AO_char_store(addr, val) AO_char_store_write(addr,val)\n#  define AO_HAVE_char_store\n#endif\n\n#if defined(AO_HAVE_char_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_store_release)\n#  define AO_char_store_release(addr,val) \\\n        (AO_nop_full(), AO_char_store(addr,val))\n#  define AO_HAVE_char_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_char_store) && \\\n     !defined(AO_HAVE_char_store_write)\n#  define AO_char_store_write(addr, val) \\\n        (AO_nop_write(), AO_char_store(addr,val))\n#  define AO_HAVE_char_store_write\n#endif\n\n#if defined(AO_HAVE_char_store_write) && \\\n     !defined(AO_HAVE_char_store_release_write)\n#  define AO_char_store_release_write(addr, val) AO_char_store_write(addr,val)\n#  define AO_HAVE_char_store_release_write\n#endif\n\n#if defined(AO_HAVE_char_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_store_full)\n#  define AO_char_store_full(addr, val) \\\n        (AO_char_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_char_store_full\n#endif\n\n\n/* char_fetch_and_add */\n#if defined(AO_HAVE_char_compare_and_swap_full) && \\\n    !defined(AO_HAVE_char_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_char_fetch_and_add_full(volatile unsigned char *addr,\n                               unsigned char incr)\n   {\n     unsigned char old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_char_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_char_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_char_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_char_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_char_fetch_and_add_acquire(volatile unsigned char *addr,\n                                  unsigned char incr)\n   {\n     unsigned char old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_char_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_char_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_char_compare_and_swap_release) && \\\n    !defined(AO_HAVE_char_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_char_fetch_and_add_release(volatile unsigned char *addr,\n                                  unsigned char incr)\n   {\n     unsigned char old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_char_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_char_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add_full)\n#  if !defined(AO_HAVE_char_fetch_and_add_release)\n#    define AO_char_fetch_and_add_release(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add_acquire)\n#    define AO_char_fetch_and_add_acquire(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add_write)\n#    define AO_char_fetch_and_add_write(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add_read)\n#    define AO_char_fetch_and_add_read(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_char_fetch_and_add_full */\n\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_release)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_release(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_acquire)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_write)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_write(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_read)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_read(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_fetch_and_add_full)\n#  define AO_char_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_char_fetch_and_add_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add_write)\n#  define AO_char_fetch_and_add_release_write(addr, val) \\\n        AO_char_fetch_and_add_write(addr, val)\n#  define AO_HAVE_char_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add_release)\n#  define AO_char_fetch_and_add_release_write(addr, val) \\\n        AO_char_fetch_and_add_release(addr, val)\n#  define AO_HAVE_char_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add_read)\n#  define AO_char_fetch_and_add_acquire_read(addr, val) \\\n        AO_char_fetch_and_add_read(addr, val)\n#  define AO_HAVE_char_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add_acquire)\n#  define AO_char_fetch_and_add_acquire_read(addr, val) \\\n        AO_char_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_char_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_fetch_and_add_acquire_read)\n#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_char_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_char_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_fetch_and_add)\n#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_char_fetch_and_add(addr, val)\n#    define AO_HAVE_char_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* char_fetch_and_add1 */\n\n#if defined(AO_HAVE_char_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_full)\n#  define AO_char_fetch_and_add1_full(addr) \\\n        AO_char_fetch_and_add_full(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_release)\n#  define AO_char_fetch_and_add1_release(addr) \\\n        AO_char_fetch_and_add_release(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_acquire)\n#  define AO_char_fetch_and_add1_acquire(addr) \\\n        AO_char_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_write)\n#  define AO_char_fetch_and_add1_write(addr) \\\n        AO_char_fetch_and_add_write(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_read)\n#  define AO_char_fetch_and_add1_read(addr) \\\n        AO_char_fetch_and_add_read(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_release_write)\n#  define AO_char_fetch_and_add1_release_write(addr) \\\n        AO_char_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_acquire_read)\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\n        AO_char_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add(addr,1)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add1_full)\n#  if !defined(AO_HAVE_char_fetch_and_add1_release)\n#    define AO_char_fetch_and_add1_release(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add1_acquire)\n#    define AO_char_fetch_and_add1_acquire(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add1_write)\n#    define AO_char_fetch_and_add1_write(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add1_read)\n#    define AO_char_fetch_and_add1_read(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_char_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_release)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_release(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_acquire)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_write)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_write(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_read)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_read(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_fetch_and_add1_full)\n#  define AO_char_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_char_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_char_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add1_write)\n#  define AO_char_fetch_and_add1_release_write(addr) \\\n        AO_char_fetch_and_add1_write(addr)\n#  define AO_HAVE_char_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add1_release)\n#  define AO_char_fetch_and_add1_release_write(addr) \\\n        AO_char_fetch_and_add1_release(addr)\n#  define AO_HAVE_char_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add1_read)\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\n        AO_char_fetch_and_add1_read(addr)\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add1_acquire)\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\n        AO_char_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_fetch_and_add1_acquire_read)\n#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_fetch_and_add1)\n#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_add1(addr)\n#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* char_fetch_and_sub1 */\n\n#if defined(AO_HAVE_char_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_full)\n#  define AO_char_fetch_and_sub1_full(addr) \\\n        AO_char_fetch_and_add_full(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_release)\n#  define AO_char_fetch_and_sub1_release(addr) \\\n        AO_char_fetch_and_add_release(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#  define AO_char_fetch_and_sub1_acquire(addr) \\\n        AO_char_fetch_and_add_acquire(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_write)\n#  define AO_char_fetch_and_sub1_write(addr) \\\n        AO_char_fetch_and_add_write(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_read)\n#  define AO_char_fetch_and_sub1_read(addr) \\\n        AO_char_fetch_and_add_read(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_release_write)\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\n        AO_char_fetch_and_add_release_write(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_acquire_read)\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\n        AO_char_fetch_and_add_acquire_read(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_add(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_char_fetch_and_sub1_release)\n#    define AO_char_fetch_and_sub1_release(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#    define AO_char_fetch_and_sub1_acquire(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_sub1_write)\n#    define AO_char_fetch_and_sub1_write(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_sub1_read)\n#    define AO_char_fetch_and_sub1_read(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_char_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_release)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_release(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_write)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_write(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_read)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_read(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_fetch_and_sub1_full)\n#  define AO_char_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_char_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_char_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_write)\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\n        AO_char_fetch_and_sub1_write(addr)\n#  define AO_HAVE_char_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_release)\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\n        AO_char_fetch_and_sub1_release(addr)\n#  define AO_HAVE_char_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_read)\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\n        AO_char_fetch_and_sub1_read(addr)\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\n        AO_char_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_fetch_and_sub1_acquire_read)\n#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_fetch_and_sub1)\n#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_sub1(addr)\n#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n\n/* short_load */\n#if defined(AO_HAVE_short_load_acquire) && !defined(AO_HAVE_short_load)\n#  define AO_short_load(addr) AO_short_load_acquire(addr)\n#  define AO_HAVE_short_load\n#endif\n\n#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_acquire)\n#  define AO_short_load_acquire(addr) AO_short_load_full(addr)\n#  define AO_HAVE_short_load_acquire\n#endif\n\n#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_read)\n#  define AO_short_load_read(addr) AO_short_load_full(addr)\n#  define AO_HAVE_short_load_read\n#endif\n\n#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_acquire)\n#  define AO_short_load_acquire_read(addr) AO_short_load_acquire(addr)\n#  define AO_HAVE_short_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_load_acquire)\n   AO_INLINE unsigned short\n   AO_short_load_acquire(const volatile unsigned short *addr)\n   {\n     unsigned short result = AO_short_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_short_load_acquire\n#endif\n\n#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_short_load_read)\n   AO_INLINE unsigned short\n   AO_short_load_read(const volatile unsigned short *addr)\n   {\n     unsigned short result = AO_short_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_short_load_read\n#endif\n\n#if defined(AO_HAVE_short_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_load_full)\n#  define AO_short_load_full(addr) (AO_nop_full(), AO_short_load_acquire(addr))\n#  define AO_HAVE_short_load_full\n#endif\n\n#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_read)\n#  define AO_short_load_acquire_read(addr) AO_short_load_read(addr)\n#  define AO_HAVE_short_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_short_load_acquire_read) && !defined(AO_HAVE_short_load)\n#  define AO_short_load(addr) AO_short_load_acquire_read(addr)\n#  define AO_HAVE_short_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_load_acquire_read)\n#    define AO_short_load_dd_acquire_read(addr) \\\n        AO_short_load_acquire_read(addr)\n#    define AO_HAVE_short_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_load)\n#    define AO_short_load_dd_acquire_read(addr) \\\n        AO_short_load(addr)\n#    define AO_HAVE_short_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* short_store */\n\n#if defined(AO_HAVE_short_store_release) && !defined(AO_HAVE_short_store)\n#  define AO_short_store(addr, val) AO_short_store_release(addr,val)\n#  define AO_HAVE_short_store\n#endif\n\n#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_release)\n#  define AO_short_store_release(addr,val) AO_short_store_full(addr,val)\n#  define AO_HAVE_short_store_release\n#endif\n\n#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_write)\n#  define AO_short_store_write(addr,val) AO_short_store_full(addr,val)\n#  define AO_HAVE_short_store_write\n#endif\n\n#if defined(AO_HAVE_short_store_release) && \\\n        !defined(AO_HAVE_short_store_release_write)\n#  define AO_short_store_release_write(addr, val) \\\n        AO_short_store_release(addr,val)\n#  define AO_HAVE_short_store_release_write\n#endif\n\n#if defined(AO_HAVE_short_store_write) && !defined(AO_HAVE_short_store)\n#  define AO_short_store(addr, val) AO_short_store_write(addr,val)\n#  define AO_HAVE_short_store\n#endif\n\n#if defined(AO_HAVE_short_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_store_release)\n#  define AO_short_store_release(addr,val) \\\n        (AO_nop_full(), AO_short_store(addr,val))\n#  define AO_HAVE_short_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_short_store) && \\\n     !defined(AO_HAVE_short_store_write)\n#  define AO_short_store_write(addr, val) \\\n        (AO_nop_write(), AO_short_store(addr,val))\n#  define AO_HAVE_short_store_write\n#endif\n\n#if defined(AO_HAVE_short_store_write) && \\\n     !defined(AO_HAVE_short_store_release_write)\n#  define AO_short_store_release_write(addr, val) AO_short_store_write(addr,val)\n#  define AO_HAVE_short_store_release_write\n#endif\n\n#if defined(AO_HAVE_short_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_store_full)\n#  define AO_short_store_full(addr, val) \\\n        (AO_short_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_short_store_full\n#endif\n\n\n/* short_fetch_and_add */\n#if defined(AO_HAVE_short_compare_and_swap_full) && \\\n    !defined(AO_HAVE_short_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_short_fetch_and_add_full(volatile unsigned short *addr,\n                               unsigned short incr)\n   {\n     unsigned short old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_short_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_short_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_short_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_short_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_short_fetch_and_add_acquire(volatile unsigned short *addr,\n                                  unsigned short incr)\n   {\n     unsigned short old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_short_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_short_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_short_compare_and_swap_release) && \\\n    !defined(AO_HAVE_short_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_short_fetch_and_add_release(volatile unsigned short *addr,\n                                  unsigned short incr)\n   {\n     unsigned short old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_short_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_short_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add_full)\n#  if !defined(AO_HAVE_short_fetch_and_add_release)\n#    define AO_short_fetch_and_add_release(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add_acquire)\n#    define AO_short_fetch_and_add_acquire(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add_write)\n#    define AO_short_fetch_and_add_write(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add_read)\n#    define AO_short_fetch_and_add_read(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_short_fetch_and_add_full */\n\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_release)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_release(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_acquire)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_write)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_write(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_read)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_read(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_fetch_and_add_full)\n#  define AO_short_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_short_fetch_and_add_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add_write)\n#  define AO_short_fetch_and_add_release_write(addr, val) \\\n        AO_short_fetch_and_add_write(addr, val)\n#  define AO_HAVE_short_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add_release)\n#  define AO_short_fetch_and_add_release_write(addr, val) \\\n        AO_short_fetch_and_add_release(addr, val)\n#  define AO_HAVE_short_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add_read)\n#  define AO_short_fetch_and_add_acquire_read(addr, val) \\\n        AO_short_fetch_and_add_read(addr, val)\n#  define AO_HAVE_short_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add_acquire)\n#  define AO_short_fetch_and_add_acquire_read(addr, val) \\\n        AO_short_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_short_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_fetch_and_add_acquire_read)\n#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_short_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_short_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_fetch_and_add)\n#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_short_fetch_and_add(addr, val)\n#    define AO_HAVE_short_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* short_fetch_and_add1 */\n\n#if defined(AO_HAVE_short_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_full)\n#  define AO_short_fetch_and_add1_full(addr) \\\n        AO_short_fetch_and_add_full(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_release)\n#  define AO_short_fetch_and_add1_release(addr) \\\n        AO_short_fetch_and_add_release(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_acquire)\n#  define AO_short_fetch_and_add1_acquire(addr) \\\n        AO_short_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_write)\n#  define AO_short_fetch_and_add1_write(addr) \\\n        AO_short_fetch_and_add_write(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_read)\n#  define AO_short_fetch_and_add1_read(addr) \\\n        AO_short_fetch_and_add_read(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_release_write)\n#  define AO_short_fetch_and_add1_release_write(addr) \\\n        AO_short_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_acquire_read)\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\n        AO_short_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add(addr,1)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add1_full)\n#  if !defined(AO_HAVE_short_fetch_and_add1_release)\n#    define AO_short_fetch_and_add1_release(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add1_acquire)\n#    define AO_short_fetch_and_add1_acquire(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add1_write)\n#    define AO_short_fetch_and_add1_write(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add1_read)\n#    define AO_short_fetch_and_add1_read(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_short_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_release)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_release(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_acquire)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_write)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_write(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_read)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_read(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_fetch_and_add1_full)\n#  define AO_short_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_short_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_short_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add1_write)\n#  define AO_short_fetch_and_add1_release_write(addr) \\\n        AO_short_fetch_and_add1_write(addr)\n#  define AO_HAVE_short_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add1_release)\n#  define AO_short_fetch_and_add1_release_write(addr) \\\n        AO_short_fetch_and_add1_release(addr)\n#  define AO_HAVE_short_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add1_read)\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\n        AO_short_fetch_and_add1_read(addr)\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add1_acquire)\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\n        AO_short_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_fetch_and_add1_acquire_read)\n#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_fetch_and_add1)\n#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_add1(addr)\n#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* short_fetch_and_sub1 */\n\n#if defined(AO_HAVE_short_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_full)\n#  define AO_short_fetch_and_sub1_full(addr) \\\n        AO_short_fetch_and_add_full(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_release)\n#  define AO_short_fetch_and_sub1_release(addr) \\\n        AO_short_fetch_and_add_release(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#  define AO_short_fetch_and_sub1_acquire(addr) \\\n        AO_short_fetch_and_add_acquire(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_write)\n#  define AO_short_fetch_and_sub1_write(addr) \\\n        AO_short_fetch_and_add_write(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_read)\n#  define AO_short_fetch_and_sub1_read(addr) \\\n        AO_short_fetch_and_add_read(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_release_write)\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\n        AO_short_fetch_and_add_release_write(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_acquire_read)\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\n        AO_short_fetch_and_add_acquire_read(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_add(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_short_fetch_and_sub1_release)\n#    define AO_short_fetch_and_sub1_release(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#    define AO_short_fetch_and_sub1_acquire(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_sub1_write)\n#    define AO_short_fetch_and_sub1_write(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_sub1_read)\n#    define AO_short_fetch_and_sub1_read(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_short_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_release)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_release(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_write)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_write(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_read)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_read(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_fetch_and_sub1_full)\n#  define AO_short_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_short_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_short_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_write)\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\n        AO_short_fetch_and_sub1_write(addr)\n#  define AO_HAVE_short_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_release)\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\n        AO_short_fetch_and_sub1_release(addr)\n#  define AO_HAVE_short_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_read)\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\n        AO_short_fetch_and_sub1_read(addr)\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\n        AO_short_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_fetch_and_sub1_acquire_read)\n#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_fetch_and_sub1)\n#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_sub1(addr)\n#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n\n/* int_load */\n#if defined(AO_HAVE_int_load_acquire) && !defined(AO_HAVE_int_load)\n#  define AO_int_load(addr) AO_int_load_acquire(addr)\n#  define AO_HAVE_int_load\n#endif\n\n#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_acquire)\n#  define AO_int_load_acquire(addr) AO_int_load_full(addr)\n#  define AO_HAVE_int_load_acquire\n#endif\n\n#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_read)\n#  define AO_int_load_read(addr) AO_int_load_full(addr)\n#  define AO_HAVE_int_load_read\n#endif\n\n#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_acquire)\n#  define AO_int_load_acquire_read(addr) AO_int_load_acquire(addr)\n#  define AO_HAVE_int_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_load_acquire)\n   AO_INLINE unsigned int\n   AO_int_load_acquire(const volatile unsigned int *addr)\n   {\n     unsigned int result = AO_int_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_int_load_acquire\n#endif\n\n#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_int_load_read)\n   AO_INLINE unsigned int\n   AO_int_load_read(const volatile unsigned int *addr)\n   {\n     unsigned int result = AO_int_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_int_load_read\n#endif\n\n#if defined(AO_HAVE_int_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_load_full)\n#  define AO_int_load_full(addr) (AO_nop_full(), AO_int_load_acquire(addr))\n#  define AO_HAVE_int_load_full\n#endif\n\n#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_read)\n#  define AO_int_load_acquire_read(addr) AO_int_load_read(addr)\n#  define AO_HAVE_int_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_int_load_acquire_read) && !defined(AO_HAVE_int_load)\n#  define AO_int_load(addr) AO_int_load_acquire_read(addr)\n#  define AO_HAVE_int_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_load_acquire_read)\n#    define AO_int_load_dd_acquire_read(addr) \\\n        AO_int_load_acquire_read(addr)\n#    define AO_HAVE_int_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_load)\n#    define AO_int_load_dd_acquire_read(addr) \\\n        AO_int_load(addr)\n#    define AO_HAVE_int_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* int_store */\n\n#if defined(AO_HAVE_int_store_release) && !defined(AO_HAVE_int_store)\n#  define AO_int_store(addr, val) AO_int_store_release(addr,val)\n#  define AO_HAVE_int_store\n#endif\n\n#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_release)\n#  define AO_int_store_release(addr,val) AO_int_store_full(addr,val)\n#  define AO_HAVE_int_store_release\n#endif\n\n#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_write)\n#  define AO_int_store_write(addr,val) AO_int_store_full(addr,val)\n#  define AO_HAVE_int_store_write\n#endif\n\n#if defined(AO_HAVE_int_store_release) && \\\n        !defined(AO_HAVE_int_store_release_write)\n#  define AO_int_store_release_write(addr, val) \\\n        AO_int_store_release(addr,val)\n#  define AO_HAVE_int_store_release_write\n#endif\n\n#if defined(AO_HAVE_int_store_write) && !defined(AO_HAVE_int_store)\n#  define AO_int_store(addr, val) AO_int_store_write(addr,val)\n#  define AO_HAVE_int_store\n#endif\n\n#if defined(AO_HAVE_int_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_store_release)\n#  define AO_int_store_release(addr,val) \\\n        (AO_nop_full(), AO_int_store(addr,val))\n#  define AO_HAVE_int_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_int_store) && \\\n     !defined(AO_HAVE_int_store_write)\n#  define AO_int_store_write(addr, val) \\\n        (AO_nop_write(), AO_int_store(addr,val))\n#  define AO_HAVE_int_store_write\n#endif\n\n#if defined(AO_HAVE_int_store_write) && \\\n     !defined(AO_HAVE_int_store_release_write)\n#  define AO_int_store_release_write(addr, val) AO_int_store_write(addr,val)\n#  define AO_HAVE_int_store_release_write\n#endif\n\n#if defined(AO_HAVE_int_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_store_full)\n#  define AO_int_store_full(addr, val) \\\n        (AO_int_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_int_store_full\n#endif\n\n\n/* int_fetch_and_add */\n#if defined(AO_HAVE_int_compare_and_swap_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_int_fetch_and_add_full(volatile unsigned int *addr,\n                               unsigned int incr)\n   {\n     unsigned int old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_int_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_int_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_int_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_int_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_int_fetch_and_add_acquire(volatile unsigned int *addr,\n                                  unsigned int incr)\n   {\n     unsigned int old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_int_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_int_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_int_compare_and_swap_release) && \\\n    !defined(AO_HAVE_int_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_int_fetch_and_add_release(volatile unsigned int *addr,\n                                  unsigned int incr)\n   {\n     unsigned int old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_int_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_int_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add_full)\n#  if !defined(AO_HAVE_int_fetch_and_add_release)\n#    define AO_int_fetch_and_add_release(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add_acquire)\n#    define AO_int_fetch_and_add_acquire(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add_write)\n#    define AO_int_fetch_and_add_write(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add_read)\n#    define AO_int_fetch_and_add_read(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_int_fetch_and_add_full */\n\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_release)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_release(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_acquire)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_write)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_write(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_read)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_read(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add_full)\n#  define AO_int_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_int_fetch_and_add_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add_write)\n#  define AO_int_fetch_and_add_release_write(addr, val) \\\n        AO_int_fetch_and_add_write(addr, val)\n#  define AO_HAVE_int_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add_release)\n#  define AO_int_fetch_and_add_release_write(addr, val) \\\n        AO_int_fetch_and_add_release(addr, val)\n#  define AO_HAVE_int_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add_read)\n#  define AO_int_fetch_and_add_acquire_read(addr, val) \\\n        AO_int_fetch_and_add_read(addr, val)\n#  define AO_HAVE_int_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add_acquire)\n#  define AO_int_fetch_and_add_acquire_read(addr, val) \\\n        AO_int_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_int_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_fetch_and_add_acquire_read)\n#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_int_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_int_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_fetch_and_add)\n#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_int_fetch_and_add(addr, val)\n#    define AO_HAVE_int_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* int_fetch_and_add1 */\n\n#if defined(AO_HAVE_int_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_full)\n#  define AO_int_fetch_and_add1_full(addr) \\\n        AO_int_fetch_and_add_full(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1_release(addr) \\\n        AO_int_fetch_and_add_release(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1_acquire(addr) \\\n        AO_int_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_write)\n#  define AO_int_fetch_and_add1_write(addr) \\\n        AO_int_fetch_and_add_write(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_read)\n#  define AO_int_fetch_and_add1_read(addr) \\\n        AO_int_fetch_and_add_read(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_release_write)\n#  define AO_int_fetch_and_add1_release_write(addr) \\\n        AO_int_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_acquire_read)\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\n        AO_int_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add(addr,1)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add1_full)\n#  if !defined(AO_HAVE_int_fetch_and_add1_release)\n#    define AO_int_fetch_and_add1_release(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add1_acquire)\n#    define AO_int_fetch_and_add1_acquire(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add1_write)\n#    define AO_int_fetch_and_add1_write(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add1_read)\n#    define AO_int_fetch_and_add1_read(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_int_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_release(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_write)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_write(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_read)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_read(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add1_full)\n#  define AO_int_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_int_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_int_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add1_write)\n#  define AO_int_fetch_and_add1_release_write(addr) \\\n        AO_int_fetch_and_add1_write(addr)\n#  define AO_HAVE_int_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1_release_write(addr) \\\n        AO_int_fetch_and_add1_release(addr)\n#  define AO_HAVE_int_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add1_read)\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\n        AO_int_fetch_and_add1_read(addr)\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\n        AO_int_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_fetch_and_add1_acquire_read)\n#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_fetch_and_add1)\n#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_add1(addr)\n#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* int_fetch_and_sub1 */\n\n#if defined(AO_HAVE_int_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_full)\n#  define AO_int_fetch_and_sub1_full(addr) \\\n        AO_int_fetch_and_add_full(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1_release(addr) \\\n        AO_int_fetch_and_add_release(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1_acquire(addr) \\\n        AO_int_fetch_and_add_acquire(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_write)\n#  define AO_int_fetch_and_sub1_write(addr) \\\n        AO_int_fetch_and_add_write(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_read)\n#  define AO_int_fetch_and_sub1_read(addr) \\\n        AO_int_fetch_and_add_read(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_release_write)\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\n        AO_int_fetch_and_add_release_write(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire_read)\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\n        AO_int_fetch_and_add_acquire_read(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_add(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_int_fetch_and_sub1_release)\n#    define AO_int_fetch_and_sub1_release(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#    define AO_int_fetch_and_sub1_acquire(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_sub1_write)\n#    define AO_int_fetch_and_sub1_write(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_sub1_read)\n#    define AO_int_fetch_and_sub1_read(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_int_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_release(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_write)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_write(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_read)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_read(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_fetch_and_sub1_full)\n#  define AO_int_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_int_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_int_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_write)\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\n        AO_int_fetch_and_sub1_write(addr)\n#  define AO_HAVE_int_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\n        AO_int_fetch_and_sub1_release(addr)\n#  define AO_HAVE_int_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_read)\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\n        AO_int_fetch_and_sub1_read(addr)\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\n        AO_int_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_fetch_and_sub1_acquire_read)\n#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_fetch_and_sub1)\n#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_sub1(addr)\n#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/generalize.h",
    "content": "/*\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * Generalize atomic operations for atomic_ops.h.\n * Should not be included directly.\n *\n * We make no attempt to define useless operations, such as\n * AO_nop_acquire\n * AO_nop_release\n *\n * We have also so far neglected to define some others, which\n * do not appear likely to be useful, e.g. stores with acquire\n * or read barriers.\n *\n * This file is sometimes included twice by atomic_ops.h.\n * All definitions include explicit checks that we are not replacing\n * an earlier definition.  In general, more desirable expansions\n * appear earlier so that we are more likely to use them.\n *\n * We only make safe generalizations, except that by default we define\n * the ...dd_acquire_read operations to be equivalent to those without\n * a barrier.  On platforms for which this is unsafe, the platform-specific\n * file must define AO_NO_DD_ORDERING.\n */\n\n#ifndef ATOMIC_OPS_H\n# error Atomic_ops_generalize.h should not be included directly.\n#endif\n\n#if AO_CHAR_TS_T\n# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \\\n         AO_char_compare_and_swap_full(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \\\n         AO_char_compare_and_swap_acquire(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \\\n         AO_char_compare_and_swap_release(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP(a,o,n) \\\n         AO_char_compare_and_swap(a,o,n)\n#endif\n\n#if AO_AO_TS_T\n# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \\\n         AO_compare_and_swap_full(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \\\n         AO_compare_and_swap_acquire(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \\\n         AO_compare_and_swap_release(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP(a,o,n) \\\n         AO_compare_and_swap(a,o,n)\n#endif\n\n/* Generate test_and_set_full, if necessary and possible.       */\n#if !defined(AO_HAVE_test_and_set) && \\\n    !defined(AO_HAVE_test_and_set_release) && \\\n    !defined(AO_HAVE_test_and_set_acquire) && \\\n    !defined(AO_HAVE_test_and_set_read) && \\\n    !defined(AO_HAVE_test_and_set_full)\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_full) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_full)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_full(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP_FULL(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set_full\n#  endif /* AO_HAVE_compare_and_swap_full */\n\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_acquire) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_acquire)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_acquire(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP_ACQUIRE(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set_acquire\n#  endif /* AO_HAVE_compare_and_swap_acquire */\n\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_release) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_release)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_release(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP_RELEASE(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set_release\n#  endif /* AO_HAVE_compare_and_swap_release */\n\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set\n#  endif /* AO_HAVE_compare_and_swap */\n\n#  if defined(AO_HAVE_test_and_set) && defined(AO_HAVE_nop_full) \\\n      && !defined(AO_HAVE_test_and_set_acquire)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_acquire(volatile AO_TS_t *addr)\n     {\n       AO_TS_VAL_t result = AO_test_and_set(addr);\n       AO_nop_full();\n       return result;\n     }\n#    define AO_HAVE_test_and_set_acquire\n#  endif\n\n#endif /* No prior test and set */\n\n/* Nop */\n#if !defined(AO_HAVE_nop)\n   AO_INLINE void AO_nop(void) {}\n#  define AO_HAVE_nop\n#endif\n\n#if defined(AO_HAVE_test_and_set_full) && !defined(AO_HAVE_nop_full)\n   AO_INLINE void\n   AO_nop_full(void)\n   {\n     AO_TS_t dummy = AO_TS_INITIALIZER;\n     AO_test_and_set_full(&dummy);\n   }\n#  define AO_HAVE_nop_full\n#endif\n\n#if defined(AO_HAVE_nop_acquire)\n#  error AO_nop_acquire is useless: dont define.\n#endif\n#if defined(AO_HAVE_nop_release)\n#  error AO_nop_release is useless: dont define.\n#endif\n\n#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_read)\n#  define AO_nop_read() AO_nop_full()\n#  define AO_HAVE_nop_read\n#endif\n\n#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_write)\n#  define AO_nop_write() AO_nop_full()\n#  define AO_HAVE_nop_write\n#endif\n\n/* Load */\n#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_acquire)\n#  define AO_load_acquire(addr) AO_load_full(addr)\n#  define AO_HAVE_load_acquire\n#endif\n\n#if defined(AO_HAVE_load_acquire) && !defined(AO_HAVE_load)\n#  define AO_load(addr) AO_load_acquire(addr)\n#  define AO_HAVE_load\n#endif\n\n#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_read)\n#  define AO_load_read(addr) AO_load_full(addr)\n#  define AO_HAVE_load_read\n#endif\n\n#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_acquire)\n#  define AO_load_acquire_read(addr) AO_load_acquire(addr)\n#  define AO_HAVE_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_load_acquire)\n   AO_INLINE AO_t\n   AO_load_acquire(const volatile AO_t *addr)\n   {\n     AO_t result = AO_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_load_acquire\n#endif\n\n#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_load_read)\n   AO_INLINE AO_t\n   AO_load_read(const volatile AO_t *addr)\n   {\n     AO_t result = AO_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_load_read\n#endif\n\n#if defined(AO_HAVE_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_load_full)\n#  define AO_load_full(addr) (AO_nop_full(), AO_load_acquire(addr))\n#  define AO_HAVE_load_full\n#endif\n\n#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_read)\n#  define AO_load_acquire_read(addr) AO_load_read(addr)\n#  define AO_HAVE_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_load_acquire_read) && !defined(AO_HAVE_load)\n#  define AO_load(addr) AO_load_acquire_read(addr)\n#  define AO_HAVE_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_load_acquire_read)\n#    define AO_load_dd_acquire_read(addr) AO_load_acquire_read(addr)\n#    define AO_HAVE_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_load)\n#    define AO_load_dd_acquire_read(addr) AO_load(addr)\n#    define AO_HAVE_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* Store */\n\n#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_release)\n#  define AO_store_release(addr,val) AO_store_full(addr,val)\n#  define AO_HAVE_store_release\n#endif\n\n#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store)\n#  define AO_store(addr, val) AO_store_release(addr,val)\n#  define AO_HAVE_store\n#endif\n\n#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_write)\n#  define AO_store_write(addr,val) AO_store_full(addr,val)\n#  define AO_HAVE_store_write\n#endif\n\n#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store_release_write)\n#  define AO_store_release_write(addr, val) AO_store_release(addr,val)\n#  define AO_HAVE_store_release_write\n#endif\n\n#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store)\n#  define AO_store(addr, val) AO_store_write(addr,val)\n#  define AO_HAVE_store\n#endif\n\n#if defined(AO_HAVE_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_store_release)\n#  define AO_store_release(addr,val) (AO_nop_full(), AO_store(addr,val))\n#  define AO_HAVE_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_store) && \\\n     !defined(AO_HAVE_store_write)\n#  define AO_store_write(addr, val) (AO_nop_write(), AO_store(addr,val))\n#  define AO_HAVE_store_write\n#endif\n\n#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store_release_write)\n#  define AO_store_release_write(addr, val) AO_store_write(addr,val)\n#  define AO_HAVE_store_release_write\n#endif\n\n#if defined(AO_HAVE_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_store_full)\n#  define AO_store_full(addr, val) (AO_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_store_full\n#endif\n\n/* NEC LE-IT: Test and set */\n#if defined(AO_HAVE_test_and_set) && \\\n        defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_test_and_set_release)\n#       define AO_test_and_set_release(addr) \\\n        (AO_nop_full(), AO_test_and_set(addr))\n#  define AO_HAVE_test_and_set_release\n#endif\n\n#if defined(AO_HAVE_test_and_set) && \\\n        defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_test_and_set_acquire)\nAO_INLINE AO_TS_t\nAO_test_and_set_acquire(volatile AO_TS_t *addr)\n{\n        AO_TS_t res = AO_test_and_set(addr);\n        AO_nop_full();\n        return res;\n}\n#  define AO_HAVE_test_and_set_acquire\n#endif\n\n\n/* Fetch_and_add */\n/* We first try to implement fetch_and_add variants in terms    */\n/* of the corresponding compare_and_swap variants to minimize   */\n/* adding barriers.                                             */\n#if defined(AO_HAVE_compare_and_swap_full) && \\\n    !defined(AO_HAVE_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_release) && \\\n    !defined(AO_HAVE_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_compare_and_swap) && \\\n    !defined(AO_HAVE_fetch_and_add)\n   AO_INLINE AO_t\n   AO_fetch_and_add(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_fetch_and_add_full)\n#  if !defined(AO_HAVE_fetch_and_add_release)\n#    define AO_fetch_and_add_release(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add_acquire)\n#    define AO_fetch_and_add_acquire(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add_write)\n#    define AO_fetch_and_add_write(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add_read)\n#    define AO_fetch_and_add_read(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_fetch_and_add_full */\n\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_release)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_release(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_acquire)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_write)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_write(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_read)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_read(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_fetch_and_add_full)\n#  define AO_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_fetch_and_add_acquire(addr, val))\n#  define AO_HAVE_fetch_and_add_full\n#endif\n\n#if !defined(AO_HAVE_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_fetch_and_add_write)\n#  define AO_fetch_and_add_release_write(addr, val) \\\n        AO_fetch_and_add_write(addr, val)\n#  define AO_HAVE_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_fetch_and_add_release)\n#  define AO_fetch_and_add_release_write(addr, val) \\\n        AO_fetch_and_add_release(addr, val)\n#  define AO_HAVE_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add_read)\n#  define AO_fetch_and_add_acquire_read(addr, val) \\\n        AO_fetch_and_add_read(addr, val)\n#  define AO_HAVE_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add_acquire)\n#  define AO_fetch_and_add_acquire_read(addr, val) \\\n        AO_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_fetch_and_add_acquire_read)\n#    define AO_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_fetch_and_add)\n#    define AO_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_fetch_and_add(addr, val)\n#    define AO_HAVE_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* Fetch_and_add1 */\n\n#if defined(AO_HAVE_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_fetch_and_add1_full)\n#  define AO_fetch_and_add1_full(addr) AO_fetch_and_add_full(addr,1)\n#  define AO_HAVE_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_fetch_and_add1_release)\n#  define AO_fetch_and_add1_release(addr) AO_fetch_and_add_release(addr,1)\n#  define AO_HAVE_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_fetch_and_add1_acquire)\n#  define AO_fetch_and_add1_acquire(addr) AO_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_fetch_and_add1_write)\n#  define AO_fetch_and_add1_write(addr) AO_fetch_and_add_write(addr,1)\n#  define AO_HAVE_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_fetch_and_add1_read)\n#  define AO_fetch_and_add1_read(addr) AO_fetch_and_add_read(addr,1)\n#  define AO_HAVE_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_fetch_and_add1_release_write)\n#  define AO_fetch_and_add1_release_write(addr) \\\n        AO_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_fetch_and_add1_acquire_read)\n#  define AO_fetch_and_add1_acquire_read(addr) \\\n        AO_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_fetch_and_add) &&\\\n    !defined(AO_HAVE_fetch_and_add1)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add(addr,1)\n#  define AO_HAVE_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_fetch_and_add1_full)\n#  if !defined(AO_HAVE_fetch_and_add1_release)\n#    define AO_fetch_and_add1_release(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add1_acquire)\n#    define AO_fetch_and_add1_acquire(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add1_write)\n#    define AO_fetch_and_add1_write(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add1_read)\n#    define AO_fetch_and_add1_read(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_release)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_release(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_acquire)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_write)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_write(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_read)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_read(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_fetch_and_add1_full)\n#  define AO_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_fetch_and_add1_write)\n#  define AO_fetch_and_add1_release_write(addr) \\\n        AO_fetch_and_add1_write(addr)\n#  define AO_HAVE_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_fetch_and_add1_release)\n#  define AO_fetch_and_add1_release_write(addr) \\\n        AO_fetch_and_add1_release(addr)\n#  define AO_HAVE_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add1_read)\n#  define AO_fetch_and_add1_acquire_read(addr) \\\n        AO_fetch_and_add1_read(addr)\n#  define AO_HAVE_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add1_acquire)\n#  define AO_fetch_and_add1_acquire_read(addr) \\\n        AO_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_fetch_and_add1_acquire_read)\n#    define AO_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_fetch_and_add1)\n#    define AO_fetch_and_add1_dd_acquire_read(addr) AO_fetch_and_add1(addr)\n#    define AO_HAVE_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* Fetch_and_sub1 */\n\n#if defined(AO_HAVE_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_full)\n#  define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_release)\n#  define AO_fetch_and_sub1_release(addr) \\\n        AO_fetch_and_add_release(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_acquire)\n#  define AO_fetch_and_sub1_acquire(addr) \\\n        AO_fetch_and_add_acquire(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_write)\n#  define AO_fetch_and_sub1_write(addr) \\\n        AO_fetch_and_add_write(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_read)\n#  define AO_fetch_and_sub1_read(addr) \\\n        AO_fetch_and_add_read(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_release_write)\n#  define AO_fetch_and_sub1_release_write(addr) \\\n        AO_fetch_and_add_release_write(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_acquire_read)\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\n        AO_fetch_and_add_acquire_read(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_fetch_and_add) &&\\\n    !defined(AO_HAVE_fetch_and_sub1)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_add(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_fetch_and_sub1_release)\n#    define AO_fetch_and_sub1_release(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_fetch_and_sub1_acquire)\n#    define AO_fetch_and_sub1_acquire(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_fetch_and_sub1_write)\n#    define AO_fetch_and_sub1_write(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_fetch_and_sub1_read)\n#    define AO_fetch_and_sub1_read(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_release)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_release(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_acquire)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_write)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_write(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_read)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_read(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_fetch_and_sub1_full)\n#  define AO_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_fetch_and_sub1_write)\n#  define AO_fetch_and_sub1_release_write(addr) \\\n        AO_fetch_and_sub1_write(addr)\n#  define AO_HAVE_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_fetch_and_sub1_release)\n#  define AO_fetch_and_sub1_release_write(addr) \\\n        AO_fetch_and_sub1_release(addr)\n#  define AO_HAVE_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_sub1_read)\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\n        AO_fetch_and_sub1_read(addr)\n#  define AO_HAVE_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_sub1_acquire)\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\n        AO_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_fetch_and_sub1_acquire_read)\n#    define AO_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_fetch_and_sub1)\n#    define AO_fetch_and_sub1_dd_acquire_read(addr) AO_fetch_and_sub1(addr)\n#    define AO_HAVE_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n\n/* Atomic or */\n#if defined(AO_HAVE_compare_and_swap_full) && \\\n    !defined(AO_HAVE_or_full)\n   AO_INLINE void\n   AO_or_full(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_full(addr, old, (old | incr)));\n   }\n#  define AO_HAVE_or_full\n#endif\n\n#if defined(AO_HAVE_or_full)\n#  if !defined(AO_HAVE_or_release)\n#    define AO_or_release(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_release\n#  endif\n#  if !defined(AO_HAVE_or_acquire)\n#    define AO_or_acquire(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_acquire\n#  endif\n#  if !defined(AO_HAVE_or_write)\n#    define AO_or_write(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_write\n#  endif\n#  if !defined(AO_HAVE_or_read)\n#    define AO_or_read(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_read\n#  endif\n#endif /* AO_HAVE_or_full */\n\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_release)\n#  define AO_or(addr, val) \\\n        AO_or_release(addr, val)\n#  define AO_HAVE_or\n#endif\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_acquire)\n#  define AO_or(addr, val) \\\n        AO_or_acquire(addr, val)\n#  define AO_HAVE_or\n#endif\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_write)\n#  define AO_or(addr, val) \\\n        AO_or_write(addr, val)\n#  define AO_HAVE_or\n#endif\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_read)\n#  define AO_or(addr, val) \\\n        AO_or_read(addr, val)\n#  define AO_HAVE_or\n#endif\n\n#if defined(AO_HAVE_or_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_or_full)\n#  define AO_or_full(addr, val) \\\n        (AO_nop_full(), AO_or_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_or_release_write) && \\\n    defined(AO_HAVE_or_write)\n#  define AO_or_release_write(addr, val) \\\n        AO_or_write(addr, val)\n#  define AO_HAVE_or_release_write\n#endif\n#if !defined(AO_HAVE_or_release_write) && \\\n    defined(AO_HAVE_or_release)\n#  define AO_or_release_write(addr, val) \\\n        AO_or_release(addr, val)\n#  define AO_HAVE_or_release_write\n#endif\n#if !defined(AO_HAVE_or_acquire_read) && \\\n    defined(AO_HAVE_or_read)\n#  define AO_or_acquire_read(addr, val) \\\n        AO_or_read(addr, val)\n#  define AO_HAVE_or_acquire_read\n#endif\n#if !defined(AO_HAVE_or_acquire_read) && \\\n    defined(AO_HAVE_or_acquire)\n#  define AO_or_acquire_read(addr, val) \\\n        AO_or_acquire(addr, val)\n#  define AO_HAVE_or_acquire_read\n#endif\n\n/* dd_aquire_read is meaningless.       */\n\n/* Test_and_set */\n\n#if defined(AO_HAVE_test_and_set_full)\n#  if !defined(AO_HAVE_test_and_set_release)\n#    define AO_test_and_set_release(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_release\n#  endif\n#  if !defined(AO_HAVE_test_and_set_acquire)\n#    define AO_test_and_set_acquire(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_acquire\n#  endif\n#  if !defined(AO_HAVE_test_and_set_write)\n#    define AO_test_and_set_write(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_write\n#  endif\n#  if !defined(AO_HAVE_test_and_set_read)\n#    define AO_test_and_set_read(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_read\n#  endif\n#endif /* AO_HAVE_test_and_set_full */\n\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_release)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_release(addr)\n#  define AO_HAVE_test_and_set\n#endif\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_acquire)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_acquire(addr)\n#  define AO_HAVE_test_and_set\n#endif\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_write)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_write(addr)\n#  define AO_HAVE_test_and_set\n#endif\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_read)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_read(addr)\n#  define AO_HAVE_test_and_set\n#endif\n\n#if defined(AO_HAVE_test_and_set_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_test_and_set_full)\n#  define AO_test_and_set_full(addr) \\\n        (AO_nop_full(), AO_test_and_set_acquire(addr))\n#  define AO_HAVE_test_and_set_full\n#endif\n\n#if !defined(AO_HAVE_test_and_set_release_write) && \\\n    defined(AO_HAVE_test_and_set_write)\n#  define AO_test_and_set_release_write(addr) \\\n        AO_test_and_set_write(addr)\n#  define AO_HAVE_test_and_set_release_write\n#endif\n#if !defined(AO_HAVE_test_and_set_release_write) && \\\n    defined(AO_HAVE_test_and_set_release)\n#  define AO_test_and_set_release_write(addr) \\\n        AO_test_and_set_release(addr)\n#  define AO_HAVE_test_and_set_release_write\n#endif\n#if !defined(AO_HAVE_test_and_set_acquire_read) && \\\n    defined(AO_HAVE_test_and_set_read)\n#  define AO_test_and_set_acquire_read(addr) \\\n        AO_test_and_set_read(addr)\n#  define AO_HAVE_test_and_set_acquire_read\n#endif\n#if !defined(AO_HAVE_test_and_set_acquire_read) && \\\n    defined(AO_HAVE_test_and_set_acquire)\n#  define AO_test_and_set_acquire_read(addr) \\\n        AO_test_and_set_acquire(addr)\n#  define AO_HAVE_test_and_set_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_test_and_set_acquire_read)\n#    define AO_test_and_set_dd_acquire_read(addr) \\\n        AO_test_and_set_acquire_read(addr)\n#    define AO_HAVE_test_and_set_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_test_and_set)\n#    define AO_test_and_set_dd_acquire_read(addr) AO_test_and_set(addr)\n#    define AO_HAVE_test_and_set_dd_acquire_read\n#  endif\n#endif\n\n/* Compare_and_swap */\n#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_acquire)\n   AO_INLINE int\n   AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val)\n   {\n     int result = AO_compare_and_swap(addr, old, new_val);\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_compare_and_swap_acquire\n#endif\n#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_release)\n#  define AO_compare_and_swap_release(addr, old, new_val) \\\n        (AO_nop_full(), AO_compare_and_swap(addr, old, new_val))\n#  define AO_HAVE_compare_and_swap_release\n#endif\n#if defined(AO_HAVE_compare_and_swap_full)\n#  if !defined(AO_HAVE_compare_and_swap_release)\n#    define AO_compare_and_swap_release(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_release\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_acquire)\n#    define AO_compare_and_swap_acquire(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_acquire\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_write)\n#    define AO_compare_and_swap_write(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_write\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_read)\n#    define AO_compare_and_swap_read(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_read\n#  endif\n#endif /* AO_HAVE_compare_and_swap_full */\n\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_release)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_release(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_acquire)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_acquire(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_write)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_write(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_read)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_read(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_compare_and_swap_full)\n#  define AO_compare_and_swap_full(addr, old, new_val) \\\n        (AO_nop_full(), AO_compare_and_swap_acquire(addr, old, new_val))\n#  define AO_HAVE_compare_and_swap_full\n#endif\n\n#if !defined(AO_HAVE_compare_and_swap_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_write)\n#  define AO_compare_and_swap_release_write(addr, old, new_val) \\\n        AO_compare_and_swap_write(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_release)\n#  define AO_compare_and_swap_release_write(addr, old, new_val) \\\n        AO_compare_and_swap_release(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_read)\n#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap_read(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_acquire_read\n#endif\n#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_acquire)\n#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap_acquire(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_compare_and_swap_acquire_read)\n#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap_acquire_read(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_compare_and_swap)\n#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_dd_acquire_read\n#  endif\n#endif\n\n#include \"generalize-small.h\"\n\n/* Compare_double_and_swap_double */\n#if defined(AO_HAVE_compare_double_and_swap_double) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_double_and_swap_double_acquire)\n   AO_INLINE int\n   AO_compare_double_and_swap_double_acquire(volatile AO_double_t *addr,\n                                             AO_t o1, AO_t o2,\n                                             AO_t n1, AO_t n2)\n   {\n     int result = AO_compare_double_and_swap_double(addr, o1, o2, n1, n2);\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_compare_double_and_swap_double_acquire\n#endif\n#if defined(AO_HAVE_compare_double_and_swap_double) \\\n    && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_double_and_swap_double_release)\n#  define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \\\n        (AO_nop_full(), AO_compare_double_and_swap_double(addr, o1, o2, n1, n2))\n#  define AO_HAVE_compare_double_and_swap_double_release\n#endif\n#if defined(AO_HAVE_compare_double_and_swap_double_full)\n#  if !defined(AO_HAVE_compare_double_and_swap_double_release)\n#    define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_release\n#  endif\n#  if !defined(AO_HAVE_compare_double_and_swap_double_acquire)\n#    define AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_acquire\n#  endif\n#  if !defined(AO_HAVE_compare_double_and_swap_double_write)\n#    define AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_write\n#  endif\n#  if !defined(AO_HAVE_compare_double_and_swap_double_read)\n#    define AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_read\n#  endif\n#endif /* AO_HAVE_compare_double_and_swap_double_full */\n\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_release)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_acquire)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_write)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_read)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n\n#if defined(AO_HAVE_compare_double_and_swap_double_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_compare_double_and_swap_double_full)\n#  define AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2) \\\n        (AO_nop_full(), AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2))\n#  define AO_HAVE_compare_double_and_swap_double_full\n#endif\n\n#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_write)\n#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_release)\n#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_read)\n#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_acquire_read\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_acquire)\n#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_compare_double_and_swap_double_acquire_read)\n#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_compare_double_and_swap_double)\n#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read\n#  endif\n#endif\n\n/* Compare_and_swap_double */\n#if defined(AO_HAVE_compare_and_swap_double) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_double_acquire)\n   AO_INLINE int\n   AO_compare_and_swap_double_acquire(volatile AO_double_t *addr,\n                                             AO_t o1,\n                                             AO_t n1, AO_t n2)\n   {\n     int result = AO_compare_and_swap_double(addr, o1, n1, n2);\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_compare_and_swap_double_acquire\n#endif\n#if defined(AO_HAVE_compare_and_swap_double) \\\n    && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_double_release)\n#  define AO_compare_and_swap_double_release(addr, o1, n1, n2) \\\n        (AO_nop_full(), AO_compare_and_swap_double(addr, o1, n1, n2))\n#  define AO_HAVE_compare_and_swap_double_release\n#endif\n#if defined(AO_HAVE_compare_and_swap_double_full)\n#  if !defined(AO_HAVE_compare_and_swap_double_release)\n#    define AO_compare_and_swap_double_release(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_release\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_double_acquire)\n#    define AO_compare_and_swap_double_acquire(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_acquire\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_double_write)\n#    define AO_compare_and_swap_double_write(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_write\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_double_read)\n#    define AO_compare_and_swap_double_read(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_read\n#  endif\n#endif /* AO_HAVE_compare_and_swap_double_full */\n\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_release)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_release(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_acquire)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_acquire(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_write)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_write(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_read)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_read(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_double_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_compare_and_swap_double_full)\n#  define AO_compare_and_swap_double_full(addr, o1, n1, n2) \\\n        (AO_nop_full(), AO_compare_and_swap_double_acquire(addr, o1, n1, n2))\n#  define AO_HAVE_compare_and_swap_double_full\n#endif\n\n#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_double_write)\n#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_write(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_double_release)\n#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_release(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_double_read)\n#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_read(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_acquire_read\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_double_acquire)\n#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_acquire(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_compare_and_swap_double_acquire_read)\n#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_compare_and_swap_double)\n#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_dd_acquire_read\n#  endif\n#endif\n\n/* NEC LE-IT: Convenience functions for AO_double compare and swap which */\n/* types and reads easier in code                                        */\n#if defined(AO_HAVE_compare_double_and_swap_double_release) && \\\n    !defined(AO_HAVE_double_compare_and_swap_release)\nAO_INLINE int\nAO_double_compare_and_swap_release(volatile AO_double_t *addr,\n                                   AO_double_t old_val, AO_double_t new_val)\n{\n        return AO_compare_double_and_swap_double_release(addr,\n                                                         old_val.AO_val1, old_val.AO_val2,\n                                                         new_val.AO_val1, new_val.AO_val2);\n}\n#define AO_HAVE_double_compare_and_swap_release\n#endif\n\n#if defined(AO_HAVE_compare_double_and_swap_double_acquire) && \\\n    !defined(AO_HAVE_double_compare_and_swap_acquire)\nAO_INLINE int\nAO_double_compare_and_swap_acquire(volatile AO_double_t *addr,\n                                   AO_double_t old_val, AO_double_t new_val)\n{\n        return AO_compare_double_and_swap_double_acquire(addr,\n                                                         old_val.AO_val1, old_val.AO_val2,\n                                                         new_val.AO_val1, new_val.AO_val2);\n}\n#define AO_HAVE_double_compare_and_swap_acquire\n#endif\n\n#if defined(AO_HAVE_compare_double_and_swap_double_full) && \\\n    !defined(AO_HAVE_double_compare_and_swap_full)\nAO_INLINE int\nAO_double_compare_and_swap_full(volatile AO_double_t *addr,\n                                         AO_double_t old_val, AO_double_t new_val)\n{\n        return AO_compare_double_and_swap_double_full(addr,\n                                                      old_val.AO_val1, old_val.AO_val2,\n                                                      new_val.AO_val1, new_val.AO_val2);\n}\n#define AO_HAVE_double_compare_and_swap_full\n#endif\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/ia64.h",
    "content": "/*\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include \"./aligned_atomic_load_store.h\"\n\n#include \"./all_acquire_release_volatile.h\"\n\n#include \"./test_and_set_t_is_char.h\"\n\n#ifdef _ILP32\n  /* 32-bit HP/UX code. */\n  /* This requires pointer \"swizzling\".  Pointers need to be expanded   */\n  /* to 64 bits using the addp4 instruction before use.  This makes it  */\n  /* hard to share code, but we try anyway.                             */\n# define AO_LEN \"4\"\n  /* We assume that addr always appears in argument position 1 in asm   */\n  /* code.  If it is clobbered due to swizzling, we also need it in     */\n  /* second position.  Any later arguments are referenced symbolically, */\n  /* so that we don't have to worry about their position.  This requires*/\n  /* gcc 3.1, but you shouldn't be using anything older than that on    */\n  /* IA64 anyway.                                                       */\n  /* The AO_MASK macro is a workaround for the fact that HP/UX gcc      */\n  /* appears to otherwise store 64-bit pointers in ar.ccv, i.e. it      */\n  /* doesn't appear to clear high bits in a pointer value we pass into  */\n  /* assembly code, even if it is supposedly of type AO_t.              */\n# define AO_IN_ADDR \"1\"(addr)\n# define AO_OUT_ADDR , \"=r\"(addr)\n# define AO_SWIZZLE \"addp4 %1=0,%1;;\\n\"\n# define AO_MASK(ptr) __asm__(\"zxt4 %1=%1\": \"=r\"(ptr) : \"0\"(ptr));\n#else\n# define AO_LEN \"8\"\n# define AO_IN_ADDR \"r\"(addr)\n# define AO_OUT_ADDR\n# define AO_SWIZZLE\n# define AO_MASK(ptr)\n#endif\n\nAO_INLINE void\nAO_nop_full(void)\n{\n  __asm__ __volatile__(\"mf\" : : : \"memory\");\n}\n#define AO_HAVE_nop_full\n\nAO_INLINE AO_t\nAO_fetch_and_add1_acquire (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".acq %0=[%1],1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n#define AO_HAVE_fetch_and_add1_acquire\n\nAO_INLINE AO_t\nAO_fetch_and_add1_release (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".rel %0=[%1],1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add1_release\n\nAO_INLINE AO_t\nAO_fetch_and_sub1_acquire (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".acq %0=[%1],-1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_sub1_acquire\n\nAO_INLINE AO_t\nAO_fetch_and_sub1_release (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".rel %0=[%1],-1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_sub1_release\n\n#ifndef _ILP32\n\nAO_INLINE unsigned int\nAO_int_fetch_and_add1_acquire (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.acq %0=[%1],1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n#define AO_HAVE_int_fetch_and_add1_acquire\n\nAO_INLINE unsigned int\nAO_int_fetch_and_add1_release (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.rel %0=[%1],1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_add1_release\n\nAO_INLINE unsigned int\nAO_int_fetch_and_sub1_acquire (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.acq %0=[%1],-1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_sub1_acquire\n\nAO_INLINE unsigned int\nAO_int_fetch_and_sub1_release (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.rel %0=[%1],-1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_sub1_release\n\n#endif /* !_ILP32 */\n\nAO_INLINE int\nAO_compare_and_swap_acquire(volatile AO_t *addr,\n                             AO_t old, AO_t new_val)\n{\n  AO_t oldval;\n  AO_MASK(old);\n  __asm__ __volatile__(AO_SWIZZLE\n                       \"mov ar.ccv=%[old] ;; cmpxchg\" AO_LEN\n                       \".acq %0=[%1],%[new_val],ar.ccv\"\n                       : \"=r\"(oldval) AO_OUT_ADDR\n                       : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"(old)\n                       : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_compare_and_swap_acquire\n\nAO_INLINE int\nAO_compare_and_swap_release(volatile AO_t *addr,\n                             AO_t old, AO_t new_val)\n{\n  AO_t oldval;\n  AO_MASK(old);\n  __asm__ __volatile__(AO_SWIZZLE\n                       \"mov ar.ccv=%[old] ;; cmpxchg\" AO_LEN\n                       \".rel %0=[%1],%[new_val],ar.ccv\"\n                       : \"=r\"(oldval) AO_OUT_ADDR\n                       : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"(old)\n                       : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_compare_and_swap_release\n\nAO_INLINE int\nAO_char_compare_and_swap_acquire(volatile unsigned char *addr,\n                                 unsigned char old, unsigned char new_val)\n{\n  unsigned char oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n               \"mov ar.ccv=%[old] ;; cmpxchg1.acq %0=[%1],%[new_val],ar.ccv\"\n               : \"=r\"(oldval) AO_OUT_ADDR\n               : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n               : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_char_compare_and_swap_acquire\n\nAO_INLINE int\nAO_char_compare_and_swap_release(volatile unsigned char *addr,\n                                 unsigned char old, unsigned char new_val)\n{\n  unsigned char oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n                \"mov ar.ccv=%[old] ;; cmpxchg1.rel %0=[%1],%[new_val],ar.ccv\"\n                : \"=r\"(oldval) AO_OUT_ADDR\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n                : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_char_compare_and_swap_release\n\nAO_INLINE int\nAO_short_compare_and_swap_acquire(volatile unsigned short *addr,\n                                  unsigned short old, unsigned short new_val)\n{\n  unsigned short oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n                \"mov ar.ccv=%[old] ;; cmpxchg2.acq %0=[%1],%[new_val],ar.ccv\"\n                : \"=r\"(oldval) AO_OUT_ADDR\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n                : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_short_compare_and_swap_acquire\n\nAO_INLINE int\nAO_short_compare_and_swap_release(volatile unsigned short *addr,\n                                  unsigned short old, unsigned short new_val)\n{\n  unsigned short oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n                \"mov ar.ccv=%[old] ;; cmpxchg2.rel %0=[%1],%[new_val],ar.ccv\"\n                : \"=r\"(oldval) AO_OUT_ADDR\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n                : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_short_compare_and_swap_release\n\n#ifndef _ILP32\n\nAO_INLINE int\nAO_int_compare_and_swap_acquire(volatile unsigned int *addr,\n                                unsigned int old, unsigned int new_val)\n{\n  unsigned int oldval;\n  __asm__ __volatile__(\"mov ar.ccv=%3 ;; cmpxchg4.acq %0=[%1],%2,ar.ccv\"\n                       : \"=r\"(oldval)\n                       : AO_IN_ADDR, \"r\"(new_val), \"r\"((AO_t)old) : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_int_compare_and_swap_acquire\n\nAO_INLINE int\nAO_int_compare_and_swap_release(volatile unsigned int *addr,\n                                unsigned int old, unsigned int new_val)\n{\n  unsigned int oldval;\n  __asm__ __volatile__(\"mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%1],%2,ar.ccv\"\n                       : \"=r\"(oldval)\n                       : AO_IN_ADDR, \"r\"(new_val), \"r\"((AO_t)old) : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_int_compare_and_swap_release\n\n#endif /* !_ILP32 */\n\n/* FIXME: Add compare_and_swap_double as soon as there is widely        */\n/* available hardware that implements it.                               */\n\n/* FIXME: Add compare_double_and_swap_double for the _ILP32 case.       */\n\n#ifdef _ILP32\n# include \"./ao_t_is_int.h\"\n#endif\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/ordered_except_wr.h",
    "content": "/*\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * These are common definitions for architectures that provide processor\n * ordered memory operations except that a later read may pass an\n * earlier write.  Real x86 implementations seem to be in this category,\n * except apparently for some IDT WinChips, which we ignore.\n */\n\n#include \"read_ordered.h\"\n\nAO_INLINE void\nAO_nop_write(void)\n{\n  AO_compiler_barrier();\n  /* sfence according to Intel docs.  Pentium 3 and up. */\n  /* Unnecessary for cached accesses?                   */\n}\n\n#define AO_HAVE_NOP_WRITE\n\n#if defined(AO_HAVE_store)\n\nAO_INLINE void\nAO_store_write(volatile AO_t *addr, AO_t val)\n{\n  AO_compiler_barrier();\n  AO_store(addr, val);\n}\n# define AO_HAVE_store_write\n\n# define AO_store_release(addr, val) AO_store_write(addr, val)\n# define AO_HAVE_store_release\n\n#endif /* AO_HAVE_store */\n\n#if defined(AO_HAVE_char_store)\n\nAO_INLINE void\nAO_char_store_write(volatile unsigned char *addr, unsigned char val)\n{\n  AO_compiler_barrier();\n  AO_char_store(addr, val);\n}\n# define AO_HAVE_char_store_write\n\n# define AO_char_store_release(addr, val) AO_char_store_write(addr, val)\n# define AO_HAVE_char_store_release\n\n#endif /* AO_HAVE_char_store */\n\n#if defined(AO_HAVE_short_store)\n\nAO_INLINE void\nAO_short_store_write(volatile unsigned short *addr, unsigned short val)\n{\n  AO_compiler_barrier();\n  AO_short_store(addr, val);\n}\n# define AO_HAVE_short_store_write\n\n# define AO_short_store_release(addr, val) AO_short_store_write(addr, val)\n# define AO_HAVE_short_store_release\n\n#endif /* AO_HAVE_short_store */\n\n#if defined(AO_HAVE_int_store)\n\nAO_INLINE void\nAO_int_store_write(volatile unsigned int *addr, unsigned int val)\n{\n  AO_compiler_barrier();\n  AO_int_store(addr, val);\n}\n# define AO_HAVE_int_store_write\n\n# define AO_int_store_release(addr, val) AO_int_store_write(addr, val)\n# define AO_HAVE_int_store_release\n\n#endif /* AO_HAVE_int_store */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/powerpc.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n */\n\n/* Memory model documented at http://www-106.ibm.com/developerworks/    */\n/* eserver/articles/archguide.html and (clearer)                        */\n/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */\n/* There appears to be no implicit ordering between any kind of         */\n/* independent memory references.                                       */\n/* Architecture enforces some ordering based on control dependence.     */\n/* I don't know if that could help.                                     */\n/* Data-dependent loads are always ordered.                             */\n/* Based on the above references, eieio is intended for use on          */\n/* uncached memory, which we don't support.  It does not order loads    */\n/* from cached memory.                                                  */\n/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to   */\n/* track some of this down and correcting my misunderstandings. -HB     */\n/* Earl Chew subsequently contributed further fixes & additions.        */\n\n#include \"./aligned_atomic_load_store.h\"\n\n#include \"./test_and_set_t_is_ao_t.h\"\n        /* There seems to be no byte equivalent of lwarx, so this       */\n        /* may really be what we want, at least in the 32-bit case.     */\n\nAO_INLINE void\nAO_nop_full(void)\n{\n  __asm__ __volatile__(\"sync\" : : : \"memory\");\n}\n\n#define AO_HAVE_nop_full\n\n/* lwsync apparently works for everything but a StoreLoad barrier.      */\nAO_INLINE void\nAO_lwsync(void)\n{\n#ifdef __NO_LWSYNC__\n  __asm__ __volatile__(\"sync\" : : : \"memory\");\n#else\n  __asm__ __volatile__(\"lwsync\" : : : \"memory\");\n#endif\n}\n\n#define AO_nop_write() AO_lwsync()\n#define AO_HAVE_nop_write\n\n#define AO_nop_read() AO_lwsync()\n#define AO_HAVE_nop_read\n\n/* We explicitly specify load_acquire, since it is important, and can   */\n/* be implemented relatively cheaply.  It could be implemented          */\n/* with an ordinary load followed by a lwsync.  But the general wisdom  */\n/* seems to be that a data dependent branch followed by an isync is     */\n/* cheaper.  And the documentation is fairly explicit that this also    */\n/* has acquire semantics.                                               */\n/* ppc64 uses ld not lwz */\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\nAO_INLINE AO_t\nAO_load_acquire(const volatile AO_t *addr)\n{\n  AO_t result;\n\n   __asm__ __volatile__ (\n    \"ld%U1%X1 %0,%1\\n\"\n    \"cmpw %0,%0\\n\"\n    \"bne- 1f\\n\"\n    \"1: isync\\n\"\n    : \"=r\" (result)\n    : \"m\"(*addr) : \"memory\", \"cr0\");\n  return result;\n}\n#else\nAO_INLINE AO_t\nAO_load_acquire(const volatile AO_t *addr)\n{\n  AO_t result;\n\n  /* FIXME: We should get gcc to allocate one of the condition  */\n  /* registers.  I always got \"impossible constraint\" when I    */\n  /* tried the \"y\" constraint.                                  */\n  __asm__ __volatile__ (\n    \"lwz%U1%X1 %0,%1\\n\"\n    \"cmpw %0,%0\\n\"\n    \"bne- 1f\\n\"\n    \"1: isync\\n\"\n    : \"=r\" (result)\n    : \"m\"(*addr) : \"memory\", \"cc\");\n  return result;\n}\n#endif\n#define AO_HAVE_load_acquire\n\n/* We explicitly specify store_release, since it relies         */\n/* on the fact that lwsync is also a LoadStore barrier.         */\nAO_INLINE void\nAO_store_release(volatile AO_t *addr, AO_t value)\n{\n  AO_lwsync();\n  *addr = value;\n}\n\n#define AO_HAVE_load_acquire\n\n/* This is similar to the code in the garbage collector.  Deleting      */\n/* this and having it synthesized from compare_and_swap would probably  */\n/* only cost us a load immediate instruction.                           */\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n/* Completely untested.  And we should be using smaller objects anyway. */\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set(volatile AO_TS_t *addr) {\n  unsigned long oldval;\n  unsigned long temp = 1; /* locked value */\n\n  __asm__ __volatile__(\n               \"1:ldarx %0,0,%1\\n\"   /* load and reserve               */\n               \"cmpdi %0, 0\\n\"       /* if load is                     */\n               \"bne 2f\\n\"            /*   non-zero, return already set */\n               \"stdcx. %2,0,%1\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"2:\\n\"                /* oldval is zero if we set       */\n              : \"=&r\"(oldval)\n              : \"r\"(addr), \"r\"(temp)\n              : \"memory\", \"cr0\");\n\n  return (AO_TS_VAL_t)oldval;\n}\n\n#else\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set(volatile AO_TS_t *addr) {\n  int oldval;\n  int temp = 1; /* locked value */\n\n  __asm__ __volatile__(\n               \"1:lwarx %0,0,%1\\n\"   /* load and reserve               */\n               \"cmpwi %0, 0\\n\"       /* if load is                     */\n               \"bne 2f\\n\"            /*   non-zero, return already set */\n               \"stwcx. %2,0,%1\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"2:\\n\"                /* oldval is zero if we set       */\n              : \"=&r\"(oldval)\n              : \"r\"(addr), \"r\"(temp)\n              : \"memory\", \"cr0\");\n\n  return (AO_TS_VAL_t)oldval;\n}\n\n#endif\n\n#define AO_HAVE_test_and_set\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_acquire(volatile AO_TS_t *addr) {\n  AO_TS_VAL_t result = AO_test_and_set(addr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_test_and_set_acquire\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_release(volatile AO_TS_t *addr) {\n  AO_lwsync();\n  return AO_test_and_set(addr);\n}\n\n#define AO_HAVE_test_and_set_release\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr) {\n  AO_TS_VAL_t result;\n  AO_lwsync();\n  result = AO_test_and_set(addr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_test_and_set_full\n\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n/* FIXME: Completely untested.  */\nAO_INLINE int\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_t oldval;\n  int result = 0;\n\n  __asm__ __volatile__(\n               \"1:ldarx %0,0,%2\\n\"   /* load and reserve              */\n               \"cmpd %0, %4\\n\"      /* if load is not equal to  */\n               \"bne 2f\\n\"            /*   old, fail                     */\n               \"stdcx. %3,0,%2\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"li %1,1\\n\"           /* result = 1;                     */\n               \"2:\\n\"\n              : \"=&r\"(oldval), \"=&r\"(result)\n              : \"r\"(addr), \"r\"(new_val), \"r\"(old), \"1\"(result)\n              : \"memory\", \"cr0\");\n\n  return result;\n}\n\n#else\n\nAO_INLINE int\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_t oldval;\n  int result = 0;\n\n  __asm__ __volatile__(\n               \"1:lwarx %0,0,%2\\n\"   /* load and reserve              */\n               \"cmpw %0, %4\\n\"      /* if load is not equal to  */\n               \"bne 2f\\n\"            /*   old, fail                     */\n               \"stwcx. %3,0,%2\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"li %1,1\\n\"           /* result = 1;                     */\n               \"2:\\n\"\n              : \"=&r\"(oldval), \"=&r\"(result)\n              : \"r\"(addr), \"r\"(new_val), \"r\"(old), \"1\"(result)\n              : \"memory\", \"cr0\");\n\n  return result;\n}\n#endif\n\n#define AO_HAVE_compare_and_swap\n\nAO_INLINE int\nAO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  int result = AO_compare_and_swap(addr, old, new_val);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_compare_and_swap_acquire\n\nAO_INLINE int\nAO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_lwsync();\n  return AO_compare_and_swap(addr, old, new_val);\n}\n\n#define AO_HAVE_compare_and_swap_release\n\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_t result;\n  AO_lwsync();\n  result = AO_compare_and_swap(addr, old, new_val);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_compare_and_swap_full\n\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n/* FIXME: Completely untested.                                          */\n\nAO_INLINE AO_t\nAO_fetch_and_add(volatile AO_t *addr, AO_t incr) {\n  AO_t oldval;\n  AO_t newval;\n\n  __asm__ __volatile__(\n               \"1:ldarx %0,0,%2\\n\"   /* load and reserve                */\n               \"add %1,%0,%3\\n\"      /* increment                       */\n               \"stdcx. %1,0,%2\\n\"    /* store conditional               */\n               \"bne- 1b\\n\"           /* retry if lost reservation       */\n              : \"=&r\"(oldval), \"=&r\"(newval)\n               : \"r\"(addr), \"r\"(incr)\n              : \"memory\", \"cr0\");\n\n  return oldval;\n}\n\n#define AO_HAVE_fetch_and_add\n\n#else\n\nAO_INLINE AO_t\nAO_fetch_and_add(volatile AO_t *addr, AO_t incr) {\n  AO_t oldval;\n  AO_t newval;\n\n  __asm__ __volatile__(\n               \"1:lwarx %0,0,%2\\n\"   /* load and reserve                */\n               \"add %1,%0,%3\\n\"      /* increment                       */\n               \"stwcx. %1,0,%2\\n\"    /* store conditional               */\n               \"bne- 1b\\n\"           /* retry if lost reservation       */\n              : \"=&r\"(oldval), \"=&r\"(newval)\n               : \"r\"(addr), \"r\"(incr)\n              : \"memory\", \"cr0\");\n\n  return oldval;\n}\n\n#define AO_HAVE_fetch_and_add\n\n#endif\n\nAO_INLINE AO_t\nAO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr) {\n  AO_t result = AO_fetch_and_add(addr, incr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_acquire\n\nAO_INLINE AO_t\nAO_fetch_and_add_release(volatile AO_t *addr, AO_t incr) {\n  AO_lwsync();\n  return AO_fetch_and_add(addr, incr);\n}\n\n#define AO_HAVE_fetch_and_add_release\n\nAO_INLINE AO_t\nAO_fetch_and_add_full(volatile AO_t *addr, AO_t incr) {\n  AO_t result;\n  AO_lwsync();\n  result = AO_fetch_and_add(addr, incr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_full\n\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n#else\n# include \"./ao_t_is_int.h\"\n#endif\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/read_ordered.h",
    "content": "/*\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * These are common definitions for architectures that provide processor\n * ordered memory operations except that a later read may pass an\n * earlier write.  Real x86 implementations seem to be in this category,\n * except apparently for some IDT WinChips, which we ignore.\n */\n\nAO_INLINE void\nAO_nop_read(void)\n{\n  AO_compiler_barrier();\n}\n\n#define AO_HAVE_NOP_READ\n\n#ifdef AO_HAVE_load\n\nAO_INLINE AO_t\nAO_load_read(const volatile AO_t *addr)\n{\n  AO_t result = AO_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_load_read\n\n#define AO_load_acquire(addr) AO_load_read(addr)\n#define AO_HAVE_load_acquire\n\n#endif /* AO_HAVE_load */\n\n#ifdef AO_HAVE_char_load\n\nAO_INLINE AO_t\nAO_char_load_read(const volatile unsigned char *addr)\n{\n  AO_t result = AO_char_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_char_load_read\n\n#define AO_char_load_acquire(addr) AO_char_load_read(addr)\n#define AO_HAVE_char_load_acquire\n\n#endif /* AO_HAVE_char_load */\n\n#ifdef AO_HAVE_short_load\n\nAO_INLINE AO_t\nAO_short_load_read(const volatile unsigned short *addr)\n{\n  AO_t result = AO_short_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_short_load_read\n\n#define AO_short_load_acquire(addr) AO_short_load_read(addr)\n#define AO_HAVE_short_load_acquire\n\n#endif /* AO_HAVE_short_load */\n\n#ifdef AO_HAVE_int_load\n\nAO_INLINE AO_t\nAO_int_load_read(const volatile unsigned int *addr)\n{\n  AO_t result = AO_int_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_int_load_read\n\n#define AO_int_load_acquire(addr) AO_int_load_read(addr)\n#define AO_HAVE_int_load_acquire\n\n#endif /* AO_HAVE_int_load */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/sparc.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n */\n\n/* FIXME.  Very incomplete.  No support for sparc64.    */\n/* Non-ancient SPARCs provide compare-and-swap (casa).  */\n/* We should make that available.                       */\n\n#include \"./aligned_atomic_load_store.h\"\n\n/* Real SPARC code uses TSO:                            */\n#include \"./ordered_except_wr.h\"\n\n/* Test_and_set location is just a byte.                */\n#include \"./test_and_set_t_is_char.h\"\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr) {\n   AO_TS_VAL_t oldval;\n\n   __asm__ __volatile__(\"ldstub %1,%0\"\n                        : \"=r\"(oldval), \"=m\"(*addr)\n                        : \"m\"(*addr) : \"memory\");\n   return oldval;\n}\n\n#define AO_HAVE_test_and_set_full\n\n#ifndef AO_NO_SPARC_V9\n/* Returns nonzero if the comparison succeeded. */\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  char ret;\n  __asm__ __volatile__ (\"membar #StoreLoad | #LoadLoad\\n\\t\"\n#                       if defined(__arch64__)\n                          \"casx [%2],%0,%1\\n\\t\"\n#                       else\n                          \"cas [%2],%0,%1\\n\\t\" /* 32-bit version */\n#                       endif\n                        \"membar #StoreLoad | #StoreStore\\n\\t\"\n                        \"cmp %0,%1\\n\\t\"\n                        \"be,a 0f\\n\\t\"\n                        \"mov 1,%0\\n\\t\"/* one insn after branch always executed */\n                        \"clr %0\\n\\t\"\n                        \"0:\\n\\t\"\n                        : \"=r\" (ret), \"+r\" (new_val)\n                        : \"r\" (addr), \"0\" (old)\n                        : \"memory\", \"cc\");\n  return (int)ret;\n}\n\n#define AO_HAVE_compare_and_swap_full\n#endif /* AO_NO_SPARC_V9 */\n\n/* FIXME: This needs to be extended for SPARC v8 and v9.        */\n/* SPARC V8 also has swap.  V9 has CAS.                         */\n/* There are barriers like membar #LoadStore.                   */\n/* CASA (32-bit) and CASXA(64-bit) instructions were            */\n/* added in V9.                                                 */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/standard_ao_double_t.h",
    "content": "/* NEC LE-IT: For 64Bit OS we extend the double type to hold two int64's\n*\n*  x86-64: __m128 serves as placeholder which also requires the compiler\n*          to align     it on 16 byte boundary (as required by cmpxchg16.\n* Similar things could be done for PowerPC 64bit using a VMX data type...       */\n\n#if (defined(__x86_64__) && defined(__GNUC__)) || defined(_WIN64)\n# include <xmmintrin.h>\n  typedef __m128 double_ptr_storage;\n#elif defined(_WIN32) && !defined(__GNUC__)\n  typedef unsigned __int64 double_ptr_storage;\n#else\n  typedef unsigned long long double_ptr_storage;\n#endif\n\n# define AO_HAVE_DOUBLE_PTR_STORAGE\n\ntypedef union {\n    double_ptr_storage AO_whole;\n    struct {AO_t AO_v1; AO_t AO_v2;} AO_parts;\n} AO_double_t;\n\n#define AO_HAVE_double_t\n#define AO_val1 AO_parts.AO_v1\n#define AO_val2 AO_parts.AO_v2\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/test_and_set_t_is_ao_t.h",
    "content": "/*\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * These are common definitions for architectures on which test_and_set\n * operates on pointer-sized quantities, the \"clear\" value contains\n * all zeroes, and the \"set\" value contains only one lowest bit set.\n * This can be used if test_and_set is synthesized from compare_and_swap.\n */\ntypedef enum {AO_TS_clear = 0, AO_TS_set = 1} AO_TS_val;\n#define AO_TS_VAL_t AO_TS_val\n#define AO_TS_CLEAR AO_TS_clear\n#define AO_TS_SET AO_TS_set\n\n#define AO_TS_t AO_t\n\n#define AO_AO_TS_T 1\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/test_and_set_t_is_char.h",
    "content": "/*\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE. \n */ \n\n/*\n * These are common definitions for architectures on which test_and_set\n * operates on byte sized quantities, the \"clear\" value contains\n * all zeroes, and the \"set\" value contains all ones.\n */\n\n#define AO_TS_t unsigned char\ntypedef enum {AO_BYTE_TS_clear = 0, AO_BYTE_TS_set = 0xff} AO_BYTE_TS_val;\n#define AO_TS_VAL_t AO_BYTE_TS_val\n#define AO_TS_CLEAR AO_BYTE_TS_clear\n#define AO_TS_SET AO_BYTE_TS_set\n\n#define AO_CHAR_TS_T 1\n\n\n\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/x86.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n * Some of the machine specific code was borrowed from our GC distribution.\n */\n\n/* The following really assume we have a 486 or better.  Unfortunately  */\n/* gcc doesn't define a suitable feature test macro based on command    */\n/* line options.                                                        */\n/* We should perhaps test dynamically.                                  */\n\n#include \"./aligned_atomic_load_store.h\"\n\n/* Real X86 implementations, except for some old WinChips, appear       */\n/* to enforce ordering between memory operations, EXCEPT that a later   */\n/* read can pass earlier writes, presumably due to the visible          */\n/* presence of store buffers.                                           */\n/* We ignore both the WinChips, and the fact that the official specs    */\n/* seem to be much weaker (and arguably too weak to be usable).         */\n\n#include \"./ordered_except_wr.h\"\n\n#include \"./test_and_set_t_is_char.h\"\n\n#include \"./standard_ao_double_t.h\"\n\n#if defined(AO_USE_PENTIUM4_INSTRS)\nAO_INLINE void\nAO_nop_full(void)\n{\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\n}\n\n#define AO_HAVE_nop_full\n\n#else\n\n/* We could use the cpuid instruction.  But that seems to be slower     */\n/* than the default implementation based on test_and_set_full.  Thus    */\n/* we omit that bit of misinformation here.                             */\n\n#endif\n\n/* As far as we can tell, the lfence and sfence instructions are not    */\n/* currently needed or useful for cached memory accesses.               */\n\n/* Really only works for 486 and later */\nAO_INLINE AO_t\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_full\n\nAO_INLINE unsigned char\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\n{\n  unsigned char result;\n\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_char_fetch_and_add_full\n\nAO_INLINE unsigned short\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\n{\n  unsigned short result;\n\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_short_fetch_and_add_full\n\n/* Really only works for 486 and later */\nAO_INLINE void\nAO_or_full (volatile AO_t *p, AO_t incr)\n{\n  __asm__ __volatile__ (\"lock; orl %1, %0\" :\n                        \"=m\" (*p) : \"r\" (incr), \"m\" (*p) : \"memory\");\n}\n\n#define AO_HAVE_or_full\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr)\n{\n  unsigned char oldval;\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\n  __asm__ __volatile__(\"xchgb %0, %1\"\n                : \"=q\"(oldval), \"=m\"(*addr)\n                : \"0\"(0xff), \"m\"(*addr) : \"memory\");\n  return (AO_TS_VAL_t)oldval;\n}\n\n#define AO_HAVE_test_and_set_full\n\n/* Returns nonzero if the comparison succeeded. */\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\n{\n# ifdef AO_USE_SYNC_CAS_BUILTIN\n    return (int)__sync_bool_compare_and_swap(addr, old, new_val);\n# else\n    char result;\n    __asm__ __volatile__(\"lock; cmpxchgl %3, %0; setz %1\"\n                         : \"=m\" (*addr), \"=a\" (result)\n                         : \"m\" (*addr), \"r\" (new_val), \"a\" (old) : \"memory\");\n    return (int)result;\n# endif\n}\n\n#define AO_HAVE_compare_and_swap_full\n\n/* Returns nonzero if the comparison succeeded. */\n/* Really requires at least a Pentium.          */\nAO_INLINE int\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\n                                       AO_t old_val1, AO_t old_val2,\n                                       AO_t new_val1, AO_t new_val2)\n{\n  char result;\n#if __PIC__\n  /* If PIC is turned on, we can't use %ebx as it is reserved for the\n     GOT pointer.  We can save and restore %ebx because GCC won't be\n     using it for anything else (such as any of the m operands) */\n  __asm__ __volatile__(\"pushl %%ebx;\"   /* save ebx used for PIC GOT ptr */\n                       \"movl %6,%%ebx;\" /* move new_val2 to %ebx */\n                       \"lock; cmpxchg8b %0; setz %1;\"\n                       \"pop %%ebx;\"     /* restore %ebx */\n                       : \"=m\"(*addr), \"=a\"(result)\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\n                         \"c\" (new_val2), \"m\" (new_val1) : \"memory\");\n#else\n  /* We can't just do the same thing in non-PIC mode, because GCC\n   * might be using %ebx as the memory operand.  We could have ifdef'd\n   * in a clobber, but there's no point doing the push/pop if we don't\n   * have to. */\n  __asm__ __volatile__(\"lock; cmpxchg8b %0; setz %1;\"\n                       : \"=m\"(*addr), \"=a\"(result)\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\n#endif\n  return (int) result;\n}\n\n#define AO_HAVE_compare_double_and_swap_double_full\n\n#include \"./ao_t_is_int.h\"\n"
  },
  {
    "path": "stms/estm-0.3.0/src/atomic_ops/x86_64.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n * Some of the machine specific code was borrowed from our GC distribution.\n */\n\n#include \"./aligned_atomic_load_store.h\"\n\n/* Real X86 implementations appear                                      */\n/* to enforce ordering between memory operations, EXCEPT that a later   */\n/* read can pass earlier writes, presumably due to the visible          */\n/* presence of store buffers.                                           */\n/* We ignore the fact that the official specs                           */\n/* seem to be much weaker (and arguably too weak to be usable).         */\n\n#include \"./ordered_except_wr.h\"\n\n#include \"./test_and_set_t_is_char.h\"\n\n#include \"./standard_ao_double_t.h\"\n\nAO_INLINE void\nAO_nop_full(void)\n{\n  /* Note: \"mfence\" (SSE2) is supported on all x86_64/amd64 chips.      */\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\n}\n\n#define AO_HAVE_nop_full\n\n/* As far as we can tell, the lfence and sfence instructions are not    */\n/* currently needed or useful for cached memory accesses.               */\n\nAO_INLINE AO_t\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (\"lock; xaddq %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_full\n\nAO_INLINE unsigned char\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\n{\n  unsigned char result;\n\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_char_fetch_and_add_full\n\nAO_INLINE unsigned short\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\n{\n  unsigned short result;\n\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_short_fetch_and_add_full\n\nAO_INLINE unsigned int\nAO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_add_full\n\nAO_INLINE void\nAO_or_full (volatile AO_t *p, AO_t incr)\n{\n  __asm__ __volatile__ (\"lock; orq %1, %0\" :\n                        \"=m\" (*p) : \"r\" (incr), \"m\" (*p) : \"memory\");\n}\n\n#define AO_HAVE_or_full\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr)\n{\n  unsigned char oldval;\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\n  __asm__ __volatile__(\"xchgb %0, %1\"\n                : \"=q\"(oldval), \"=m\"(*addr)\n                : \"0\"(0xff), \"m\"(*addr) : \"memory\");\n  return (AO_TS_VAL_t)oldval;\n}\n\n#define AO_HAVE_test_and_set_full\n\n/* Returns nonzero if the comparison succeeded. */\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\n{\n# ifdef AO_USE_SYNC_CAS_BUILTIN\n    return (int)__sync_bool_compare_and_swap(addr, old, new_val);\n# else\n    char result;\n    __asm__ __volatile__(\"lock; cmpxchgq %3, %0; setz %1\"\n                         : \"=m\" (*addr), \"=a\" (result)\n                         : \"m\" (*addr), \"r\" (new_val), \"a\" (old) : \"memory\");\n    return (int) result;\n# endif\n}\n\n#define AO_HAVE_compare_and_swap_full\n\n#ifdef AO_CMPXCHG16B_AVAILABLE\n/* NEC LE-IT: older AMD Opterons are missing this instruction.\n * On these machines SIGILL will be thrown.\n * Define AO_WEAK_DOUBLE_CAS_EMULATION to have an emulated\n * (lock based) version available */\n/* HB: Changed this to not define either by default.  There are\n * enough machines and tool chains around on which cmpxchg16b\n * doesn't work.  And the emulation is unsafe by our usual rules.\n * Hoewever both are clearly useful in certain cases.\n */\nAO_INLINE int\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\n                                       AO_t old_val1, AO_t old_val2,\n                                       AO_t new_val1, AO_t new_val2)\n{\n  char result;\n  __asm__ __volatile__(\"lock; cmpxchg16b %0; setz %1\"\n                       : \"=m\"(*addr), \"=a\"(result)\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\n  return (int) result;\n}\n#define AO_HAVE_compare_double_and_swap_double_full\n#else\n/* this one provides spinlock based emulation of CAS implemented in     */\n/* atomic_ops.c.  We probably do not want to do this here, since it is  */\n/* not atomic with respect to other kinds of updates of *addr.  On the  */\n/* other hand, this may be a useful facility on occasion.               */\n#ifdef AO_WEAK_DOUBLE_CAS_EMULATION\nint AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,\n                                                AO_t old_val1, AO_t old_val2,\n                                                AO_t new_val1, AO_t new_val2);\n\nAO_INLINE int\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\n                                       AO_t old_val1, AO_t old_val2,\n                                       AO_t new_val1, AO_t new_val2)\n{\n        return AO_compare_double_and_swap_double_emulation(addr,\n                                                           old_val1, old_val2,\n                                                           new_val1, new_val2);\n}\n#define AO_HAVE_compare_double_and_swap_double_full\n#endif /* AO_WEAK_DOUBLE_CAS_EMULATION */\n#endif /* AO_CMPXCHG16B_AVAILABLE */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/gc.c",
    "content": "/*\n * File:\n *   gc.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Epoch-based garbage collector.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdint.h>\n\n#include <pthread.h>\n\n#include \"gc.h\"\n\n#include \"atomic.h\"\n#include \"stm.h\"\n\n/* TODO: could be made much more efficient by allocating large chunks. */\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n\n#define MAX_THREADS                     1024\n#define EPOCH_MAX                       (~(gc_word_t)0)\n\n#ifndef NO_PERIODIC_CLEANUP\n# ifndef CLEANUP_FREQUENCY\n#  define CLEANUP_FREQUENCY             1\n# endif /* ! CLEANUP_FREQUENCY */\n#endif /* ! NO_PERIODIC_CLEANUP */\n\n#ifdef DEBUG\n/* Note: stdio is thread-safe */\n# define IO_FLUSH                       fflush(NULL)\n# define PRINT_DEBUG(...)               printf(__VA_ARGS__); fflush(NULL)\n#else /* ! DEBUG */\n# define IO_FLUSH\n# define PRINT_DEBUG(...)\n#endif /* ! DEBUG */\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\nenum {                                  /* Descriptor status */\n  GC_NULL = 0,\n  GC_BUSY = 1,\n  GC_FREE_EMPTY = 2,\n  GC_FREE_FULL = 3\n};\n\ntypedef struct mem_block {              /* Block of allocated memory */\n  void *addr;                           /* Address of memory */\n  struct mem_block *next;               /* Next block */\n} mem_block_t;\n\ntypedef struct mem_region {             /* A list of allocated memory blocks */\n  struct mem_block *blocks;             /* Memory blocks */\n  gc_word_t ts;                         /* Allocation timestamp */\n  struct mem_region *next;              /* Next region */\n} mem_region_t;\n\ntypedef struct tm_thread {              /* Descriptor of an active thread */\n  gc_word_t used;                       /* Is this entry used? */\n  pthread_t thread;                     /* Thread descriptor */\n  gc_word_t ts;                         /* Start timestamp */\n  mem_region_t *head;                   /* First memory region(s) assigned to thread */\n  mem_region_t *tail;                   /* Last memory region(s) assigned to thread */\n#ifndef NO_PERIODIC_CLEANUP\n  unsigned int frees;                   /* How many blocks have been freed? */\n#endif /* ! NO_PERIODIC_CLEANUP */\n} tm_thread_t;\n\nstatic volatile tm_thread_t *threads;   /* Array of active threads */\nstatic volatile gc_word_t nb_threads;   /* Number of active threads */\n\nstatic gc_word_t (*current_epoch)();    /* Read the value of the current epoch */\n\n#ifdef TLS\nstatic __thread int thread_idx;\n#else /* ! TLS */\nstatic pthread_key_t thread_idx;\n#endif /* ! TLS */\n\n/* ################################################################### *\n * STATIC\n * ################################################################### */\n\n/*\n * Returns the index of the CURRENT thread.\n */\nstatic inline int gc_get_idx()\n{\n#ifdef TLS\n  return thread_idx;\n#else /* ! TLS */\n  return (int)pthread_getspecific(thread_idx);\n#endif /* ! TLS */\n}\n\n/*\n * Compute a lower bound on the minimum start time of all active transactions.\n */\nstatic inline gc_word_t gc_compute_min(gc_word_t now)\n{\n  int i;\n  gc_word_t min, ts;\n  stm_word_t used;\n\n  PRINT_DEBUG(\"==> gc_compute_min(%d)\\n\", gc_get_idx());\n\n  min = now;\n  for (i = 0; i < MAX_THREADS; i++) {\n    used = (gc_word_t)ATOMIC_LOAD(&threads[i].used);\n    if (used == GC_NULL)\n      break;\n    if (used != GC_BUSY)\n      continue;\n    /* Used entry */\n    ts = (gc_word_t)ATOMIC_LOAD(&threads[i].ts);\n    if (ts < min)\n      min = ts;\n  }\n\n  PRINT_DEBUG(\"==> gc_compute_min(%d,m=%lu)\\n\", gc_get_idx(), (unsigned long)min);\n\n  return min;\n}\n\n/*\n * Free block list.\n */\nstatic inline void gc_clean_blocks(mem_block_t *mb)\n{\n  mem_block_t *next_mb;\n\n  while (mb != NULL) {\n    PRINT_DEBUG(\"==> free(%d,a=%p)\\n\", gc_get_idx(), mb->addr);\n    free(mb->addr);\n    next_mb = mb->next;\n    free(mb);\n    mb = next_mb;\n  }\n}\n\n/*\n * Free region list.\n */\nstatic inline void gc_clean_regions(mem_region_t *mr)\n{\n  mem_region_t *next_mr;\n\n  while (mr != NULL) {\n    gc_clean_blocks(mr->blocks);\n    next_mr = mr->next;\n    free(mr);\n    mr = next_mr;\n  }\n}\n\n/*\n * Garbage-collect old data associated with a thread.\n */\nvoid gc_cleanup_thread(int idx, gc_word_t min)\n{\n  mem_region_t *mr;\n\n  PRINT_DEBUG(\"==> gc_cleanup_thread(%d,m=%lu)\\n\", idx, (unsigned long)min);\n\n  if (threads[idx].head == NULL) {\n    /* Nothing to clean up */\n    return;\n  }\n\n  while (min > threads[idx].head->ts) {\n    gc_clean_blocks(threads[idx].head->blocks);\n    mr = threads[idx].head->next;\n    free(threads[idx].head);\n    threads[idx].head = mr;\n    if(mr == NULL) {\n      /* All memory regions deleted */\n      threads[idx].tail = NULL;\n      break;\n    }\n  }\n}\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/*\n * Initialize GC library (to be called from main thread).\n */\nvoid gc_init(gc_word_t (*epoch)())\n{\n  int i;\n\n  PRINT_DEBUG(\"==> gc_init()\\n\");\n\n  current_epoch = epoch;\n  if ((threads = (tm_thread_t *)malloc(MAX_THREADS * sizeof(tm_thread_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  for (i = 0; i < MAX_THREADS; i++) {\n    threads[i].used = GC_NULL;\n    threads[i].ts = EPOCH_MAX;\n    threads[i].head = threads[i].tail = NULL;\n#ifndef NO_PERIODIC_CLEANUP\n    threads[i].frees = 0;\n#endif /* ! NO_PERIODIC_CLEANUP */\n  }\n  nb_threads = 0;\n#ifndef TLS\n  if (pthread_key_create(&thread_idx, NULL) != 0) {\n    fprintf(stderr, \"Error creating thread local\\n\");\n    exit(1);\n  }\n#endif /* ! TLS */\n}\n\n/*\n * Clean up GC library (to be called from main thread).\n */\nvoid gc_exit()\n{\n  int i;\n\n  PRINT_DEBUG(\"==> gc_exit()\\n\");\n\n  /* Make sure that all threads have been stopped */\n  if (ATOMIC_LOAD(&nb_threads) != 0) {\n    fprintf(stderr, \"Error: some threads have not been cleaned up\\n\");\n    exit(1);\n  }\n  /* Clean up memory */\n  for (i = 0; i < MAX_THREADS; i++)\n    gc_clean_regions(threads[i].head);\n\n  free((void *)threads);\n}\n\n/*\n * Initialize thread-specific GC resources (to be called once by each thread).\n */\nvoid gc_init_thread()\n{\n  int i, idx;\n  gc_word_t used;\n\n  PRINT_DEBUG(\"==> gc_init_thread()\\n\");\n\n  if (ATOMIC_FETCH_INC_FULL(&nb_threads) >= MAX_THREADS) {\n    fprintf(stderr, \"Error: too many concurrent threads created\\n\");\n    exit(1);\n  }\n  /* Find entry in threads array */\n  i = 0;\n  /* TODO: not wait-free */\n  while (1) {\n    used = (gc_word_t)ATOMIC_LOAD(&threads[i].used);\n    if (used != GC_BUSY) {\n      if (ATOMIC_CAS_FULL(&threads[i].used, used, GC_BUSY) != 0) {\n        idx = i;\n        /* Sets lower bound to current time (transactions by this thread cannot happen before) */\n        ATOMIC_STORE(&threads[idx].ts, current_epoch());\n        break;\n      }\n      /* CAS failed: anotehr thread must have acquired slot */\n      assert (threads[i].used != GC_NULL);\n    }\n    if (++i >= MAX_THREADS)\n      i = 0;\n  }\n#ifdef TLS\n  thread_idx = idx;\n#else /* ! TLS */\n  pthread_setspecific(thread_idx, (void *)idx);\n#endif /* ! TLS */\n\n  PRINT_DEBUG(\"==> gc_init_thread(i=%d)\\n\", idx);\n}\n\n/*\n * Clean up thread-specific GC resources (to be called once by each thread).\n */\nvoid gc_exit_thread()\n{\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_exit_thread(%d)\\n\", idx);\n\n  /* No more lower bound for this thread */\n  ATOMIC_STORE(&threads[idx].ts, EPOCH_MAX);\n  /* Release slot */\n  ATOMIC_STORE(&threads[idx].used, threads[idx].head == NULL ? GC_FREE_EMPTY : GC_FREE_FULL);\n  ATOMIC_FETCH_DEC_FULL(&nb_threads);\n  /* Leave memory for next thread to cleanup */\n}\n\n/*\n * Set new epoch (to be called by each thread, typically when starting\n * new transactions to indicate their start timestamp).\n */\nvoid gc_set_epoch(gc_word_t epoch)\n{\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_set_epoch(%d,%lu)\\n\", idx, (unsigned long)epoch);\n\n  if (epoch >= EPOCH_MAX) {\n    fprintf(stderr, \"Exceeded maximum epoch number: 0x%lx\\n\", (unsigned long)epoch);\n    /* Do nothing (will prevent data from being garbage collected) */\n    return;\n  }\n\n  /* Do not need a barrier as we only compute lower bounds */\n  ATOMIC_STORE(&threads[idx].ts, epoch);\n}\n\n/*\n * Free memory (the thread must indicate the current timestamp).\n */\nvoid gc_free(void *addr, gc_word_t epoch)\n{\n  mem_region_t *mr;\n  mem_block_t *mb;\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_free(%d,%lu)\\n\", idx, (unsigned long)epoch);\n\n  if (threads[idx].head == NULL || threads[idx].head->ts < epoch) {\n    /* Allocate a new region */\n    if ((mr = (mem_region_t *)malloc(sizeof(mem_region_t))) == NULL) {\n      perror(\"malloc\");\n      exit(1);\n    }\n    mr->ts = epoch;\n    mr->blocks = NULL;\n    mr->next = NULL;\n    if (threads[idx].head == NULL) {\n      threads[idx].head = threads[idx].tail = mr;\n    } else {\n      threads[idx].tail->next = mr;\n      threads[idx].tail = mr;\n    }\n  } else {\n    /* Add to current region */\n    mr = threads[idx].head;\n  }\n\n  /* Allocate block */\n  if ((mb = (mem_block_t *)malloc(sizeof(mem_block_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mb->addr = addr;\n  mb->next = mr->blocks;\n  mr->blocks = mb;\n\n#ifndef NO_PERIODIC_CLEANUP\n  threads[idx].frees++;\n  if (threads[idx].frees % CLEANUP_FREQUENCY == 0)\n    gc_cleanup();\n#endif /* ! NO_PERIODIC_CLEANUP */\n}\n\n/*\n * Garbage-collect old data associated with the current thread (should\n * be called periodically).\n */\nvoid gc_cleanup()\n{\n  gc_word_t min;\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_cleanup(%d)\\n\", idx);\n\n  if (threads[idx].head == NULL) {\n    /* Nothing to clean up */\n    return;\n  }\n\n  min = gc_compute_min(current_epoch());\n\n  gc_cleanup_thread(idx, min);\n}\n\n/*\n * Garbage-collect old data associated with all threads (should be\n * called periodically).\n */\nvoid gc_cleanup_all()\n{\n  int i;\n  gc_word_t min = EPOCH_MAX;\n\n  PRINT_DEBUG(\"==> gc_cleanup_all()\\n\");\n\n  for (i = 0; i < MAX_THREADS; i++) {\n    if ((gc_word_t)ATOMIC_LOAD(&threads[i].used) == GC_NULL)\n      break;\n    if ((gc_word_t)ATOMIC_LOAD(&threads[i].used) == GC_FREE_FULL) {\n      if (ATOMIC_CAS_FULL(&threads[i].used, GC_FREE_FULL, GC_BUSY) != 0) {\n        if (min == EPOCH_MAX)\n          min = gc_compute_min(current_epoch());\n        gc_cleanup_thread(i, min);\n        ATOMIC_STORE(&threads[i].used, threads[i].head == NULL ? GC_FREE_EMPTY : GC_FREE_FULL);\n      }\n    }\n  }\n}\n\n/*\n * Reset all epochs for all threads (must be called with all threads\n * stopped and out of transactions, e.g., upon roll-over).\n */\nvoid gc_reset()\n{\n  int i;\n\n  PRINT_DEBUG(\"==> gc_reset()\\n\");\n\n  assert(nb_threads == 0);\n\n  for (i = 0; i < MAX_THREADS; i++) {\n    if (threads[i].used == GC_NULL)\n      break;\n    gc_clean_regions(threads[i].head);\n    threads[i].ts = EPOCH_MAX;\n    threads[i].head = threads[i].tail = NULL;\n#ifndef NO_PERIODIC_CLEANUP\n    threads[i].frees = 0;\n#endif /* ! NO_PERIODIC_CLEANUP */\n  }\n}\n"
  },
  {
    "path": "stms/estm-0.3.0/src/gc.h",
    "content": "/*\n * File:\n *   gc.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Epoch-based garbage collector.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#ifndef _GC_H_\n# define _GC_H_\n\n# include <stdlib.h>\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\ntypedef uintptr_t gc_word_t;\n\nvoid gc_init(gc_word_t (*epoch)());\nvoid gc_exit();\n\nvoid gc_init_thread();\nvoid gc_exit_thread();\n\nvoid gc_set_epoch(gc_word_t epoch);\n\nvoid gc_free(void *addr, gc_word_t epoch);\n\nvoid gc_cleanup();\n\nvoid gc_cleanup_all();\n\nvoid gc_reset();\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _GC_H_ */\n"
  },
  {
    "path": "stms/estm-0.3.0/src/mod_local.c",
    "content": "/*\n * File:\n *   mod_local.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module for local memory accesses.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"mod_local.h\"\n\n#include \"stm.h\"\n\n#ifndef LW_SET_SIZE\n# define LW_SET_SIZE                    1024\n#endif /* ! LW_SET_SIZE */\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\nenum {\n  TYPE_WORD,\n  TYPE_CHAR,\n  TYPE_UCHAR,\n  TYPE_SHORT,\n  TYPE_USHORT,\n  TYPE_INT,\n  TYPE_UINT,\n  TYPE_LONG,\n  TYPE_ULONG,\n  TYPE_FLOAT,\n  TYPE_DOUBLE\n};\n\ntypedef struct w_entry {                /* Write set entry */\n  int type;                             /* Data type */\n  union {                               /* Address written and old value */\n    struct { volatile char *a; char v; } c;\n    struct { volatile unsigned char *a; unsigned char v; } uc;\n    struct { volatile short *a; short v; } s;\n    struct { volatile unsigned short *a; unsigned short v; } us;\n    struct { volatile int *a; int v; } i;\n    struct { volatile unsigned int *a; unsigned int v; } ui;\n    struct { volatile long *a; long v; } l;\n    struct { volatile unsigned long *a; unsigned long v; } ul;\n    struct { volatile float *a; float v; } f;\n    struct { volatile double *a; double v; } d;\n    struct { volatile stm_word_t *a; stm_word_t v; } w;\n  } data;\n} w_entry_t;\n\ntypedef struct w_set {                  /* Write set */\n  w_entry_t *entries;                   /* Array of entries */\n  int nb_entries;                       /* Number of entries */\n  int size;                             /* Size of array */\n} w_set_t;\n\nstatic int key;\nstatic int initialized = 0;\n\n/* ################################################################### *\n * STATIC\n * ################################################################### */\n\n/*\n * Called by the CURRENT thread to write to local memory.\n */\nstatic inline w_entry_t *get_entry(TXPARAM)\n{\n  w_set_t *ws;\n\n  if (!initialized) {\n    fprintf(stderr, \"Module mod_local not initialized\\n\");\n    exit(1);\n  }\n\n  /* Store in undo log */\n  ws = (w_set_t *)stm_get_specific(TXARGS key);\n  assert(ws != NULL);\n\n  if (ws->nb_entries == ws->size) {\n    /* Extend read set */\n    ws->size = (ws->size < LW_SET_SIZE ? LW_SET_SIZE : ws->size * 2);\n    if ((ws->entries = (w_entry_t *)realloc(ws->entries, ws->size * sizeof(w_entry_t))) == NULL) {\n      perror(\"realloc\");\n      exit(1);\n    }\n  }\n\n  return &ws->entries[ws->nb_entries++];\n}\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\nvoid stm_store_local(TXPARAMS stm_word_t *addr, stm_word_t value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_WORD;\n  w->data.w.a = addr;\n  w->data.w.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_char(TXPARAMS char *addr, char value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_CHAR;\n  w->data.c.a = addr;\n  w->data.c.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_uchar(TXPARAMS unsigned char *addr, unsigned char value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_UCHAR;\n  w->data.uc.a = addr;\n  w->data.uc.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_short(TXPARAMS short *addr, short value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_SHORT;\n  w->data.s.a = addr;\n  w->data.s.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_ushort(TXPARAMS unsigned short *addr, unsigned short value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_USHORT;\n  w->data.us.a = addr;\n  w->data.us.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_int(TXPARAMS int *addr, int value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_INT;\n  w->data.i.a = addr;\n  w->data.i.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_uint(TXPARAMS unsigned int *addr, unsigned int value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_UINT;\n  w->data.ui.a = addr;\n  w->data.ui.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_long(TXPARAMS long *addr, long value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_LONG;\n  w->data.l.a = addr;\n  w->data.l.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_ulong(TXPARAMS unsigned long *addr, unsigned long value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_ULONG;\n  w->data.ul.a = addr;\n  w->data.ul.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_float(TXPARAMS float *addr, float value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_FLOAT;\n  w->data.f.a = addr;\n  w->data.f.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_double(TXPARAMS double *addr, double value)\n{\n  w_entry_t *w = get_entry(TXARG);\n\n  w->type = TYPE_DOUBLE;\n  w->data.d.a = addr;\n  w->data.d.v = *addr;\n\n  /* Write to memory */\n  *addr = value;\n}\n\nvoid stm_store_local_ptr(TXPARAMS void **addr, void *value)\n{\n  union { stm_word_t w; void *v; } convert;\n  convert.v = value;\n  stm_store_local(TXARGS (stm_word_t *)addr, convert.w);\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void on_thread_init(TXPARAMS void *arg)\n{\n  w_set_t *ws;\n\n  if ((ws = (w_set_t *)malloc(sizeof(w_set_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  ws->entries = NULL;\n  ws->nb_entries = ws->size = 0;\n\n  stm_set_specific(TXARGS key, ws);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void on_thread_exit(TXPARAMS void *arg)\n{\n  w_set_t *ws;\n\n  ws = (w_set_t *)stm_get_specific(TXARGS key);\n  assert(ws != NULL);\n\n  free(ws->entries);\n  free(ws);\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void on_commit(TXPARAMS void *arg)\n{\n  w_set_t *ws;\n\n  ws = (w_set_t *)stm_get_specific(TXARGS key);\n  assert(ws != NULL);\n\n  /* Erase undo log */\n  ws->nb_entries = 0;\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void on_abort(TXPARAMS void *arg)\n{\n  w_set_t *ws;\n  int i;\n\n  ws = (w_set_t *)stm_get_specific(TXARGS key);\n  assert(ws != NULL);\n\n  /* Apply undo log */\n  for (i = ws->nb_entries - 1; i >= 0; i--) {\n    switch (ws->entries[i].type) {\n     case TYPE_WORD:\n       *ws->entries[i].data.w.a = ws->entries[i].data.w.v;\n       break;\n     case TYPE_CHAR:\n       *ws->entries[i].data.c.a = ws->entries[i].data.c.v;\n       break;\n     case TYPE_UCHAR:\n       *ws->entries[i].data.uc.a = ws->entries[i].data.uc.v;\n       break;\n     case TYPE_SHORT:\n       *ws->entries[i].data.s.a = ws->entries[i].data.s.v;\n       break;\n     case TYPE_USHORT:\n       *ws->entries[i].data.us.a = ws->entries[i].data.us.v;\n       break;\n     case TYPE_INT:\n       *ws->entries[i].data.i.a = ws->entries[i].data.i.v;\n       break;\n     case TYPE_UINT:\n       *ws->entries[i].data.ui.a = ws->entries[i].data.ui.v;\n       break;\n     case TYPE_LONG:\n       *ws->entries[i].data.l.a = ws->entries[i].data.l.v;\n       break;\n     case TYPE_ULONG:\n       *ws->entries[i].data.ul.a = ws->entries[i].data.ul.v;\n       break;\n     case TYPE_FLOAT:\n       *ws->entries[i].data.f.a = ws->entries[i].data.f.v;\n       break;\n     case TYPE_DOUBLE:\n       *ws->entries[i].data.d.a = ws->entries[i].data.d.v;\n       break;\n     default:\n       fprintf(stderr, \"Unexpected entry in undo log\\n\");\n       abort();\n       exit(1);\n    }\n  }\n}\n\n/*\n * Initialize module.\n */\nvoid mod_local_init()\n{\n  if (initialized)\n    return;\n\n  stm_register(on_thread_init, on_thread_exit, NULL, on_commit, on_abort, NULL);\n  key = stm_create_specific();\n  if (key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  initialized = 1;\n}\n"
  },
  {
    "path": "stms/estm-0.3.0/src/mod_mem.c",
    "content": "/*\n * File:\n *   mod_mem.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Vincent Gramoli <vincent.gramoli@epfl.ch>\n * Description:\n *   Module for dynamic memory management.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"mod_mem.h\"\n\n#include \"gc.h\"\n#include \"stm.h\"\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef struct mem_block {              /* Block of allocated memory */\n  void *addr;                           /* Address of memory */\n  struct mem_block *next;               /* Next block */\n} mem_block_t;\n\ntypedef struct mem_info {               /* Memory descriptor */\n  mem_block_t *allocated;               /* Memory allocated by this transation (freed upon abort) */\n  mem_block_t *freed;                   /* Memory freed by this transation (freed upon commit) */\n} mem_info_t;\n\nstatic int key;\nstatic int initialized = 0;\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/*\n * Called by the CURRENT thread to allocate memory within a transaction.\n */\nvoid *stm_malloc(TXPARAMS size_t size)\n{\n  /* Memory will be freed upon abort */\n  mem_info_t *mi;\n  mem_block_t *mb;\n\n  if (!initialized) {\n    fprintf(stderr, \"Module mod_mem not initialized\\n\");\n    exit(1);\n  }\n\n  mi = (mem_info_t *)stm_get_specific(TXARGS key);\n  assert(mi != NULL);\n\n  /* Round up size */\n  if (sizeof(stm_word_t) == 4) {\n    size = (size + 3) & ~(size_t)0x03;\n  } else {\n    size = (size + 7) & ~(size_t)0x07;\n  }\n\n  if ((mb = (mem_block_t *)malloc(sizeof(mem_block_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  if ((mb->addr = malloc(size)) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mb->next = mi->allocated;\n  mi->allocated = mb;\n\n  return mb->addr;\n}\n\n/*\n * Called by the CURRENT thread to free memory within a transaction.\n */\nvoid stm_free(TXPARAMS void *addr, size_t size)\n{\n  stm_free2(TXARGS addr, 0, size);\n}\n\n/*\n * Called by the CURRENT thread to free memory within a transaction.\n */\nvoid stm_free2(TXPARAMS void *addr, size_t idx, size_t size)\n{\n  /* Memory disposal is delayed until commit */\n  mem_info_t *mi;\n  mem_block_t *mb;\n  stm_word_t *a;\n\n  if (!initialized) {\n    fprintf(stderr, \"Module mod_mem not initialized\\n\");\n    exit(1);\n  }\n\n  mi = (mem_info_t *)stm_get_specific(TXARGS key);\n  assert(mi != NULL);\n\n  /* TODO: if block allocated in same transaction => no need to overwrite */\n  if (size > 0) {\n    /* Overwrite to prevent inconsistent reads */\n    if (sizeof(stm_word_t) == 4) {\n      idx = (idx + 3) >> 2;\n      size = (size + 3) >> 2;\n    } else {\n      idx = (idx + 7) >> 3;\n      size = (size + 7) >> 3;\n    }\n    a = (stm_word_t *)addr + idx;\n    while (size-- > 0) {\n      /* Acquire lock and update version number */\n\t  stm_store2(TXARGS a++, 0, 0);\n    }\n  }\n  /* Schedule for removal */\n  if ((mb = (mem_block_t *)malloc(sizeof(mem_block_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mb->addr = addr;\n  mb->next = mi->freed;\n  mi->freed = mb;\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void on_thread_init(TXPARAMS void *arg)\n{\n  mem_info_t *mi;\n\n  if ((mi = (mem_info_t *)malloc(sizeof(mem_info_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mi->allocated = mi->freed = NULL;\n\n  stm_set_specific(TXARGS key, mi);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void on_thread_exit(TXPARAMS void *arg)\n{\n  free(stm_get_specific(TXARGS key));\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void on_commit(TXPARAMS void *arg)\n{\n  mem_info_t *mi;\n  mem_block_t *mb, *next;\n\n  mi = (mem_info_t *)stm_get_specific(TXARGS key);\n  assert(mi != NULL);\n\n  /* Keep memory allocated during transaction */\n  if (mi->allocated != NULL) {\n    mb = mi->allocated;\n    while (mb != NULL) {\n      next = mb->next;\n      free(mb);\n      mb = next;\n    }\n    mi->allocated = NULL;\n  }\n\n  /* Dispose of memory freed during transaction */\n  if (mi->freed != NULL) {\n#ifdef EPOCH_GC\n    stm_word_t t = stm_get_clock();\n#endif /* EPOCH_GC */\n    mb = mi->freed;\n    while (mb != NULL) {\n      next = mb->next;\n#ifdef EPOCH_GC\n      gc_free(mb->addr, t);\n#else /* ! EPOCH_GC */\n      free(mb->addr);\n#endif /* ! EPOCH_GC */\n      free(mb);\n      mb = next;\n    }\n    mi->freed = NULL;\n  }\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void on_abort(TXPARAMS void *arg)\n{\n  mem_info_t *mi;\n  mem_block_t *mb, *next;\n\n  mi = (mem_info_t *)stm_get_specific(TXARGS key);\n  assert (mi != NULL);\n\n  /* Dispose of memory allocated during transaction */\n  if (mi->allocated != NULL) {\n    mb = mi->allocated;\n    while (mb != NULL) {\n      next = mb->next;\n      free(mb->addr);\n      free(mb);\n      mb = next;\n    }\n    mi->allocated = NULL;\n  }\n\n  /* Keep memory freed during transaction */\n  if (mi->freed != NULL) {\n    mb = mi->freed;\n    while (mb != NULL) {\n      next = mb->next;\n      free(mb);\n      mb = next;\n    }\n    mi->freed = NULL;\n  }\n}\n\n/*\n * Initialize module.\n */\nvoid mod_mem_init()\n{\n  if (initialized)\n    return;\n\n  stm_register(on_thread_init, on_thread_exit, NULL, on_commit, on_abort, NULL);\n  key = stm_create_specific();\n  if (key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  initialized = 1;\n}\n"
  },
  {
    "path": "stms/estm-0.3.0/src/mod_print.c",
    "content": "/*\n * File:\n *   mod_print.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module to test callbacks.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include \"mod_print.h\"\n\n#include \"stm.h\"\n\n/*\n * Called upon thread creation.\n */\nstatic void on_thread_init(TXPARAMS void *arg)\n{\n  printf(\"==> on_thread_init()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void on_thread_exit(TXPARAMS void *arg)\n{\n  printf(\"==> on_thread_exit()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon transaction start.\n */\nstatic void on_start(TXPARAMS void *arg)\n{\n  printf(\"==> on_start()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void on_commit(TXPARAMS void *arg)\n{\n  printf(\"==> on_commit()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void on_abort(TXPARAMS void *arg)\n{\n  printf(\"==> on_abort()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Initialize module.\n */\nvoid mod_print_init()\n{\n  stm_register(on_thread_init, on_thread_exit, on_start, on_commit, on_abort, NULL);\n}\n"
  },
  {
    "path": "stms/estm-0.3.0/src/mod_stats.c",
    "content": "/*\n * File:\n *   mod_stats.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   Module for gathering global statistics about transactions.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"mod_stats.h\"\n\n#include \"atomic.h\"\n#include \"stm.h\"\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef struct tx_stats {               /* Transaction statistics */\n  unsigned long commits;                /* Total number of commits (cumulative) */\n  unsigned long aborts;                 /* Total number of aborts (cumulative) */\n  unsigned long retries;                /* Number of consecutive aborts (retries) */\n  unsigned long max_retries;            /* Maximum number of consecutive aborts (retries) */\n} tx_stats_t;\n\nstatic int key;\nstatic int initialized = 0;\n\nstatic tx_stats_t global_stats = { 0, 0, 0, 0 };\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/*\n * Return aggregate statistics about transactions.\n */\nint stm_get_global_stats(const char *name, void *val)\n{\n  if (!initialized) {\n    fprintf(stderr, \"Module mod_stats not initialized\\n\");\n    exit(1);\n  }\n\n  if (strcmp(\"global_nb_commits\", name) == 0) {\n    *(unsigned long *)val = global_stats.commits;\n    return 1;\n  }\n  if (strcmp(\"global_nb_aborts\", name) == 0) {\n    *(unsigned long *)val = global_stats.aborts;\n    return 1;\n  }\n  if (strcmp(\"global_max_retries\", name) == 0) {\n    *(unsigned long *)val = global_stats.max_retries;\n    return 1;\n  }\n\n  return 0;\n}\n\n/*\n * Return statistics about current thread.\n */\nint stm_get_local_stats(TXPARAMS const char *name, void *val)\n{\n  tx_stats_t *stats;\n\n  if (!initialized) {\n    fprintf(stderr, \"Module mod_stats not initialized\\n\");\n    exit(1);\n  }\n\n  stats = (tx_stats_t *)stm_get_specific(TXARGS key);\n  assert(stats != NULL);\n\n  if (strcmp(\"nb_commits\", name) == 0) {\n    *(unsigned long *)val = stats->commits;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts\", name) == 0) {\n    *(unsigned long *)val = stats->aborts;\n    return 1;\n  }\n  if (strcmp(\"max_retries\", name) == 0) {\n    *(unsigned long *)val = stats->max_retries;\n    return 1;\n  }\n\n  return 0;\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void on_thread_init(TXPARAMS void *arg)\n{\n  tx_stats_t *stats;\n\n  if ((stats = (tx_stats_t *)malloc(sizeof(tx_stats_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  stats->commits = 0;\n  stats->aborts = 0;\n  stats->retries = 0;\n  stats->max_retries = 0;\n\n  stm_set_specific(TXARGS key, stats);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void on_thread_exit(TXPARAMS void *arg)\n{\n  tx_stats_t *stats;\n  unsigned long max;\n\n  stats = (tx_stats_t *)stm_get_specific(TXARGS key);\n  assert(stats != NULL);\n\n  ATOMIC_FETCH_ADD_FULL(&global_stats.commits, stats->commits);\n  ATOMIC_FETCH_ADD_FULL(&global_stats.aborts, stats->aborts);\n retry:\n  max = ATOMIC_LOAD(&global_stats.max_retries);\n  if (stats->max_retries > max) {\n    if (ATOMIC_CAS_FULL(&global_stats.max_retries, max, stats->max_retries) == 0)\n      goto retry;\n  }\n\n  free(stats);\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void on_commit(TXPARAMS void *arg)\n{\n  tx_stats_t *stats;\n\n  stats = (tx_stats_t *)stm_get_specific(TXARGS key);\n  assert(stats != NULL);\n\n  stats->commits++;\n  stats->retries = 0;\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void on_abort(TXPARAMS void *arg)\n{\n  tx_stats_t *stats;\n\n  stats = (tx_stats_t *)stm_get_specific(TXARGS key);\n  assert(stats != NULL);\n\n  stats->aborts++;\n  stats->retries++;\n  if (stats->max_retries < stats->retries)\n    stats->max_retries = stats->retries;\n}\n\n/*\n * Initialize module.\n */\nvoid mod_stats_init()\n{\n  if (initialized)\n    return;\n\n  stm_register(on_thread_init, on_thread_exit, NULL, on_commit, on_abort, NULL);\n  key = stm_create_specific();\n  if (key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  initialized = 1;\n}\n"
  },
  {
    "path": "stms/estm-0.3.0/src/stm.c",
    "content": "/*\n * File:\n *   stm.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Vincent Gramoli <vincent.gramoli@epfl.ch>\n * Description:\n *   STM functions.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include <assert.h>\n#include <signal.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <pthread.h>\n#include <sched.h>\n\n#include \"stm.h\"\n#include \"atomic.h\"\n#include \"gc.h\"\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n\n#define COMPILE_TIME_ASSERT(pred)       switch (0) { case 0: case pred: ; }\n\n/* Designs */\n#define WRITE_BACK_ETL                  0\n#define WRITE_BACK_CTL                  1\n#define WRITE_THROUGH                   2\n\n#define EL\t\t\t\t0\n#define NL\t\t\t\t1\n\n#ifdef EXPLICIT_TX_PARAMETER\n# define TX_RETURN                      return tx\n# define TX_GET                         /* Nothing */\n#else /* ! EXPLICIT_TX_PARAMETER */\n# define TX_RETURN                      /* Nothing */\n# define TX_GET                         stm_tx_t *tx = stm_get_tx()\n#endif /* ! EXPLICIT_TX_PARAMETER */\n\n# define IO_FLUSH\n# define PRINT_DEBUG(...)\n# define PRINT_DEBUG2(...)\n\n#ifndef RW_SET_SIZE\n# define RW_SET_SIZE                    4096                /* Initial size of read/write sets */\n#endif /* ! RW_SET_SIZE */\n\n#ifndef LOCK_ARRAY_LOG_SIZE\n# define LOCK_ARRAY_LOG_SIZE            20                  /* Size of lock array: 2^20 = 1M */\n#endif /* LOCK_ARRAY_LOG_SIZE */\n\n#ifndef LOCK_SHIFT_EXTRA\n# define LOCK_SHIFT_EXTRA               2                   /* 2 extra shift */\n#endif /* LOCK_SHIFT_EXTRA */\n\n#define XSTR(s)                         STR(s)\n#define STR(s)                          #s\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\nenum {                                  /* Transaction status */\n  TX_IDLE = 0,\n  TX_ACTIVE = 1,\n  TX_COMMITTED = 2,\n  TX_ABORTED = 3\n};\n\ntypedef struct r_entry {                /* Read set entry */\n  stm_word_t version;                   /* Version read */\n  volatile stm_word_t *lock;            /* Pointer to lock (for fast access) */\n} r_entry_t;\n\ntypedef struct r_set {                  /* Read set */\n  r_entry_t *entries;                   /* Array of entries */\n  int nb_entries;                       /* Number of entries */\n  int size;                             /* Size of array */\n} r_set_t;\n\ntypedef struct w_entry {                /* Write set entry */\n  union {                               /* For padding... */\n    struct {\n      volatile stm_word_t *addr;        /* Address written */\n      stm_word_t value;                 /* New (write-back) or old (write-through) value */\n      stm_word_t mask;                  /* Write mask */\n      stm_word_t version;               /* Version overwritten */\n      volatile stm_word_t *lock;        /* Pointer to lock (for fast access) */\n      struct w_entry *next;             /* Next address covered by same lock (if any) */\n    };\n  };\n} w_entry_t;\n\ntypedef struct w_set {                  /* Write set */\n  w_entry_t *entries;                   /* Array of entries */\n  int nb_entries;                       /* Number of entries */\n  int size;                             /* Size of array */\n  int reallocate;                       /* Reallocate on next start */\n} w_set_t;\n\n#define ELASTICITY                      2\n#ifndef MAX_SPECIFIC\n# define MAX_SPECIFIC                   16\n#endif /* MAX_SPECIFIC */\n\ntypedef struct stm_tx {                 /* Transaction descriptor */\n  stm_tx_attr_t *attr;                  /* Transaction attributes (user-specified) */\n  stm_word_t status;                    /* Transaction status (not read by other threads) */\n  stm_word_t start;                     /* Start timestamp */\n  stm_word_t end;                       /* End timestamp (validity range) */\n  r_set_t r_set;                        /* Read set */\n  w_set_t w_set;                        /* Write set */\n  sigjmp_buf env;                       /* Environment for setjmp/longjmp */\n  sigjmp_buf *jmp;                      /* Pointer to environment (NULL when not using setjmp/longjmp) */\n  int nesting;                          /* Nesting level */\n  int ro;                               /* Is this execution read-only? */\n  int can_extend;                       /* Can this transaction be extended? */\n  void *data[MAX_SPECIFIC];             /* Transaction-specific data (fixed-size array for better speed) */\n  unsigned long retries;                /* Number of consecutive aborts (retries) */\n  unsigned long aborts;                 /* Total number of aborts (cumulative) */\n  unsigned long aborts_ro;              /* Aborts due to wrong read-only specification (cumulative) */\n  unsigned long aborts_locked_read;     /* Aborts due to trying to read when locked (cumulative) */\n  unsigned long aborts_locked_write;    /* Aborts due to trying to write when locked (cumulative) */\n  unsigned long aborts_validate_read;   /* Aborts due to failed validation upon read (cumulative) */\n  unsigned long aborts_validate_write;  /* Aborts due to failed validation upon write (cumulative) */\n  unsigned long aborts_validate_commit; /* Aborts due to failed validation upon commit (cumulative) */\n  unsigned long aborts_invalid_memory;  /* Aborts due to invalid memory access (cumulative) */\n  unsigned long aborts_double_write;    /* Aborts due to impossible cut of elastic tx */ \n  unsigned long aborts_reallocate;      /* Aborts due to write set reallocation (cumulative) */\n  unsigned long aborts_rollover;        /* Aborts due to clock rolling over (cumulative) */\n  unsigned long max_retries;            /* Maximum number of consecutive aborts (retries) */\n  int type;\t\t\t\t/* Is this transaction normal (NL=1) or elastic (EL=0)? */\n  stm_word_t *lastraddr[ELASTICITY];\t/* Elastic rotating buffer, keep track of the last read values (if elastic) */\n  int marker;                           /* Marker for the elastic rotating buffer */\n} stm_tx_t;\n\nstatic int nb_specific = 0;             /* Number of specific slots used (<= MAX_SPECIFIC) */\n\n/*\n * Transaction nesting is supported in a minimalist way (flat nesting):\n * - When a transaction is started in the context of another\n *   transaction, we simply increment a nesting counter but do not\n *   actually start a new transaction.\n * - The environment to be used for setjmp/longjmp is only returned when\n *   no transaction is active so that it is not overwritten by nested\n *   transactions. This allows for composability as the caller does not\n *   need to know whether it executes inside another transaction.\n * - The commit of a nested transaction simply decrements the nesting\n *   counter. Only the commit of the top-level transaction will actually\n *   carry through updates to shared memory.\n * - An abort of a nested transaction will rollback the top-level\n *   transaction and reset the nesting counter. The call to longjmp will\n *   restart execution before the top-level transaction.\n * Using nested transactions without setjmp/longjmp is not recommended\n * as one would need to explicitly jump back outside of the top-level\n * transaction upon abort of a nested transaction. This breaks\n * composability.\n */\n\n/*\n * Reading from the previous version of locked addresses is implemented\n * by peeking into the write set of the transaction that owns the\n * lock. Each transaction has a unique identifier, updated even upon\n * retry. A special \"commit\" bit of this identifier is set upon commit,\n * right before writing the values from the redo log to shared memory. A\n * transaction can read a locked address if the identifier of the owner\n * does not change between before and after reading the value and\n * version, and it does not have the commit bit set.\n */\n\n/* ################################################################### *\n * CALLBACKS\n * ################################################################### */\n\ntypedef struct cb_entry {               /* Callback entry */\n  void (*f)(TXPARAMS void *);           /* Function */\n  void *arg;                            /* Argument to be passed to function */\n} cb_entry_t;\n\n#define MAX_CB                          16\n\n/* Declare as static arrays (vs. lists) to improve cache locality */\nstatic cb_entry_t init_cb[MAX_CB];      /* Init thread callbacks */\nstatic cb_entry_t exit_cb[MAX_CB];      /* Exit thread callbacks */\nstatic cb_entry_t start_cb[MAX_CB];     /* Start callbacks */\nstatic cb_entry_t commit_cb[MAX_CB];    /* Commit callbacks */\nstatic cb_entry_t abort_cb[MAX_CB];     /* Abort callbacks */\n\nstatic int nb_init_cb = 0;\nstatic int nb_exit_cb = 0;\nstatic int nb_start_cb = 0;\nstatic int nb_commit_cb = 0;\nstatic int nb_abort_cb = 0;\n\n/* ################################################################### *\n * THREAD-LOCAL\n * ################################################################### */\n\n#ifdef TLS\nstatic __thread stm_tx_t* thread_tx;\n#else /* ! TLS */\nstatic pthread_key_t thread_tx;\n#endif /* ! TLS */\n\n/* ################################################################### *\n * LOCKS\n * ################################################################### */\n\n/*\n * A lock is a unsigned int of the size of a pointer.\n * The LSB is the lock bit. If it is set, this means:\n * - At least some covered memory addresses is being written.\n * - Write-back (ETL): all bits of the lock apart from the lock bit form\n *   a pointer that points to the write log entry holding the new\n *   value. Multiple values covered by the same log entry and orginized\n *   in a linked list in the write log.\n * - Write-through and write-back (CTL): all bits of the lock apart from\n *   the lock bit form a pointer that points to the transaction\n *   descriptor containing the write-set.\n * If the lock bit is not set, then:\n * - All covered memory addresses contain consistent values.\n * - Write-back (ETL and CTL): all bits of the lock besides the lock bit\n *   contain a version number (timestamp).\n * - Write-through: all bits of the lock besides the lock bit contain a\n *   version number.\n *   - The high order bits contain the commit time.\n *   - The low order bits contain an incarnation number (incremented\n *     upon abort while writing the covered memory addresses).\n * When using the PRIORITY contention manager, the format of locks is\n * slightly different. It is documented elsewhere.\n */\n\n#define OWNED_MASK                      0x01                /* 1 bit */\n#define VERSION_MAX                    (~(stm_word_t)0 >> 1)\n\n#define LOCK_GET_OWNED(l)               (l & OWNED_MASK)\n#define LOCK_SET_ADDR(a)               (a | OWNED_MASK)    /* OWNED bit set */\n#define LOCK_GET_ADDR(l)               (l & ~(stm_word_t)OWNED_MASK)\n#define LOCK_GET_TIMESTAMP(l)          (l >> 1)            /* Logical shift (unsigned) */\n#define LOCK_SET_TIMESTAMP(t)          (t << 1)            /* OWNED bit not set */\n#define LOCK_UNIT                       (~(stm_word_t)0)\n\n/*\n * We use the very same hash functions as TL2 for degenerate Bloom\n * filters on 32 bits.\n */\n\n/*\n * We use an array of locks and hash the address to find the location of the lock.\n * We try to avoid collisions as much as possible (two addresses covered by the same lock).\n */\n#define LOCK_ARRAY_SIZE                 (1 << LOCK_ARRAY_LOG_SIZE)\n#define LOCK_MASK                       (LOCK_ARRAY_SIZE - 1)\n#define LOCK_SHIFT                      (((sizeof(stm_word_t) == 4) ? 2 : 3) + LOCK_SHIFT_EXTRA)\n#define LOCK_IDX(a)                     (((stm_word_t)(a) >> LOCK_SHIFT) & LOCK_MASK)\n#define GET_LOCK(a)                    (locks + LOCK_IDX(a))\n\nstatic volatile stm_word_t locks[LOCK_ARRAY_SIZE];\n\n/* ################################################################### *\n * CLOCK\n * ################################################################### */\n\n/* At least twice a cache line (512 bytes to be on the safe side) */\nstatic volatile stm_word_t gclock[1024 / sizeof(stm_word_t)];\n#define CLOCK                          (gclock[512 / sizeof(stm_word_t)])\n\n#define GET_CLOCK                       (ATOMIC_LOAD_ACQ(&CLOCK))\n#define FETCH_INC_CLOCK                 (ATOMIC_FETCH_INC_FULL(&CLOCK))\n\n/* ################################################################### *\n * STATIC\n * ################################################################### */\n\n/*\n * Returns the transaction descriptor for the CURRENT thread.\n */\nstatic inline stm_tx_t *stm_get_tx()\n{\n#ifdef TLS\n  return thread_tx;\n#else /* ! TLS */\n  return (stm_tx_t *)pthread_getspecific(thread_tx);\n#endif /* ! TLS */\n}\n\n\n/*\n * We use a simple approach for clock roll-over:\n * - We maintain the count of (active) transactions using a counter\n *   protected by a mutex. This approach is not very efficient but the\n *   cost is quickly amortized because we only modify the counter when\n *   creating and deleting a transaction descriptor, which typically\n *   happens much less often than starting and committing a transaction.\n * - We detect overflows when reading the clock or when incrementing it.\n *   Upon overflow, we wait until all threads have blocked on a barrier.\n * - Threads can block on the barrier upon overflow when they (1) start\n *   a transaction, or (2) delete a transaction. This means that threads\n *   must ensure that they properly delete their transaction descriptor\n *   before performing any blocking operation outside of a transaction\n *   in order to guarantee liveness (our model prohibits blocking\n *   inside a transaction).\n */\n\npthread_mutex_t tx_count_mutex;\npthread_cond_t tx_reset;\nint tx_count;\nint tx_overflow;\n\n/*\n * Enter new transactional thread.\n */\nstatic inline void stm_rollover_enter(stm_tx_t *tx)\n{\n  PRINT_DEBUG(\"==> stm_rollover_enter(%p)\\n\", tx);\n\n  pthread_mutex_lock(&tx_count_mutex);\n  while (tx_overflow != 0)\n    pthread_cond_wait(&tx_reset, &tx_count_mutex);\n  /* One more (active) transaction */\n  tx_count++;\n  pthread_mutex_unlock(&tx_count_mutex);\n}\n\n/*\n * Exit transactional thread.\n */\nstatic inline void stm_rollover_exit(stm_tx_t *tx)\n{\n  PRINT_DEBUG(\"==> stm_rollover_exit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  pthread_mutex_lock(&tx_count_mutex);\n  /* One less (active) transaction */\n  tx_count--;\n  assert(tx_count >= 0);\n  /* Are all transactions stopped? */\n  if (tx_overflow != 0 && tx_count == 0) {\n    /* Yes: reset clock */\n    memset((void *)locks, 0, LOCK_ARRAY_SIZE * sizeof(stm_word_t));\n    CLOCK = 0;\n    tx_overflow = 0;\n    /* Reset GC */\n    gc_reset();\n    /* Wake up all thread */\n    pthread_cond_broadcast(&tx_reset);\n  }\n  pthread_mutex_unlock(&tx_count_mutex);\n}\n\n/*\n * Clock overflow.\n */\nstatic inline void stm_overflow(stm_tx_t *tx)\n{\n  PRINT_DEBUG(\"==> stm_overflow(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  pthread_mutex_lock(&tx_count_mutex);\n  /* Set overflow flag (might already be set) */\n  tx_overflow = 1;\n  /* One less (active) transaction */\n  tx_count--;\n  assert(tx_count >= 0);\n  /* Are all transactions stopped? */\n  if (tx_count == 0) {\n    /* Yes: reset clock */\n    memset((void *)locks, 0, LOCK_ARRAY_SIZE * sizeof(stm_word_t));\n    CLOCK = 0;\n    tx_overflow = 0;\n    /* Reset GC */\n    gc_reset();\n    /* Wake up all thread */\n    pthread_cond_broadcast(&tx_reset);\n  } else {\n    /* No: wait for other transactions to stop */\n    pthread_cond_wait(&tx_reset, &tx_count_mutex);\n  }\n  /* One more (active) transaction */\n  tx_count++;\n  pthread_mutex_unlock(&tx_count_mutex);\n}\n\n/*\n * Check if stripe has been read previously.\n */\nstatic inline r_entry_t *stm_has_read(stm_tx_t *tx, volatile stm_word_t *lock)\n{\n  r_entry_t *r;\n  int i;\n\n  PRINT_DEBUG(\"==> stm_has_read(%p[%lu-%lu],%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, lock);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Look for read */\n  r = tx->r_set.entries;\n  for (i = tx->r_set.nb_entries; i > 0; i--, r++) {\n    if (r->lock == lock) {\n      /* Return first match*/\n      return r;\n    }\n  }\n  return NULL;\n}\n\n/*\n * (Re)allocate read set entries.\n */\nstatic inline void stm_allocate_rs_entries(stm_tx_t *tx, int extend)\n{\n  if (extend) {\n    /* Extend read set */\n    tx->r_set.size *= 2;\n    PRINT_DEBUG2(\"==> reallocate read set (%p[%lu-%lu],%d)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, tx->r_set.size);\n    if ((tx->r_set.entries = (r_entry_t *)realloc(tx->r_set.entries, tx->r_set.size * sizeof(r_entry_t))) == NULL) {\n      perror(\"realloc\");\n      exit(1);\n    }\n  } else {\n    /* Allocate read set */\n    if ((tx->r_set.entries = (r_entry_t *)malloc(tx->r_set.size * sizeof(r_entry_t))) == NULL) {\n      perror(\"malloc\");\n      exit(1);\n    }\n  }\n}\n\n/*\n * (Re)allocate write set entries.\n */\nstatic inline void stm_allocate_ws_entries(stm_tx_t *tx, int extend)\n{\n\n  if (extend) {\n    /* Extend write set */\n    tx->w_set.size *= 2;\n    PRINT_DEBUG(\"==> reallocate write set (%p[%lu-%lu],%d)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, tx->w_set.size);\n    if ((tx->w_set.entries = (w_entry_t *)realloc(tx->w_set.entries, tx->w_set.size * sizeof(w_entry_t))) == NULL) {\n      perror(\"realloc\");\n      exit(1);\n    }\n  } else {\n    /* Allocate write set */\n    if ((tx->w_set.entries = (w_entry_t *)malloc(tx->w_set.size * sizeof(w_entry_t))) == NULL) {\n      perror(\"malloc\");\n      exit(1);\n    }\n  }\n\n}\n\n/*\n * Validate read set (check if all read addresses are still valid now).\n */\nstatic inline int stm_validate(stm_tx_t *tx)\n{\n  r_entry_t *r;\n  int i;\n  stm_word_t l;\n\n  PRINT_DEBUG(\"==> stm_validate(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Validate reads */\n  r = tx->r_set.entries;\n  for (i = tx->r_set.nb_entries; i > 0; i--, r++) {\n    /* Read lock */\n    l = ATOMIC_LOAD(r->lock);\n    /* Unlocked and still the same version? */\n    if (LOCK_GET_OWNED(l)) {\n      /* Do we own the lock? */\n      w_entry_t *w = (w_entry_t *)LOCK_GET_ADDR(l);\n      /* Simply check if address falls inside our write set (avoids non-faulting load) */\n      if (!(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries))\n\t{\n\t  /* Locked by another transaction: cannot validate */\n\t  return 0;\n\t}\n      /* We own the lock: OK */\n    } else {\n      if (LOCK_GET_TIMESTAMP(l) != r->version) {\n        /* Other version: cannot validate */\n        return 0;\n      }\n      /* Same version: OK */\n    }\n  }\n  return 1;\n}\n\n/*\n * Extend snapshot range.\n */\nstatic inline int stm_extend(stm_tx_t *tx)\n{\n  stm_word_t now;\n\n  PRINT_DEBUG(\"==> stm_extend(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Get current time */\n  now = GET_CLOCK;\n  if (now >= VERSION_MAX) {\n    /* Clock overflow */\n    return 0;\n  }\n  /* Try to validate read set */\n  if (stm_validate(tx)) {\n    /* It works: we can extend until now */\n    tx->end = now;\n    return 1;\n  }\n  return 0;\n}\n\n/*\n * Rollback transaction.\n */\nstatic inline void stm_rollback(stm_tx_t *tx)\n{\n  w_entry_t *w;\n  int i;\n\n  PRINT_DEBUG(\"==> stm_rollback(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Drop locks */\n  i = tx->w_set.nb_entries;\n  if (i > 0) {\n    w = tx->w_set.entries;\n    for (; i > 0; i--, w++) {\n      if (w->next == NULL) {\n        /* Only drop lock for last covered address in write set */\n        ATOMIC_STORE(w->lock, LOCK_SET_TIMESTAMP(w->version));\n      }\n      PRINT_DEBUG2(\"==> discard(t=%p[%lu-%lu],a=%p,d=%p-%lu,v=%lu)\\n\",\n                   tx, (unsigned long)tx->start, (unsigned long)tx->end, w->addr, (void *)w->value, (unsigned long)w->value, (unsigned long)w->version);\n    }\n    /* Make sure that all lock releases become visible */\n    ATOMIC_MB_WRITE;\n  }\n\n  tx->retries++;\n  tx->aborts++;\n  if (tx->max_retries < tx->retries)\n    tx->max_retries = tx->retries;\n\n  /* Callbacks */\n  if (nb_abort_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_abort_cb; cb++)\n      abort_cb[cb].f(TXARGS abort_cb[cb].arg);\n  }\n\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_ABORTED;\n\n  /* Reset nesting level */\n  tx->nesting = 0;\n\n\n  /* Jump back to transaction start */\n  if (tx->jmp != NULL)\n    siglongjmp(*tx->jmp, 1);\n}\n\n/*\n * Store a word-sized value (return write set entry or NULL).\n */\nstatic inline w_entry_t *stm_write(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, version;\n  w_entry_t *w;\n  w_entry_t *prev = NULL;\n\n  PRINT_DEBUG2(\"==> stm_write(t=%p[%lu-%lu],a=%p,d=%p-%lu,m=0x%lx)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  if (tx->ro) {\n    /* Disable read-only and abort */\n    assert(tx->attr != NULL);\n    tx->attr->ro = 0;\n    tx->aborts_ro++;\n    stm_rollback(tx);\n    return NULL;\n  }\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Try to acquire lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked */\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries) {\n      /* Yes */\n      prev = w;\n      /* Did we previously write the same address? */\n      while (1) {\n        if (addr == prev->addr) {\n          if (mask == 0)\n            return prev;\n          /* No need to add to write set */\n          PRINT_DEBUG2(\"==> stm_write(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu,m=0x%lx)\\n\",\n                       tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, lock, (unsigned long)l, (void *)value, (unsigned long)value, (unsigned long)mask);\n          if (mask != ~(stm_word_t)0) {\n            if (prev->mask == 0)\n              prev->value = ATOMIC_LOAD(addr);\n            value = (prev->value & ~mask) | (value & mask);\n          }\n          prev->value = value;\n          prev->mask |= mask;\n          return prev;\n        }\n        if (prev->next == NULL) {\n          /* Remember last entry in linked list (for adding new entry) */\n          break;\n        }\n        prev = prev->next;\n      }\n      /* Get version from previous write set entry (all entries in linked list have same version) */\n      version = prev->version;\n      /* Must add to write set */\n      if (tx->w_set.nb_entries == tx->w_set.size) {\n        /* Extend write set (invalidate pointers to write set entries => abort and reallocate) */\n        tx->w_set.size *= 2;\n        tx->w_set.reallocate = 1;\n        tx->aborts_reallocate++;\n        stm_rollback(tx);\n        return NULL;\n      }\n      w = &tx->w_set.entries[tx->w_set.nb_entries];\n      goto do_write;\n    }\n    /* Abort */\n    tx->aborts_locked_write++;\n    stm_rollback(tx);\n    return NULL;\n  } else {\n    /* Not locked */\n    /* Handle write after reads (before CAS) */\n    version = LOCK_GET_TIMESTAMP(l);\n    if (version > tx->end) {\n      /* We might have read an older version previously */\n      if (!tx->can_extend || stm_has_read(tx, lock) != NULL) {\n        /* Read version must be older (otherwise, tx->end >= version) */\n        /* Not much we can do: abort */\n        tx->aborts_validate_write++;\n        stm_rollback(tx);\n        return NULL;\n      }\n    }\n    /* Acquire lock (ETL) */\n    if (tx->w_set.nb_entries == tx->w_set.size) {\n      /* Extend write set (invalidate pointers to write set entries => abort and reallocate) */\n      tx->w_set.size *= 2;\n      tx->w_set.reallocate = 1;\n      tx->aborts_reallocate++;\n      stm_rollback(tx);\n      return NULL;\n    }\n    w = &tx->w_set.entries[tx->w_set.nb_entries];\n    if (ATOMIC_CAS_FULL(lock, l, LOCK_SET_ADDR((stm_word_t)w)) == 0)\n      goto restart;\n  }\n  /* We own the lock here (ETL) */\n do_write:\n  PRINT_DEBUG2(\"==> stm_write(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu,m=0x%lx)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, lock, (unsigned long)l, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n  /* Add address to write set */\n  w->addr = addr;\n  w->mask = mask;\n  w->lock = lock;\n  if (mask == 0) {\n    /* Do not write anything */\n#ifndef NDEBUG\n    w->value = 0;\n#endif /* ! NDEBUG */\n  } else\n    {\n      /* Remember new value */\n      if (mask != ~(stm_word_t)0)\n\tvalue = (ATOMIC_LOAD(addr) & ~mask) | (value & mask);\n      w->value = value;\n    }\n  w->version = version;\n  w->next = NULL;\n  if (prev != NULL) {\n    /* Link new entry in list */\n    prev->next = w;\n  }\n  tx->w_set.nb_entries++;\n\n  return w;\n}\n\n\n\n/*\n * Catch signal (to emulate non-faulting load).\n */\nstatic void signal_catcher(int sig)\n{\n  stm_tx_t *tx = stm_get_tx();\n\n  /* A fault might only occur upon a load concurrent with a free (read-after-free) */\n  PRINT_DEBUG(\"Caught signal: %d\\n\", sig);\n\n  if (tx == NULL || tx->jmp == NULL) {\n    /* There is not much we can do: execution will restart at faulty load */\n    fprintf(stderr, \"Error: invalid memory accessed and no longjmp destination\\n\");\n    exit(1);\n  }\n\n  tx->aborts_invalid_memory++;\n  /* Will cause a longjmp */\n  stm_rollback(tx);\n}\n\n/* ################################################################### *\n * STM FUNCTIONS\n * ################################################################### */\n\n/*\n * Called once (from main) to initialize STM infrastructure.\n */\nvoid stm_init()\n{\n  struct sigaction act;\n\n  PRINT_DEBUG(\"==> stm_init()\\n\");\n\n  PRINT_DEBUG(\"\\tsizeof(word)=%d\\n\", (int)sizeof(stm_word_t));\n\n  PRINT_DEBUG(\"\\tVERSION_MAX=0x%lx\\n\", (unsigned long)VERSION_MAX);\n\n  COMPILE_TIME_ASSERT(sizeof(stm_word_t) == sizeof(void *));\n  COMPILE_TIME_ASSERT(sizeof(stm_word_t) == sizeof(atomic_t));\n\n  gc_init(stm_get_clock);\n\n  memset((void *)locks, 0, LOCK_ARRAY_SIZE * sizeof(stm_word_t));\n\n\n  CLOCK = 0;\n  if (pthread_mutex_init(&tx_count_mutex, NULL) != 0) {\n    fprintf(stderr, \"Error creating mutex\\n\");\n    exit(1);\n  }\n  if (pthread_cond_init(&tx_reset, NULL) != 0) {\n    fprintf(stderr, \"Error creating condition variable\\n\");\n    exit(1);\n  }\n  tx_count = 0;\n  tx_overflow = 0;\n\n#ifndef TLS\n  if (pthread_key_create(&thread_tx, NULL) != 0) {\n    fprintf(stderr, \"Error creating thread local\\n\");\n    exit(1);\n  }\n#endif /* ! TLS */\n\n  /* Catch signals for non-faulting load */\n  act.sa_handler = signal_catcher;\n  act.sa_flags = 0;\n  sigemptyset(&act.sa_mask);\n  if (sigaction(SIGBUS, &act, NULL) < 0 || sigaction(SIGSEGV, &act, NULL) < 0) {\n    perror(\"sigaction\");\n    exit(1);\n  }\n\n}\n\n/*\n * Called once (from main) to clean up STM infrastructure.\n */\nvoid stm_exit()\n{\n  PRINT_DEBUG(\"==> stm_exit()\\n\");\n\n#ifndef TLS\n  pthread_key_delete(thread_tx);\n#endif /* ! TLS */\n  pthread_cond_destroy(&tx_reset);\n  pthread_mutex_destroy(&tx_count_mutex);\n\n  gc_exit();\n}\n\n/*\n * Called by the CURRENT thread to initialize thread-local STM data.\n */\nTXTYPE stm_init_thread()\n{\n  stm_tx_t *tx;\n\n  PRINT_DEBUG(\"==> stm_init_thread()\\n\");\n\n  gc_init_thread();\n\n  /* Allocate descriptor */\n  if ((tx = (stm_tx_t *)malloc(sizeof(stm_tx_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_IDLE;\n  /* Read set */\n  tx->r_set.nb_entries = 0;\n  tx->r_set.size = RW_SET_SIZE;\n  stm_allocate_rs_entries(tx, 0);\n  /* Write set */\n  tx->w_set.nb_entries = 0;\n  tx->w_set.size = RW_SET_SIZE;\n  tx->w_set.reallocate = 0;\n  stm_allocate_ws_entries(tx, 0);\n  /* Nesting level */\n  tx->nesting = 0;\n  /* Transaction-specific data */\n  memset(tx->data, 0, MAX_SPECIFIC * sizeof(void *));\n  tx->retries = 0;\n  /* Statistics */\n  tx->aborts = 0;\n  tx->aborts_ro = 0;\n  tx->aborts_locked_read = 0;\n  tx->aborts_locked_write = 0;\n  tx->aborts_validate_read = 0;\n  tx->aborts_validate_write = 0;\n  tx->aborts_validate_commit = 0;\n  tx->aborts_invalid_memory = 0;\n  tx->aborts_reallocate = 0;\n  tx->aborts_rollover = 0;\n  tx->max_retries = 0;\n  /* Store as thread-local data */\n#ifdef TLS\n  thread_tx = tx;\n#else /* ! TLS */\n  pthread_setspecific(thread_tx, tx);\n#endif /* ! TLS */\n  stm_rollover_enter(tx);\n\n  /* Callbacks */\n  if (nb_init_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_init_cb; cb++)\n      init_cb[cb].f(TXARGS init_cb[cb].arg);\n  }\n\n  PRINT_DEBUG(\"==> %p\\n\", tx);\n\n  TX_RETURN;\n}\n\n/*\n * Called by the CURRENT thread to cleanup thread-local STM data.\n */\nvoid stm_exit_thread(TXPARAM)\n{\n  stm_word_t t;\n  TX_GET;\n\n  PRINT_DEBUG(\"==> stm_exit_thread(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Callbacks */\n  if (nb_exit_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_exit_cb; cb++)\n      exit_cb[cb].f(TXARGS exit_cb[cb].arg);\n  }\n\n  stm_rollover_exit(tx);\n\n  t = GET_CLOCK;\n  gc_free(tx->r_set.entries, t);\n  gc_free(tx->w_set.entries, t);\n  gc_free(tx, t);\n  gc_exit_thread();\n}\n\n/*\n * Called by the CURRENT thread to start an elastic transaction.\n */\nstatic inline void stm_elastic_start(TXPARAMS sigjmp_buf *env, stm_tx_attr_t *attr)\n{\n  TX_GET;\n  tx->type = EL;\n  \n  memset(tx->lastraddr, 0, ELASTICITY * sizeof(void *));\n  tx->marker = 0;\n  \t\n  PRINT_DEBUG(\"==> stm_elastic_start(%p)\\n\", tx);\n\t\n  /* Increment nesting level */\n  if (tx->nesting++ > 0)\n    return;\n\t\n  /* Use setjmp/longjmp? */\n  tx->jmp = env;\n  /* Attributes */\n  tx->attr = attr;\n  tx->ro = (attr == NULL ? 0 : attr->ro);\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_ACTIVE;\n start:\n  /* Start timestamp */\n  tx->start = tx->end = GET_CLOCK; /* OPT: Could be delayed until first read/write */\n  /* Disallow extensions in elastic transactions */\n  tx->can_extend = 0;\n  if (tx->start >= VERSION_MAX) {\n    /* Overflow: we must reset clock */\n    stm_overflow(tx);\n    goto start;\n  }\n  /* Read/write set */\n  if (tx->w_set.reallocate) {\n    /* Don't need to copy the content from the previous write set */\n    gc_free(tx->w_set.entries, tx->start);\n    stm_allocate_ws_entries(tx, 0);\n    tx->w_set.reallocate = 0;\n  }\n  tx->w_set.nb_entries = 0;\n  tx->r_set.nb_entries = 0;\n\t\n  gc_set_epoch(tx->start);\n\t\n  /* Callbacks */\n  if (nb_start_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_start_cb; cb++)\n      start_cb[cb].f(TXARGS start_cb[cb].arg);\n  }\n}\n\n/*\n * Called by the CURRENT thread to start a transaction.\n */\nstatic inline void stm_normal_start(TXPARAMS sigjmp_buf *env, stm_tx_attr_t *attr)\n{\n  TX_GET;\n  tx->type = NL;\n\n  PRINT_DEBUG(\"==> stm_normal_start(%p)\\n\", tx);\n\n  /* Increment nesting level */\n  if (tx->nesting++ > 0)\n    return;\n\n  /* Use setjmp/longjmp? */\n  tx->jmp = env;\n  /* Attributes */\n  tx->attr = attr;\n  tx->ro = (attr == NULL ? 0 : attr->ro);\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_ACTIVE;\n start:\n  /* Start timestamp */\n  tx->start = tx->end = GET_CLOCK; /* OPT: Could be delayed until first read/write */\n  /* Allow extensions */\n  tx->can_extend = 1;\n  if (tx->start >= VERSION_MAX) {\n    /* Overflow: we must reset clock */\n    stm_overflow(tx);\n    goto start;\n  }\n  /* Read/write set */\n  if (tx->w_set.reallocate) {\n    /* Don't need to copy the content from the previous write set */\n    gc_free(tx->w_set.entries, tx->start);\n    stm_allocate_ws_entries(tx, 0);\n    tx->w_set.reallocate = 0;\n  }\n  tx->w_set.nb_entries = 0;\n  tx->r_set.nb_entries = 0;\n\n  gc_set_epoch(tx->start);\n\n  /* Callbacks */\n  if (nb_start_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_start_cb; cb++)\n      start_cb[cb].f(TXARGS start_cb[cb].arg);\n  }\n}\n\nvoid stm_start(TXPARAMS sigjmp_buf *env, stm_tx_attr_t *attr, int type) {\n  if (type == NL) stm_normal_start(env, attr);\n  else stm_elastic_start(env, attr);\n}\n\n/*\n * Called by the CURRENT thread to commit an elastic transaction.\n */\nstatic inline int stm_elastic_commit(TXPARAM)\n{\n  TX_GET;\n\t\n  PRINT_DEBUG(\"==> stm_elastic_commit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\t\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Decrement nesting level */\n  if (--tx->nesting > 0)\n    return 1;\n\t\n  tx->retries = 0;\n\t\t\n  /* Callbacks */\n  if (nb_commit_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_commit_cb; cb++)\n      commit_cb[cb].f(TXARGS commit_cb[cb].arg);\n  }\n\t\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_COMMITTED;\n\t\n  return 1;\n}\n\n/*\n * Called by the CURRENT thread to commit a transaction.\n */\nstatic inline int stm_normal_commit(TXPARAM)\n{\n  w_entry_t *w;\n  stm_word_t t;\n  int i;\n  TX_GET;\n\n  PRINT_DEBUG(\"==> stm_normal_commit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Decrement nesting level */\n  if (--tx->nesting > 0)\n    return 1;\n\n  if (tx->w_set.nb_entries > 0) {\n    /* Update transaction */\n\n\n    /* Get commit timestamp */\n    t = FETCH_INC_CLOCK + 1;\n    if (t >= VERSION_MAX) {\n      /* Abort: will reset the clock on next transaction start or delete */\n      tx->aborts_rollover++;\n      stm_rollback(tx);\n      return 0;\n    }\n\n    /* Try to validate (only if a concurrent transaction has committed since tx->start) */\n    if (tx->start != t - 1 && !stm_validate(tx)) {\n      /* Cannot commit */\n      tx->aborts_validate_commit++;\n      stm_rollback(tx);\n      return 0;\n    }\n\n    /* Install new versions, drop locks and set new timestamp */\n    w = tx->w_set.entries;\n    for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n      if (w->mask != 0)\n        ATOMIC_STORE(w->addr, w->value);\n      /* Only drop lock for last covered address in write set */\n      if (w->next == NULL)\n        ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(t));\n\n      PRINT_DEBUG2(\"==> write(t=%p[%lu-%lu],a=%p,d=%p-%d,v=%d)\\n\",\n                   tx, (unsigned long)tx->start, (unsigned long)tx->end, w->addr, (void *)w->value, (int)w->value, (int)w->version);\n    }\n  }\n\n  tx->retries = 0;\n\n\n\n  /* Callbacks */\n  if (nb_commit_cb != 0) {\n    int cb;\n    for (cb = 0; cb < nb_commit_cb; cb++)\n      commit_cb[cb].f(TXARGS commit_cb[cb].arg);\n  }\n\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_COMMITTED;\n\n  return 1;\n}\n\nint stm_commit(TXPARAM) {\n  TX_GET;\n  if (tx->type == NL) return stm_normal_commit();\n  else return stm_elastic_commit();\n}\n\n/*\n * Called by the CURRENT thread to abort a transaction.\n */\nvoid stm_abort(TXPARAM)\n{\n  TX_GET;\n  stm_rollback(tx);\n}\n\n/* \n * Read version value and same version to make sure the value corresponds to the version.\n */\nstatic inline stm_word_t stm_vervalver(volatile stm_word_t *addr, stm_word_t *timestamp)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, value;\n  w_entry_t *w;\n\t\n  TX_GET;\n\t\t\n  PRINT_DEBUG2(\"==> stm_vervalver(a=%p)\\n\", addr);\n\t\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\t\n  /* Read lock, value, lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_OWNED(l)) {\n\t\t\n    if ((stm_tx_t *)LOCK_GET_ADDR(l) == tx) {\n      /* If the current tx owns the lock */\n      w = (w_entry_t *)LOCK_GET_ADDR(l);\n      /* Simply check if address falls inside our write set (avoids non-faulting load) */\n      if (tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries) {\n\t/* Yes: did we previously write the same address? */\n\twhile (1) {\n\t  if (addr == w->addr) {\n\t    /* Yes: get value from write set (or from memory if mask was empty) */\n\t    value = (w->mask == 0 ? ATOMIC_LOAD(addr) : w->value);\n\t    break;\n\t  }\n\t  if (w->next == NULL) {\n\t    /* No: get value from memory */\n\t    value = ATOMIC_LOAD(addr);\n\t    break;\n\t  }\n\t  w = w->next;\n\t}\n\t/* No need to add to read set (will remain valid) */\n\tPRINT_DEBUG2(\"==> stm_normal_load(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu)\\n\",\n\t\t     tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, lock, (unsigned long)l, (void *)value, (unsigned long)value);\n\treturn value;\n      }\n    }\n\t\t\n    /* Locked: wait until lock is free */\n    goto restart;\n  }\n  /* Not locked */\n  value = ATOMIC_LOAD_ACQ(addr);\n  l2 = ATOMIC_LOAD_ACQ(lock);\n  if (l != l2) {\n    l = l2;\n    goto restart_no_load;\n  }\n\t\n  *timestamp = LOCK_GET_TIMESTAMP(l);\n\t\n  PRINT_DEBUG2(\"==> stm_vervalver(a=%p,l=%p,*l=%lu,d=%p-%lu)\\n\",\n\t       addr, lock, (unsigned long)l, (void *)value, (unsigned long)value);\n\t\n  return value;\n}\n\n/*\n * Called by the CURRENT thread in an elastic transaction to \n * load a word-sized value.\n */\nstatic inline stm_word_t stm_elastic_load(TXPARAMS volatile stm_word_t *x)\n{\n  int i;\n  stm_word_t v_x;\n  stm_word_t *y;\n  stm_word_t ts_x = 0;\n  stm_word_t ts_y = 0;\n\n  TX_GET;\n\t\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\t\n  PRINT_DEBUG2(\"==> stm_elastic_load(t=%p[%lu-%lu],a=%p)\\n\", tx, \n\t       (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\t\n  v_x = stm_vervalver(x, &ts_x);\n  \n  if (ts_x > tx->start) {\n    /* Check consistency of the rotating buffer read addresses */ \n    for (i=0; i<ELASTICITY; i++) {\n      if ((y=tx->lastraddr[i])) {\n\tstm_vervalver(y, &ts_y);\n\tif (ts_y > tx->start) {\n\t  tx->aborts_ro++;\n\t  stm_rollback(tx);\n\t  return 0;\n\t}\n      }\n    }\n    tx->start = ts_x;\n  }\n\n  /* Fill the elastic rotating buffer with the address read */ \n  tx->lastraddr[tx->marker] = (stm_word_t *)x;\n  /* Increment the marker of the elastic rotating buffer */\n  tx->marker = ++tx->marker % ELASTICITY;\n  \n  return v_x;\n}\n\n/*\n * Called by the CURRENT thread in a normal transaction to \n * load a word-sized value.\n */\nstatic inline stm_word_t stm_normal_load(TXPARAMS volatile stm_word_t *addr)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, value, version;\n  r_entry_t *r;\n  w_entry_t *w;\n  TX_GET;\n\n  PRINT_DEBUG2(\"==> stm_normal_load(t=%p[%lu-%lu],a=%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\n  /* Check status */\n  assert(tx->status == TX_ACTIVE);\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Note: we could check for duplicate reads and get value from read set */\n\n  /* Read lock, value, lock */\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked */\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries) {\n      /* Yes: did we previously write the same address? */\n      while (1) {\n        if (addr == w->addr) {\n          /* Yes: get value from write set (or from memory if mask was empty) */\n          value = (w->mask == 0 ? ATOMIC_LOAD(addr) : w->value);\n          break;\n        }\n        if (w->next == NULL) {\n          /* No: get value from memory */\n          value = ATOMIC_LOAD(addr);\n          break;\n        }\n        w = w->next;\n      }\n      /* No need to add to read set (will remain valid) */\n      PRINT_DEBUG2(\"==> stm_normal_load(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu)\\n\",\n                   tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, lock, (unsigned long)l, (void *)value, (unsigned long)value);\n      return value;\n    }\n    /* Abort */\n    tx->aborts_locked_read++;\n    stm_rollback(tx);\n    return 0;\n  } else {\n    /* Not locked */\n    value = ATOMIC_LOAD_ACQ(addr);\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (l != l2) {\n      l = l2;\n      goto restart_no_load;\n    }\n    /* Check timestamp */\n    version = LOCK_GET_TIMESTAMP(l);\n    /* Valid version? */\n    if (version > tx->end) {\n      /* No: try to extend first (except for read-only transactions: no read set) */\n      if (tx->ro || !tx->can_extend || !stm_extend(tx)) {\n        /* Not much we can do: abort */\n        tx->aborts_validate_read++;\n        stm_rollback(tx);\n        return 0;\n      }\n      /* Verify that version has not been overwritten (read value has not\n       * yet been added to read set and may have not been checked during\n       * extend) */\n      l = ATOMIC_LOAD_ACQ(lock);\n      if (l != l2) {\n        l = l2;\n        goto restart_no_load;\n      }\n      /* Worked: we now have a good version (version <= tx->end) */\n    }\n  }\n  /* We have a good version: add to read set (update transactions) and return value */\n\n  if (!tx->ro) {\n    /* Add address and version to read set */\n    if (tx->r_set.nb_entries == tx->r_set.size)\n      stm_allocate_rs_entries(tx, 1);\n    r = &tx->r_set.entries[tx->r_set.nb_entries++];\n    r->version = version;\n    r->lock = lock;\n  }\n\n  PRINT_DEBUG2(\"==> stm_normal_load(t=%p[%lu-%lu],a=%p,l=%p,*l=%lu,d=%p-%lu,v=%lu)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, lock, (unsigned long)l, (void *)value, (unsigned long)value, (unsigned long)version);\n\n  return value;\n}\n\n/*\n * Called by the CURRENT thread in an elastic transaction to \n * load a word-sized value.\n */\nstm_word_t stm_load(TXPARAMS volatile stm_word_t *addr) {\n  TX_GET;\n  if (tx->type == NL) return stm_normal_load(addr);\n  else return stm_elastic_load(addr);\n}\n\n/*\n * Called by the CURRENT thread in an elastic transaction to store \n * a word-sized value.\n */\nstatic inline int stm_elastic_store(volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  int i;\n  stm_word_t ts_x;\n  volatile stm_word_t *lock;\n  stm_word_t l;\n  w_entry_t *w;  \n\t\n  TX_GET;\n\t\n  PRINT_DEBUG2(\"==> stm_elastic_store(t=%p[%lu-%lu],a=%p)\\n\", tx, \n\t       (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\t\n  tx->type = NL;\n  stm_write(tx, addr, value, mask);\n\n  /* Make sure last read values are unchanged */\n  for (i=0; i<ELASTICITY; i++) {\n    /* All addresses of the elastic rotating buffer must be consistent */\n    if (tx->lastraddr[i]) {\n      lock = GET_LOCK(tx->lastraddr[i]);\n      l = ATOMIC_LOAD_ACQ(lock);\n      if (LOCK_GET_OWNED(l)) {\n\t/* Is the buffer read address, the one we write? */\n\tw = (w_entry_t *)LOCK_GET_ADDR(l);                                                                                                                         \n\t/* Simply check if address falls inside our write set (avoids non-faulting load) */                                                                        \n\tif ((tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries))\n\t  return 1;  \n\t/* It is locked by another tx */\t\t\t\n\ttx->aborts_locked_write++;\n\tstm_rollback(tx);\n\treturn 0;\n      }\n      /* The read address of the rotating buffer has been seen unlocked */\n      ts_x = (stm_word_t)LOCK_GET_TIMESTAMP(l);\n      if (ts_x > tx->start) {\n\t/* The read address of the rotating buffer has changed */\n\ttx->aborts_validate_write++;\n\tstm_rollback(tx);\n\treturn 0;\n      }\n    }\n   \n    /* Do not recheck the elastic rotating buffer in further stores */\n    memset(tx->lastraddr, 0, ELASTICITY * sizeof(void *));\n  }\t\n  return 1;\n}\n\n/*\n * CURRENT thread in a normal transaction to store \n * a word-sized value.\n */\nstatic inline void stm_normal_store(volatile stm_word_t *addr, stm_word_t value)\n{\t\n  TX_GET;\n  stm_write(tx, addr, value, ~(stm_word_t)0);\n}\n\n/*\n * Called by the CURRENT thread in a transaction to store a \n * word-sized value.\n */\nvoid stm_store(TXPARAMS volatile stm_word_t *addr, stm_word_t value)\n{\n  TX_GET;\n  if (tx->type == EL) stm_elastic_store(addr, value, ~(stm_word_t)0);\n  else stm_write(tx, addr, value, ~(stm_word_t)0);\n}\n\n/*\n * Called by the CURRENT thread in a normal transaction to store part\n * a word-sized value.\n */\nvoid stm_store2(TXPARAMS volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  TX_GET;\n  if (tx->type == EL) stm_elastic_store(addr, value, mask);\n  else stm_write(tx, addr, value, mask);\n}\n\n/*\n * Called by the CURRENT thread to inquire about the status of a transaction.\n */\nint stm_active(TXPARAM)\n{\n  TX_GET;\n\n  return (tx->status == TX_ACTIVE);\n}\n\n/*\n * Called by the CURRENT thread to inquire about the status of a transaction.\n */\nint stm_aborted(TXPARAM)\n{\n  TX_GET;\n\n  return (tx->status == TX_ABORTED);\n}\n\n/*\n * Called by the CURRENT thread to obtain an environment for setjmp/longjmp.\n */\nsigjmp_buf *stm_get_env(TXPARAM)\n{\n  TX_GET;\n\n  /* Only return environment for top-level transaction */\n  return tx->nesting == 0 ? &tx->env : NULL;\n}\n\n/*\n * Get transaction attributes.\n */\nstm_tx_attr_t *stm_get_attributes(TXPARAM)\n{\n  TX_GET;\n\n  return tx->attr;\n}\n\n/*\n * Return statistics about a thread/transaction.\n */\nint stm_get_stats(TXPARAMS const char *name, void *val)\n{\n  TX_GET;\n\n  if (strcmp(\"read_set_size\", name) == 0) {\n    *(unsigned int *)val = tx->r_set.size;\n    return 1;\n  }\n  if (strcmp(\"write_set_size\", name) == 0) {\n    *(unsigned int *)val = tx->w_set.size;\n    return 1;\n  }\n  if (strcmp(\"read_set_nb_entries\", name) == 0) {\n    *(unsigned int *)val = tx->r_set.nb_entries;\n    return 1;\n  }\n  if (strcmp(\"write_set_nb_entries\", name) == 0) {\n    *(unsigned int *)val = tx->w_set.nb_entries;\n    return 1;\n  }\n  if (strcmp(\"read_only\", name) == 0) {\n    *(unsigned int *)val = tx->ro;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts\", name) == 0) {\n    *(unsigned long *)val = tx->aborts;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_ro\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_ro;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_locked_read\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_locked_read;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_locked_write\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_locked_write;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_validate_read\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_validate_read;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_validate_write\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_validate_write;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_validate_commit\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_validate_commit;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_invalid_memory\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_invalid_memory;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_double_write\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_double_write;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_reallocate\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_reallocate;\n    return 1;\n  } \n  if (strcmp(\"nb_aborts_rollover\", name) == 0) {\n    *(unsigned long *)val = tx->aborts_rollover;\n    return 1;\n  }\n  if (strcmp(\"max_retries\", name) == 0) {\n    *(unsigned long *)val = tx->max_retries;\n    return 1;\n  }\n  return 0;\n}\n\n/*\n * Return STM parameters.\n */\nint stm_get_parameter(const char *name, void *val)\n{\n  if (strcmp(\"contention_manager\", name) == 0) {\n    *(const char **)val = 0;\n    return 1;\n  }\n  if (strcmp(\"design\", name) == 0) {\n    *(const char **)val = 0;\n    return 1;\n  }\n  if (strcmp(\"initial_rw_set_size\", name) == 0) {\n    *(int *)val = RW_SET_SIZE;\n    return 1;\n  }\n#ifdef COMPILE_FLAGS\n  if (strcmp(\"compile_flags\", name) == 0) {\n    *(const char **)val = XSTR(COMPILE_FLAGS);\n    return 1;\n  }\n#endif /* COMPILE_FLAGS */\n  return 0;\n}\n\n/*\n * Set STM parameters.\n */\nint stm_set_parameter(const char *name, void *val)\n{\n  return 0;\n}\n\n/*\n * Create transaction-specific data (return -1 on error).\n */\nint stm_create_specific()\n{\n  if (nb_specific >= MAX_SPECIFIC) {\n    fprintf(stderr, \"Error: maximum number of specific slots reached\\n\");\n    return -1;\n  }\n  return nb_specific++;\n}\n\n/*\n * Store transaction-specific data.\n */\nvoid stm_set_specific(TXPARAMS int key, void *data)\n{\n  TX_GET;\n\n  assert (key >= 0 && key < nb_specific);\n  tx->data[key] = data;\n}\n\n/*\n * Fetch transaction-specific data.\n */\nvoid *stm_get_specific(TXPARAMS int key)\n{\n  TX_GET;\n\n  assert (key >= 0 && key < nb_specific);\n  return tx->data[key];\n}\n\n/*\n * Register callbacks for an external module (must be called before creating transactions).\n */\nint stm_register(void (*on_thread_init)(TXPARAMS void *arg),\n                 void (*on_thread_exit)(TXPARAMS void *arg),\n                 void (*on_start)(TXPARAMS void *arg),\n                 void (*on_commit)(TXPARAMS void *arg),\n                 void (*on_abort)(TXPARAMS void *arg),\n                 void *arg)\n{\n  if ((on_thread_init != NULL && nb_init_cb >= MAX_CB) ||\n      (on_thread_exit != NULL && nb_exit_cb >= MAX_CB) ||\n      (on_start != NULL && nb_start_cb >= MAX_CB) ||\n      (on_commit != NULL && nb_commit_cb >= MAX_CB) ||\n      (on_abort != NULL && nb_abort_cb >= MAX_CB)) {\n    fprintf(stderr, \"Error: maximum number of modules reached\\n\");\n    return 0;\n  }\n  /* New callback */\n  if (on_thread_init != NULL) {\n    init_cb[nb_init_cb].f = on_thread_init;\n    init_cb[nb_init_cb++].arg = arg;\n  }\n  /* Delete callback */\n  if (on_thread_exit != NULL) {\n    exit_cb[nb_exit_cb].f = on_thread_exit;\n    exit_cb[nb_exit_cb++].arg = arg;\n  }\n  /* Start callback */\n  if (on_start != NULL) {\n    start_cb[nb_start_cb].f = on_start;\n    start_cb[nb_start_cb++].arg = arg;\n  }\n  /* Commit callback */\n  if (on_commit != NULL) {\n    commit_cb[nb_commit_cb].f = on_commit;\n    commit_cb[nb_commit_cb++].arg = arg;\n  }\n  /* Abort callback */\n  if (on_abort != NULL) {\n    abort_cb[nb_abort_cb].f = on_abort;\n    abort_cb[nb_abort_cb++].arg = arg;\n  }\n\n  return 1;\n}\n\n/*\n * Get curent value of global clock.\n */\nstm_word_t stm_get_clock()\n{\n  return GET_CLOCK;\n}\n\n/*\n * Get current transaction descriptor.\n */\nstm_tx_t *stm_current_tx()\n{\n  return stm_get_tx();\n}\n"
  },
  {
    "path": "stms/estm-0.3.0/src/wrappers.c",
    "content": "/*\n * File:\n *   wrappers.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n * Description:\n *   STM wrapper functions for different data types.\n *\n * Copyright (c) 2007-2009.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n\n#include <assert.h>\n\n#include \"wrappers.h\"\n\n#define COMPILE_TIME_ASSERT(pred)       switch (0) { case 0: case pred: ; }\n\ntypedef union convert_64 {\n  uint64_t u64;\n  uint32_t u32[2];\n  uint16_t u16[4];\n  uint8_t u8[8];\n  int64_t s64;\n  double d;\n} convert_64_t;\n\ntypedef union convert_32 {\n  uint32_t u32;\n  uint16_t u16[2];\n  uint8_t u8[4];\n  int32_t s32;\n  float f;\n} convert_32_t;\n\ntypedef union convert_16 {\n  uint16_t u16;\n  int16_t s16;\n} convert_16_t;\n\ntypedef union convert_8 {\n  uint8_t u8;\n  int8_t s8;\n} convert_8_t;\n\ntypedef union convert {\n  stm_word_t w;\n  uint8_t b[sizeof(stm_word_t)];\n} convert_t;\n\n/* ################################################################### *\n * LOADS\n * ################################################################### */\n\nuint8_t stm_load8(TXPARAMS volatile uint8_t *addr)\n{\n  if (sizeof(stm_word_t) == 4) {\n    convert_32_t val;\n    val.u32 = (uint32_t)stm_load(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03));\n    return val.u8[(uintptr_t)addr & 0x03];\n  } else {\n    convert_64_t val;\n    val.u64 = (uint64_t)stm_load(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07));\n    return val.u8[(uintptr_t)addr & 0x07];\n  }\n}\n\nuint16_t stm_load16(TXPARAMS volatile uint16_t *addr)\n{\n  if (((uintptr_t)addr & 0x01) != 0) {\n    uint16_t val;\n    stm_load_bytes(TXARGS (volatile uint8_t *)addr, (uint8_t *)&val, sizeof(uint16_t));\n    return val;\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_32_t val;\n    val.u32 = (uint32_t)stm_load(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03));\n    return val.u16[((uintptr_t)addr & 0x03) >> 1];\n  } else {\n    convert_64_t val;\n    val.u64 = (uint64_t)stm_load(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07));\n    return val.u16[((uintptr_t)addr & 0x07) >> 1];\n  }\n}\n\nuint32_t stm_load32(TXPARAMS volatile uint32_t *addr)\n{\n  if (((uintptr_t)addr & 0x03) != 0) {\n    uint32_t val;\n    stm_load_bytes(TXARGS (volatile uint8_t *)addr, (uint8_t *)&val, sizeof(uint32_t));\n    return val;\n  } else if (sizeof(stm_word_t) == 4) {\n    return (uint32_t)stm_load(TXARGS (volatile stm_word_t *)addr);\n  } else {\n    convert_64_t val;\n    val.u64 = (uint64_t)stm_load(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07));\n    return val.u32[((uintptr_t)addr & 0x07) >> 2];\n  }\n}\n\nuint64_t stm_load64(TXPARAMS volatile uint64_t *addr)\n{\n  if (((uintptr_t)addr & 0x07) != 0) {\n    uint64_t val;\n    stm_load_bytes(TXARGS (volatile uint8_t *)addr, (uint8_t *)&val, sizeof(uint64_t));\n    return val;\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_64_t val;\n    val.u32[0] = (uint32_t)stm_load(TXARGS (volatile stm_word_t *)addr);\n    val.u32[1] = (uint32_t)stm_load(TXARGS (volatile stm_word_t *)addr + 1);\n    return val.u64;\n  } else {\n    return (uint64_t)stm_load(TXARGS (volatile stm_word_t *)addr);\n  }\n}\n\nchar stm_load_char(TXPARAMS volatile char *addr)\n{\n  convert_8_t val;\n  val.u8 = stm_load8(TXARGS (volatile uint8_t *)addr);\n  return val.s8;\n}\n\nunsigned char stm_load_uchar(TXPARAMS volatile unsigned char *addr)\n{\n  return (unsigned char)stm_load8(TXARGS (volatile uint8_t *)addr);\n}\n\nshort stm_load_short(TXPARAMS volatile short *addr)\n{\n  convert_16_t val;\n  val.u16 = stm_load16(TXARGS (volatile uint16_t *)addr);\n  return val.s16;\n}\n\nunsigned short stm_load_ushort(TXPARAMS volatile unsigned short *addr)\n{\n  return (unsigned short)stm_load16(TXARGS (volatile uint16_t *)addr);\n}\n\nint stm_load_int(TXPARAMS volatile int *addr)\n{\n  convert_32_t val;\n  val.u32 = stm_load32(TXARGS (volatile uint32_t *)addr);\n  return val.s32;\n}\n\nunsigned int stm_load_uint(TXPARAMS volatile unsigned int *addr)\n{\n  return (unsigned int)stm_load32(TXARGS (volatile uint32_t *)addr);\n}\n\nlong stm_load_long(TXPARAMS volatile long *addr)\n{\n  if (sizeof(long) == 4) {\n    convert_32_t val;\n    val.u32 = stm_load32(TXARGS (volatile uint32_t *)addr);\n    return val.s32;\n  } else {\n    convert_64_t val;\n    val.u64 = stm_load64(TXARGS (volatile uint64_t *)addr);\n    return val.s64;\n  }\n}\n\nunsigned long stm_load_ulong(TXPARAMS volatile unsigned long *addr)\n{\n  if (sizeof(long) == 4) {\n    return (unsigned long)stm_load32(TXARGS (volatile uint32_t *)addr);\n  } else {\n    return (unsigned long)stm_load64(TXARGS (volatile uint64_t *)addr);\n  }\n}\n\nfloat stm_load_float(TXPARAMS volatile float *addr)\n{\n  convert_32_t val;\n  val.u32 = stm_load32(TXARGS (volatile uint32_t *)addr);\n  return val.f;\n}\n\ndouble stm_load_double(TXPARAMS volatile double *addr)\n{\n  convert_64_t val;\n  val.u64 = stm_load64(TXARGS (volatile uint64_t *)addr);\n  return val.d;\n}\n\nvoid *stm_load_ptr(TXPARAMS volatile void **addr)\n{\n  union { stm_word_t w; void *v; } convert;\n  convert.w = stm_load(TXARGS (stm_word_t *)addr);\n  return convert.v;\n}\n\nvoid stm_load_bytes(TXPARAMS volatile uint8_t *addr, uint8_t *buf, size_t size)\n{\n  convert_t val;\n  unsigned int i;\n  stm_word_t *a;\n\n  if (size == 0)\n    return;\n  i = (uintptr_t)addr & (sizeof(stm_word_t) - 1);\n  if (i != 0) {\n    /* First bytes */\n    a = (stm_word_t *)((uintptr_t)addr & ~(uintptr_t)(sizeof(stm_word_t) - 1));\n    val.w = stm_load(TXARGS a++);\n    for (; i < sizeof(stm_word_t) && size > 0; i++, size--)\n      *buf++ = val.b[i];\n  } else\n    a = (stm_word_t *)addr;\n  /* Full words */\n  while (size >= sizeof(stm_word_t)) {\n#ifdef ALLOW_MISALIGNED_ACCESSES\n    *((stm_word_t *)buf) = stm_load(TXARGS a++);\n    buf += sizeof(stm_word_t);\n#else /* ! ALLOW_MISALIGNED_ACCESSES */\n    val.w = stm_load(TXARGS a++);\n    for (i = 0; i < sizeof(stm_word_t); i++)\n      *buf++ = val.b[i];\n#endif /* ! ALLOW_MISALIGNED_ACCESSES */\n    size -= sizeof(stm_word_t);\n  }\n  if (size > 0) {\n    /* Last bytes */\n    val.w = stm_load(TXARGS a);\n    i = 0;\n    for (i = 0; size > 0; i++, size--)\n      *buf++ = val.b[i];\n  }\n}\n\n/* ################################################################### *\n * STORES\n * ################################################################### */\n\nvoid stm_store8(TXPARAMS volatile uint8_t *addr, uint8_t value)\n{\n  if (sizeof(stm_word_t) == 4) {\n    convert_32_t val, mask;\n    val.u8[(uintptr_t)addr & 0x03] = value;\n    mask.u32 = 0;\n    mask.u8[(uintptr_t)addr & 0x03] = ~(uint8_t)0;\n    stm_store2(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03), (stm_word_t)val.u32, (stm_word_t)mask.u32);\n  } else {\n    convert_64_t val, mask;\n    val.u8[(uintptr_t)addr & 0x07] = value;\n    mask.u64 = 0;\n    mask.u8[(uintptr_t)addr & 0x07] = ~(uint8_t)0;\n    stm_store2(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07), (stm_word_t)val.u64, (stm_word_t)mask.u64);\n  }\n}\n\nvoid stm_store16(TXPARAMS volatile uint16_t *addr, uint16_t value)\n{\n  if (((uintptr_t)addr & 0x01) != 0) {\n    stm_store_bytes(TXARGS (volatile uint8_t *)addr, (uint8_t *)&value, sizeof(uint16_t));\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_32_t val, mask;\n    val.u16[((uintptr_t)addr & 0x03) >> 1] = value;\n    mask.u32 = 0;\n    mask.u16[((uintptr_t)addr & 0x03) >> 1] = ~(uint16_t)0;\n    stm_store2(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03), (stm_word_t)val.u32, (stm_word_t)mask.u32);\n  } else {\n    convert_64_t val, mask;\n    val.u16[((uintptr_t)addr & 0x07) >> 1] = value;\n    mask.u64 = 0;\n    mask.u16[((uintptr_t)addr & 0x07) >> 1] = ~(uint16_t)0;\n    stm_store2(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07), (stm_word_t)val.u64, (stm_word_t)mask.u64);\n  }\n}\n\nvoid stm_store32(TXPARAMS volatile uint32_t *addr, uint32_t value)\n{\n  if (((uintptr_t)addr & 0x03) != 0) {\n    stm_store_bytes(TXARGS (volatile uint8_t *)addr, (uint8_t *)&value, sizeof(uint32_t));\n  } else if (sizeof(stm_word_t) == 4) {\n    stm_store(TXARGS (volatile stm_word_t *)addr, (stm_word_t)value);\n  } else {\n    convert_64_t val, mask;\n    val.u32[((uintptr_t)addr & 0x07) >> 2] = value;\n    mask.u64 = 0;\n    mask.u32[((uintptr_t)addr & 0x07) >> 2] = ~(uint32_t)0;\n    stm_store2(TXARGS (volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07), (stm_word_t)val.u64, (stm_word_t)mask.u64);\n  }\n}\n\nvoid stm_store64(TXPARAMS volatile uint64_t *addr, uint64_t value)\n{\n  if (((uintptr_t)addr & 0x07) != 0) {\n    stm_store_bytes(TXARGS (volatile uint8_t *)addr, (uint8_t *)&value, sizeof(uint64_t));\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_64_t val;\n    val.u64 = value;\n    stm_store(TXARGS (volatile stm_word_t *)addr, (stm_word_t)val.u32[0]);\n    stm_store(TXARGS (volatile stm_word_t *)addr + 1, (stm_word_t)val.u32[1]);\n  } else {\n    return stm_store(TXARGS (volatile stm_word_t *)addr, (stm_word_t)value);\n  }\n}\n\nvoid stm_store_char(TXPARAMS volatile char *addr, char value)\n{\n  convert_8_t val;\n  val.s8 = value;\n  stm_store8(TXARGS (volatile uint8_t *)addr, val.u8);\n}\n\nvoid stm_store_uchar(TXPARAMS volatile unsigned char *addr, unsigned char value)\n{\n  stm_store8(TXARGS (volatile uint8_t *)addr, (uint8_t)value);\n}\n\nvoid stm_store_short(TXPARAMS volatile short *addr, short value)\n{\n  convert_16_t val;\n  val.s16 = value;\n  stm_store16(TXARGS (volatile uint16_t *)addr, val.u16);\n}\n\nvoid stm_store_ushort(TXPARAMS volatile unsigned short *addr, unsigned short value)\n{\n  stm_store16(TXARGS (volatile uint16_t *)addr, (uint16_t)value);\n}\n\nvoid stm_store_int(TXPARAMS volatile int *addr, int value)\n{\n  convert_32_t val;\n  val.s32 = value;\n  stm_store32(TXARGS (volatile uint32_t *)addr, val.u32);\n}\n\nvoid stm_store_uint(TXPARAMS volatile unsigned int *addr, unsigned int value)\n{\n  stm_store32(TXARGS (volatile uint32_t *)addr, (uint32_t)value);\n}\n\nvoid stm_store_long(TXPARAMS volatile long *addr, long value)\n{\n  if (sizeof(long) == 4) {\n    convert_32_t val;\n    val.s32 = value;\n    stm_store32(TXARGS (volatile uint32_t *)addr, val.u32);\n  } else {\n    convert_64_t val;\n    val.s64 = value;\n    stm_store64(TXARGS (volatile uint64_t *)addr, val.u64);\n  }\n}\n\nvoid stm_store_ulong(TXPARAMS volatile unsigned long *addr, unsigned long value)\n{\n  if (sizeof(long) == 4) {\n    stm_store32(TXARGS (volatile uint32_t *)addr, (uint32_t)value);\n  } else {\n    stm_store64(TXARGS (volatile uint64_t *)addr, (uint64_t)value);\n  }\n}\n\nvoid stm_store_float(TXPARAMS volatile float *addr, float value)\n{\n  convert_32_t val;\n  val.f = value;\n  stm_store32(TXARGS (volatile uint32_t *)addr, val.u32);\n}\n\nvoid stm_store_double(TXPARAMS volatile double *addr, double value)\n{\n  convert_64_t val;\n  val.d = value;\n  stm_store64(TXARGS (volatile uint64_t *)addr, val.u64);\n}\n\nvoid stm_store_ptr(TXPARAMS volatile void **addr, void *value)\n{\n  union { stm_word_t w; void *v; } convert;\n  convert.v = value;\n  stm_store(TXARGS (stm_word_t *)addr, convert.w);\n}\n\nvoid stm_store_bytes(TXPARAMS volatile uint8_t *addr, uint8_t *buf, size_t size)\n{\n  convert_t val, mask;\n  unsigned int i;\n  stm_word_t *a;\n\n  if (size == 0)\n    return;\n  i = (uintptr_t)addr & (sizeof(stm_word_t) - 1);\n  if (i != 0) {\n    /* First bytes */\n    a = (stm_word_t *)((uintptr_t)addr & ~(uintptr_t)(sizeof(stm_word_t) - 1));\n    val.w = mask.w = 0;\n    for (; i < sizeof(stm_word_t) && size > 0; i++, size--) {\n      mask.b[i] = 0xFF;\n      val.b[i] = *buf++;\n    }\n    stm_store2(TXARGS a++, val.w, mask.w);\n  } else\n    a = (stm_word_t *)addr;\n  /* Full words */\n  while (size >= sizeof(stm_word_t)) {\n#ifdef ALLOW_MISALIGNED_ACCESSES\n    stm_store(TXARGS a++, *((stm_word_t *)buf));\n    buf += sizeof(stm_word_t);\n#else /* ! ALLOW_MISALIGNED_ACCESSES */\n    for (i = 0; i < sizeof(stm_word_t); i++)\n      val.b[i] = *buf++;\n    stm_store(TXARGS a++, val.w);\n#endif /* ! ALLOW_MISALIGNED_ACCESSES */\n    size -= sizeof(stm_word_t);\n  }\n  if (size > 0) {\n    /* Last bytes */\n    val.w = mask.w = 0;\n    for (i = 0; size > 0; i++, size--) {\n      mask.b[i] = 0xFF;\n      val.b[i] = *buf++;\n    }\n    stm_store2(TXARGS a, val.w, mask.w);\n  }\n}\n"
  },
  {
    "path": "stms/tinystm/ChangeLog",
    "content": "[unreleased]\n\n2014-12-01  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Remove hybrid implementation (ASF)\n\n[1.0.5 release]\n\n2013-01-14  Pascal Felber  <pascal.felber@unine.ch>\n\t* Fixed bugs in garbage collection.\n\t* Added module that for to commit in order (mod_order)\n\t* Added stm_get_specific_tx and stm_set_specific_tx for mod_order.\n\n[1.0.4 release]\n\n2012-10-23  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added MIT license (dual license).\n\n2012-03-27  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Split stm.c file for the different strategies (wb-etl/wb-ctl/wt).\n\n[1.0.3 release]\n\n2011-11-17  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Fixed stack saving and minor changes for DTMC (tanger).\n\n2011-10-20  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Fixed a bug in tanger_stm_realloc (reported by Luke Dalessandro).\n\n2011-02-15  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Fixed a bug in stm_rollback (reported by Rahul Gayatri).\n\n[1.0.2 release]\n\n2011-02-07  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Minor fixes.\n\t* Added stm_get_attribute_tx() for Event Processing.\n\t* Added transactional_safe new/delete operators for GCC-TM.\n\n2010-08-10  Patrick Marlier <patrick.marlier@unine.ch>\n\t* ABI uses WRITE_THROUGH by default.\n\t* Added irrevocability management for hybrid ASF mode.\n\t* Disable inlining for tanger load/store due to a LLVM bug.\n\t* Fixed a bug in gc.c (thanks to Walther Maldonado).\n\t* Fixed a bug in mod_log.c (thanks to Adam Cozzette).\n\n2010-07-08  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Fixed a bug in stm_commit with CTL (thanks to Srđan Stipić).\n\n2010-07-07  Pascal Felber  <pascal.felber@unine.ch>\n\t* Fixed a bug in stm_set_irrevoable when using abort handler.\n\n[1.0.1 release]\n\n2010-06-02  Patrick Marlier <patrick.marlier@unine.ch>\n\t* Added Hybrid TM using AMD ASF.\n\t* Added ABI compatability with Intel STM C Compiler, GCC with TM\n\tsupport and DTMC.\n\t* Removed outdated Tanger support (now DTMC in ABI).\n\n2010-04-29  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added mod_ab module (atomic block statistics).\n\n[1.0.0 release]\n\n2010-02-22  Pascal Felber  <pascal.felber@unine.ch>\n\t* Various fixes and cosmetic changes.\n\n2010-01-15  Pascal Felber  <pascal.felber@unine.ch>\n\t* Changed rollover code.\n\t* Added quiescence and serial-irrevocable mode.\n\n2009-12-18  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added commit/abort callbacks.\n\t* Various fixes.\n\n2009-12-15  Pascal Felber  <pascal.felber@unine.ch>\n\t* Updated irrevocability to work with modular contention manager.\n\n2009-11-29  Pascal Felber  <pascal.felber@unine.ch>\n\t* Updated modules to avoid name conflicts.\n\n2009-11-20  Pascal Felber  <pascal.felber@unine.ch>\n\t* Changed signature of stm_start().\n\t* Added irrevocability.\n\t* Added ABI for intel compiler and tm-gcc.\n\t* Fixed a bug in mod_log.\n\n2009-09-25  Pascal Felber  <pascal.felber@unine.ch>\n\t* Can disable alternation of insertion/removal in intset.\n\n2009-06-10  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added customizable (modular) contention manager.\n\n2009-03-08  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added some more statistics.\n\t* Added call to conflict callback upon validation.\n\n2009-02-06  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added version number.\n\t* Renamed mod_local module to mod_log and updated code.\n\n2009-02-06  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added abort reason as parameter of siglongjmp().\n\n[0.9.9 release]\n\n2009-01-29  Pascal Felber  <pascal.felber@unine.ch>\n\t* Updated TANGER wrappers.\n\t* Prepared new release.\n\n2009-01-17  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added content of README as doxygen documentation.\n\t* Added new version of TANGER wrappers (partial).\n\t* Added region load/store and support for misaligned accesses.\n\t* Bug fixes.\n\n2009-01-04  Pascal Felber  <pascal.felber@unine.ch>\n\t* Documented APIs (doxygen comments in include files).\n\t* Cleaned up some APIs, changed parameters of stm_start().\n\t* CTL now spins while address is locked.\n\n2008-12-06  Pascal Felber  <pascal.felber@unine.ch>\n\t* Cleaned up atomic operations and memory barriers.\n\n2008-11-26  Pascal Felber  <pascal.felber@unine.ch>\n\t* Documented compile-time options in Makefile\n\n2008-11-16  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added support to read previous version of locked data.\n\t* Added support in Makefile for unifdef.\n\n2008-07-22  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added epoch-based memory allocator.\n\t* Added conflict tracking and callback.\n\t* Added skip list and refactored intset benchmark\n\t* Added mod_local module.\n\t* Added functions to control extensions and read the clock.\n\t* Added support for unit transactions in intset.\n\t* Many other changes and fixes.\n\n[0.9.5 release]\n\n2008-07-07  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added support for the latest version of STAMP.\n\t* Removed TANGER wrappers (distributed separately).\n\t* Many modifications and fixes.\n\n2008-05-26  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added CTL.\n\n2008-05-20  Pascal Felber  <pascal.felber@unine.ch>\n\t* Major API changes (no more transaction parameters, etc.).\n\t* Added unit transactions.\n\t* Many other changes and fixes.\n\n[0.9.0 release]\n\n2008-04-25  Pascal Felber  <pascal.felber@unine.ch>\n\t* Removed parameter to stm_new() => transaction cannot be on stack.\n\n2008-03-27  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added new module for coarse-grain statistics.\n\t* Added new internal statistics.\n\t* Added new support for reading configuration parameters.\n\n2008-03-25  Pascal Felber  <pascal.felber@unine.ch>\n\t* Merged write-back and write-through in a single file.\n\n2008-03-16  Pascal Felber  <pascal.felber@unine.ch>\n\t* Refactored dynamic memory management as a module.\n\n2008-03-15  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added support for modules.\n\t* Added sample mod_print module.\n\n2008-02-13  Pascal Felber  <pascal.felber@unine.ch>\n\t* Improvements to PRIORITY contention manager.\n\n2008-01-21  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added BACKOFF contention manager.\n\n2008-01-03  Pascal Felber  <pascal.felber@unine.ch>\n\t* Added PRIORITY contention manager.\n\t* Added DELAY contention manager.\n\t* Added bank benchmark.\n\n2008-01-01  Pascal Felber  <pascal.felber@unine.ch>\n\t* Initial code base for the VELOX project.\n"
  },
  {
    "path": "stms/tinystm/Doxyfile",
    "content": "# Doxyfile 1.8.1.2\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a hash (#) is considered a comment and will be ignored.\n# The format is:\n#       TAG = value [value, ...]\n# For lists items can also be appended using:\n#       TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\" \").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all\n# text before the first occurrence of this tag. Doxygen uses libiconv (or the\n# iconv built into libc) for the transcoding. See\n# http://www.gnu.org/software/libiconv for the list of possible encodings.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or sequence of words) that should\n# identify the project. Note that if you do not use Doxywizard you need\n# to put quotes around the project name if it contains spaces.\n\nPROJECT_NAME           = TinySTM\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number.\n# This could be handy for archiving the generated documentation or\n# if some version control system is used.\n\nPROJECT_NUMBER         = 1.0.6\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer\n# a quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          =\n\n# With the PROJECT_LOGO tag one can specify an logo or icon that is\n# included in the documentation. The maximum height of the logo should not\n# exceed 55 pixels and the maximum width should not exceed 200 pixels.\n# Doxygen will copy the logo to the output directory.\n\nPROJECT_LOGO           =\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)\n# base path where the generated documentation will be put.\n# If a relative path is entered, it will be relative to the location\n# where doxygen was started. If left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = doc\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create\n# 4096 sub-directories (in 2 levels) under the output directory of each output\n# format and will distribute the generated files over these directories.\n# Enabling this option can be useful when feeding doxygen a huge amount of\n# source files, where putting all generated files in the same directory would\n# otherwise cause performance problems for the file system.\n\nCREATE_SUBDIRS         = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# The default language is English, other supported languages are:\n# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,\n# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,\n# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English\n# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,\n# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,\n# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will\n# include brief member descriptions after the members that are listed in\n# the file and class documentation (similar to JavaDoc).\n# Set to NO to disable this.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend\n# the brief description of a member or function before the detailed description.\n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator\n# that is used to form the text in various listings. Each string\n# in this list, if found as the leading text of the brief description, will be\n# stripped from the text and the result after processing the whole list, is\n# used as the annotated text. Otherwise, the brief description is used as-is.\n# If left blank, the following values are used (\"$name\" is automatically\n# replaced with the name of the entity): \"The $name class\" \"The $name widget\"\n# \"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\"\n# \"represents\" \"a\" \"an\" \"the\"\n\nABBREVIATE_BRIEF       =\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# Doxygen will generate a detailed section even if there is only a brief\n# description.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full\n# path before files name in the file list and in the header files. If set\n# to NO the shortest path that makes the file name unique will be used.\n\nFULL_PATH_NAMES        = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag\n# can be used to strip a user-defined part of the path. Stripping is\n# only done if one of the specified strings matches the left-hand part of\n# the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the\n# path to strip.\n\nSTRIP_FROM_PATH        =\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of\n# the path mentioned in the documentation of a class, which tells\n# the reader which header file to include in order to use a class.\n# If left blank only the name of the header file containing the class\n# definition is used. Otherwise one should specify the include paths that\n# are normally passed to the compiler using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter\n# (but less readable) file names. This can be useful if your file system\n# doesn't support long names like on DOS, Mac, or CD-ROM.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen\n# will interpret the first line (until the first dot) of a JavaDoc-style\n# comment as the brief description. If set to NO, the JavaDoc\n# comments will behave just like regular Qt-style comments\n# (thus requiring an explicit @brief command for a brief description.)\n\nJAVADOC_AUTOBRIEF      = YES\n\n# If the QT_AUTOBRIEF tag is set to YES then Doxygen will\n# interpret the first line (until the first dot) of a Qt-style\n# comment as the brief description. If set to NO, the comments\n# will behave just like regular Qt-style comments (thus requiring\n# an explicit \\brief command for a brief description.)\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen\n# treat a multi-line C++ special comment block (i.e. a block of //! or ///\n# comments) as a brief description. This used to be the default behaviour.\n# The new default is to treat a multi-line C++ comment block as a detailed\n# description. Set this tag to YES if you prefer the old behaviour instead.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented\n# member inherits the documentation from any documented member that it\n# re-implements.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce\n# a new page for each member. If set to NO, the documentation of a member will\n# be part of the file/class/namespace that contains it.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab.\n# Doxygen uses this value to replace tabs by spaces in code fragments.\n\nTAB_SIZE               = 8\n\n# This tag can be used to specify a number of aliases that acts\n# as commands in the documentation. An alias has the form \"name=value\".\n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to\n# put the command \\sideeffect (or @sideeffect) in the documentation, which\n# will result in a user-defined paragraph with heading \"Side Effects:\".\n# You can put \\n's in the value part of an alias to insert newlines.\n\nALIASES                =\n\n# This tag can be used to specify a number of word-keyword mappings (TCL only).\n# A mapping has the form \"name=value\". For example adding\n# \"class=itcl::class\" will allow you to use the command class in the\n# itcl::class meaning.\n\nTCL_SUBST              =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C\n# sources only. Doxygen will then generate output that is more tailored for C.\n# For instance, some of the names that are used will be different. The list\n# of all members will be omitted, etc.\n\nOPTIMIZE_OUTPUT_FOR_C  = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java\n# sources only. Doxygen will then generate output that is more tailored for\n# Java. For instance, namespaces will be presented as packages, qualified\n# scopes will look different, etc.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources only. Doxygen will then generate output that is more tailored for\n# Fortran.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for\n# VHDL.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given extension.\n# Doxygen has a built-in mapping, but you can override or extend it using this\n# tag. The format is ext=language, where ext is a file extension, and language\n# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,\n# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make\n# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C\n# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions\n# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.\n\nEXTENSION_MAPPING      =\n\n# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all\n# comments according to the Markdown format, which allows for more readable\n# documentation. See http://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you\n# can mix doxygen, HTML, and XML commands with Markdown formatting.\n# Disable only in case of backward compatibilities issues.\n\nMARKDOWN_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should\n# set this tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.\n# func(std::string) {}). This also makes the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.\n# Doxygen will parse them like normal C++ but will assume all classes use public\n# instead of private inheritance when no explicit protection keyword is present.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate getter\n# and setter methods for a property. Setting this option to YES (the default)\n# will make doxygen replace the get and set methods by a property in the\n# documentation. This will only work if the methods are indeed getting or\n# setting a simple type. If this is not the case, or you want to show the\n# methods anyway, you should set this option to NO.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES, then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of\n# the same type (for instance a group of public functions) to be put as a\n# subgroup of that type (e.g. under the Public Functions section). Set it to\n# NO to prevent subgrouping. Alternatively, this can be done per class using\n# the \\nosubgrouping command.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and\n# unions are shown inside the group in which they are included (e.g. using\n# @ingroup) instead of on a separate page (for HTML and Man pages) or\n# section (for LaTeX and RTF).\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and\n# unions with only public data fields will be shown inline in the documentation\n# of the scope in which they are defined (i.e. file, namespace, or group\n# documentation), provided this scope is documented. If set to NO (the default),\n# structs, classes, and unions are shown on a separate page (for HTML and Man\n# pages) or section (for LaTeX and RTF).\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum\n# is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically\n# be useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to\n# determine which symbols to keep in memory and which to flush to disk.\n# When the cache is full, less often used symbols will be written to disk.\n# For small to medium size projects (<1000 input files) the default value is\n# probably good enough. For larger projects a too small cache size can cause\n# doxygen to be busy swapping symbols to and from disk most of the time\n# causing a significant performance penalty.\n# If the system has enough physical memory increasing the cache will improve the\n# performance by keeping more symbols in memory. Note that the value works on\n# a logarithmic scale so increasing the size by one will roughly double the\n# memory usage. The cache size is given by this formula:\n# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,\n# corresponding to a cache size of 2^16 = 65536 symbols.\n\nSYMBOL_CACHE_SIZE      = 0\n\n# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be\n# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given\n# their name and scope. Since this can be an expensive process and often the\n# same symbol appear multiple times in the code, doxygen keeps a cache of\n# pre-resolved symbols. If the cache is too small doxygen will become slower.\n# If the cache is too large, memory is wasted. The cache size is given by this\n# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,\n# corresponding to a cache size of 2^16 = 65536 symbols.\n\nLOOKUP_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in\n# documentation are documented, even if no documentation was available.\n# Private class members and static file members will be hidden unless\n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class\n# will be included in the documentation.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file\n# will be included in the documentation.\n\nEXTRACT_STATIC         = NO\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)\n# defined locally in source files will be included in the documentation.\n# If set to NO only classes defined in header files are included.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. When set to YES local\n# methods, which are defined in the implementation section but not in\n# the interface are included in the documentation.\n# If set to NO (the default) only methods in the interface are included.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base\n# name of the file that contains the anonymous namespace. By default\n# anonymous namespaces are hidden.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all\n# undocumented members of documented classes, files or namespaces.\n# If set to NO (the default) these members will be included in the\n# various overviews, but no documentation section is generated.\n# This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy.\n# If set to NO (the default) these classes will be included in the various\n# overviews. This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all\n# friend (class|struct|union) declarations.\n# If set to NO (the default) these declarations will be included in the\n# documentation.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any\n# documentation blocks found inside the body of a function.\n# If set to NO (the default) these blocks will be appended to the\n# function's detailed documentation block.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation\n# that is typed after a \\internal command is included. If the tag is set\n# to NO (the default) then the documentation will be excluded.\n# Set it to YES to include the internal documentation.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate\n# file names in lower-case letters. If set to YES upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n\nCASE_SENSE_NAMES       = NO\n\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen\n# will show members with their full class and namespace scopes in the\n# documentation. If set to YES the scope will be hidden.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen\n# will put a list of the files that are included by a file in the documentation\n# of that file.\n\nSHOW_INCLUDE_FILES     = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen\n# will list include files with double quotes in the documentation\n# rather than with sharp brackets.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]\n# is inserted in the documentation for inline members.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen\n# will sort the (detailed) documentation of file and class members\n# alphabetically by member name. If set to NO the members will appear in\n# declaration order.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the\n# brief documentation of file, namespace and class members alphabetically\n# by member name. If set to NO (the default) the members will appear in\n# declaration order.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen\n# will sort the (brief and detailed) documentation of class members so that\n# constructors and destructors are listed first. If set to NO (the default)\n# the constructors will appear in the respective orders defined by\n# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.\n# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO\n# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the\n# hierarchy of group names into alphabetical order. If set to NO (the default)\n# the group names will appear in their defined order.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be\n# sorted by fully-qualified names, including namespaces. If set to\n# NO (the default), the class list will be sorted only by class name,\n# not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the\n# alphabetical list.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to\n# do proper type resolution of all parameters of a function it will reject a\n# match between the prototype and the implementation of a member function even\n# if there is only one candidate or it is obvious which candidate to choose\n# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen\n# will still accept a match between prototype and implementation in such cases.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or\n# disable (NO) the todo list. This list is created by putting \\todo\n# commands in the documentation.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or\n# disable (NO) the test list. This list is created by putting \\test\n# commands in the documentation.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or\n# disable (NO) the bug list. This list is created by putting \\bug\n# commands in the documentation.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or\n# disable (NO) the deprecated list. This list is created by putting\n# \\deprecated commands in the documentation.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional\n# documentation sections, marked by \\if sectionname ... \\endif.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines\n# the initial value of a variable or macro consists of for it to appear in\n# the documentation. If the initializer consists of more lines than specified\n# here it will be hidden. Use a value of 0 to hide initializers completely.\n# The appearance of the initializer of individual variables and macros in the\n# documentation can be controlled using \\showinitializer or \\hideinitializer\n# command in the documentation regardless of this setting.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated\n# at the bottom of the documentation of classes and structs. If set to YES the\n# list will mention the files that were used to generate the documentation.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page.\n# This will remove the Files entry from the Quick Index and from the\n# Folder Tree View (if specified). The default is YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the\n# Namespaces page.\n# This will remove the Namespaces entry from the Quick Index\n# and from the Folder Tree View (if specified). The default is YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command <command> <input-file>, where <command> is the value of\n# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file\n# provided by doxygen. Whatever the program writes to standard output\n# is used as the file version. See the manual for examples.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option.\n# You can optionally specify a file name after the option, if omitted\n# DoxygenLayout.xml will be used as the name of the layout file.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files\n# containing the references data. This must be a list of .bib files. The\n# .bib extension is automatically appended if omitted. Using this command\n# requires the bibtex tool to be installed. See also\n# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style\n# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this\n# feature you need bibtex and perl available in the search path.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated\n# by doxygen. Possible values are YES and NO. If left blank NO is used.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated by doxygen. Possible values are YES and NO. If left blank\n# NO is used.\n\nWARNINGS               = YES\n\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings\n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will\n# automatically be disabled.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some\n# parameters in a documented function, or documenting parameters that\n# don't exist or using markup commands wrongly.\n\nWARN_IF_DOC_ERROR      = YES\n\n# The WARN_NO_PARAMDOC option can be enabled to get warnings for\n# functions that are documented, but have no documentation for their parameters\n# or return value. If set to NO (the default) doxygen will only warn about\n# wrong or incomplete parameter documentation, but not about the absence of\n# documentation.\n\nWARN_NO_PARAMDOC       = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that\n# doxygen can produce. The string should contain the $file, $line, and $text\n# tags, which will be replaced by the file and line number from which the\n# warning originated and the warning text. Optionally the format may contain\n# $version, which will be replaced by the version of the file (if it could\n# be obtained via FILE_VERSION_FILTER)\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning\n# and error messages should be written. If left blank the output is written\n# to stderr.\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag can be used to specify the files and/or directories that contain\n# documented source files. You may enter file names like \"myfile.cpp\" or\n# directories like \"/usr/src/myproject\". Separate the files or directories\n# with spaces.\n\nINPUT                  = include/stm.h \\\n                         include/wrappers.h \\\n                         include/mod_ab.h \\\n                         include/mod_cb.h \\\n                         include/mod_log.h \\\n                         include/mod_mem.h \\\n                         include/mod_print.h \\\n                         include/mod_stats.h\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is\n# also the default input encoding. Doxygen uses libiconv (or the iconv built\n# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for\n# the list of possible encodings.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\n# and *.h) to filter out the source-files in the directories. If left\n# blank the following patterns are tested:\n# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh\n# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py\n# *.f90 *.f *.for *.vhd *.vhdl\n\nFILE_PATTERNS          =\n\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories\n# should be searched for input files as well. Possible values are YES and NO.\n# If left blank NO is used.\n\nRECURSIVE              = NO\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories. Note that the wildcards are matched\n# against the file with absolute path, so to exclude all test directories\n# for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n\nEXCLUDE_SYMBOLS        = TXTYPE \\\n                         TXPARAM \\\n                         TXPARAMS \\\n                         TXARG \\\n                         TXARGS\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or\n# directories that contain example code fragments that are included (see\n# the \\include command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\n# and *.h) to filter out the source-files in the directories. If left\n# blank all files are included.\n\nEXAMPLE_PATTERNS       =\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude\n# commands irrespective of the value of the RECURSIVE tag.\n# Possible values are YES and NO. If left blank NO is used.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or\n# directories that contain image that are included in the documentation (see\n# the \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command <filter> <input-file>, where <filter>\n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an\n# input file. Doxygen will then use the output that the filter program writes\n# to standard output.\n# If FILTER_PATTERNS is specified, this tag will be\n# ignored.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis.\n# Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match.\n# The filters are a list of the form:\n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further\n# info on how filters are used. If FILTER_PATTERNS is empty or if\n# non of the patterns match the file name, INPUT_FILTER is applied.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will be used to filter the input files when producing source\n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any)\n# and it is also possible to disable source filtering for a specific pattern\n# using *.ext= (so without naming a filter). This option only has effect when\n# FILTER_SOURCE_FILES is enabled.\n\nFILTER_SOURCE_PATTERNS =\n\n#---------------------------------------------------------------------------\n# configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will\n# be generated. Documented entities will be cross-referenced with these sources.\n# Note: To get rid of all source code in the generated output, make sure also\n# VERBATIM_HEADERS is set to NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body\n# of functions and classes directly in the documentation.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct\n# doxygen to hide any special comment blocks from generated source code\n# fragments. Normal C, C++ and Fortran comments will always remain visible.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES\n# then for each documented function all documented\n# functions referencing it will be listed.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES\n# then for each documented function all documented entities\n# called/used by that function will be listed.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\n# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\n# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\n# link to the source code.\n# Otherwise they will link to the documentation.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code\n# will point to the HTML generated by the htags(1) tool instead of doxygen\n# built-in source browser. The htags tool is part of GNU's global source\n# tagging system (see http://www.gnu.org/software/global/global.html). You\n# will need version 4.8.6 or higher.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen\n# will generate a verbatim copy of the header file for each class for\n# which an include is specified. Set to NO to disable this.\n\nVERBATIM_HEADERS       = YES\n\n#---------------------------------------------------------------------------\n# configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index\n# of all compounds will be generated. Enable this if the project\n# contains a lot of classes, structs, unions or interfaces.\n\nALPHABETICAL_INDEX     = NO\n\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then\n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns\n# in which this list will be split (can be a number in the range [1..20])\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all\n# classes will be put under the same header in the alphabetical index.\n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that\n# should be ignored while generating the index headers.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will\n# generate HTML output.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `html' will be used as the default path.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for\n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank\n# doxygen will generate files with .html extension.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a personal HTML header for\n# each generated HTML page. If it is left blank doxygen will generate a\n# standard header. Note that when using a custom header you are responsible\n#  for the proper inclusion of any scripts and style sheets that doxygen\n# needs, which is dependent on the configuration options used.\n# It is advised to generate a default header using \"doxygen -w html\n# header.html footer.html stylesheet.css YourConfigFile\" and then modify\n# that header. Note that the header is subject to change so you typically\n# have to redo this when upgrading to a newer version of doxygen or when\n# changing the value of configuration settings such as GENERATE_TREEVIEW!\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for\n# each generated HTML page. If it is left blank doxygen will generate a\n# standard footer.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading\n# style sheet that is used by each HTML page. It can be used to\n# fine-tune the look of the HTML output. If the tag is left blank doxygen\n# will generate a default style sheet. Note that doxygen will try to copy\n# the style sheet file to the HTML output directory, so don't put your own\n# style sheet in the HTML output directory as well, or it will be erased!\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that\n# the files will be copied as-is; there are no commands or markers available.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.\n# Doxygen will adjust the colors in the style sheet and background images\n# according to this color. Hue is specified as an angle on a colorwheel,\n# see http://en.wikipedia.org/wiki/Hue for more information.\n# For instance the value 0 represents red, 60 is yellow, 120 is green,\n# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.\n# The allowed range is 0 to 359.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of\n# the colors in the HTML output. For a value of 0 the output will use\n# grayscales only. A value of 255 will produce the most vivid colors.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to\n# the luminance component of the colors in the HTML output. Values below\n# 100 gradually make the output lighter, whereas values above 100 make\n# the output darker. The value divided by 100 is the actual gamma applied,\n# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,\n# and 100 does not change the gamma.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting\n# this to NO can help when comparing the output of multiple runs.\n\nHTML_TIMESTAMP         = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of\n# entries shown in the various tree structured indices initially; the user\n# can expand and collapse entries dynamically later on. Doxygen will expand\n# the tree to such a level that at most the specified number of entries are\n# visible (unless a fully collapsed tree already exceeds this amount).\n# So setting the number of entries 1 will produce a full collapsed tree by\n# default. 0 is a special value representing an infinite number of entries\n# and will result in a full expanded tree by default.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files\n# will be generated that can be used as input for Apple's Xcode 3\n# integrated development environment, introduced with OSX 10.5 (Leopard).\n# To create a documentation set, doxygen will generate a Makefile in the\n# HTML output directory. Running make will produce the docset in that\n# directory and running \"make install\" will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find\n# it at startup.\n# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n\nGENERATE_DOCSET        = NO\n\n# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the\n# feed. A documentation feed provides an umbrella under which multiple\n# documentation sets from a single provider (such as a company or product suite)\n# can be grouped.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that\n# should uniquely identify the documentation set bundle. This should be a\n# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen\n# will append .docset to the name.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files\n# will be generated that can be used as input for tools like the\n# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)\n# of the generated HTML documentation.\n\nGENERATE_HTMLHELP      = NO\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can\n# be used to specify the file name of the resulting .chm file. You\n# can add a path in front of the file if the result should not be\n# written to the html output directory.\n\nCHM_FILE               =\n\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can\n# be used to specify the location (absolute path including file name) of\n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run\n# the HTML help compiler on the generated index.hhp.\n\nHHC_LOCATION           =\n\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag\n# controls if a separate .chi index file is generated (YES) or that\n# it should be included in the master .chm file (NO).\n\nGENERATE_CHI           = NO\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING\n# is used to encode HtmlHelp index (hhk), content (hhc) and project file\n# content.\n\nCHM_INDEX_ENCODING     =\n\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag\n# controls whether a binary table of contents is generated (YES) or a\n# normal table of contents (NO) in the .chm file.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members\n# to the contents of the HTML help documentation and to the tree view.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated\n# that can be used as input for Qt's qhelpgenerator to generate a\n# Qt Compressed Help (.qch) of the generated HTML documentation.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can\n# be used to specify the file name of the resulting .qch file.\n# The path specified is relative to the HTML output folder.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating\n# Qt Help Project output. For more information please see\n# http://doc.trolltech.com/qthelpproject.html#namespace\n\nQHP_NAMESPACE          =\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating\n# Qt Help Project output. For more information please see\n# http://doc.trolltech.com/qthelpproject.html#virtual-folders\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to\n# add. For more information please see\n# http://doc.trolltech.com/qthelpproject.html#custom-filters\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see\n# <a href=\"http://doc.trolltech.com/qthelpproject.html#custom-filters\">\n# Qt Help Project / Custom Filters</a>.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's\n# filter section matches.\n# <a href=\"http://doc.trolltech.com/qthelpproject.html#filter-attributes\">\n# Qt Help Project / Filter Attributes</a>.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can\n# be used to specify the location of Qt's qhelpgenerator.\n# If non-empty doxygen will try to run qhelpgenerator on the generated\n# .qhp file.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files\n#  will be generated, which together with the HTML files, form an Eclipse help\n# plugin. To install this plugin and make it available under the help contents\n# menu in Eclipse, the contents of the directory containing the HTML and XML\n# files needs to be copied into the plugins directory of eclipse. The name of\n# the directory within the plugins directory should be the same as\n# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before\n# the help appears.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have\n# this name.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)\n# at top of each HTML page. The value NO (the default) enables the index and\n# the value YES disables it. Since the tabs have the same information as the\n# navigation tree you can set this option to NO if you already set\n# GENERATE_TREEVIEW to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information.\n# If the tag value is set to YES, a side panel will be generated\n# containing a tree-like index structure (just like the one that\n# is generated for HTML Help). For this to work a browser that supports\n# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).\n# Windows users are probably better off using the HTML help feature.\n# Since the tree basically has the same information as the tab index you\n# could consider to set DISABLE_INDEX to NO when enabling this option.\n\nGENERATE_TREEVIEW      = NONE\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values\n# (range [0,1..20]) that doxygen will group on one line in the generated HTML\n# documentation. Note that a value of 0 will completely suppress the enum\n# values from appearing in the overview section.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be\n# used to set the initial width (in pixels) of the frame in which the tree\n# is shown.\n\nTREEVIEW_WIDTH         = 250\n\n# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open\n# links to external symbols imported via tag files in a separate window.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of Latex formulas included\n# as images in the HTML documentation. The default is 10. Note that\n# when you change the font size after a successful doxygen run you need\n# to manually remove any form_*.png images from the HTML output directory\n# to force them to be regenerated.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are\n# not supported properly for IE 6.0, but are supported on all modern browsers.\n# Note that when changing this option you need to delete any form_*.png files\n# in the HTML output before the changes have effect.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax\n# (see http://www.mathjax.org) which uses client side Javascript for the\n# rendering instead of using prerendered bitmaps. Use this if you do not\n# have LaTeX installed or if you want to formulas look prettier in the HTML\n# output. When enabled you may also need to install MathJax separately and\n# configure the path to it using the MATHJAX_RELPATH option.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you need to specify the location relative to the\n# HTML output directory using the MATHJAX_RELPATH option. The destination\n# directory should contain the MathJax.js script. For instance, if the mathjax\n# directory is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to\n# the MathJax Content Delivery Network so you can quickly see the result without\n# installing MathJax.\n# However, it is strongly recommended to install a local\n# copy of MathJax from http://www.mathjax.org before deployment.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension\n# names that should be enabled during MathJax rendering.\n\nMATHJAX_EXTENSIONS     =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box\n# for the HTML output. The underlying search engine uses javascript\n# and DHTML and should work on any modern browser. Note that when using\n# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets\n# (GENERATE_DOCSET) there is already a search function so this one should\n# typically be disabled. For large projects the javascript based search engine\n# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.\n\nSEARCHENGINE           = NO\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a PHP enabled web server instead of at the web client\n# using Javascript. Doxygen will generate the search PHP script and index\n# file to put on the web server. The advantage of the server\n# based approach is that it scales better to large projects and allows\n# full text search. The disadvantages are that it is more difficult to setup\n# and does not have live searching capabilities.\n\nSERVER_BASED_SEARCH    = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will\n# generate Latex output.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `latex' will be used as the default path.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked. If left blank `latex' will be used as the default command name.\n# Note that when enabling USE_PDFLATEX this option is only used for\n# generating bitmaps for formulas in the HTML output, but not in the\n# Makefile that is written to the output directory.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to\n# generate index for LaTeX. If left blank `makeindex' will be used as the\n# default command name.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact\n# LaTeX documents. This may be useful for small projects and may help to\n# save some trees in general.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used\n# by the printer. Possible values are: a4, letter, legal and\n# executive. If left blank a4wide will be used.\n\nPAPER_TYPE             = a4wide\n\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX\n# packages that should be included in the LaTeX output.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for\n# the generated latex document. The header should contain everything until\n# the first chapter. If it is left blank doxygen will generate a\n# standard header. Notice: only use this tag if you know what you are doing!\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for\n# the generated latex document. The footer should contain everything after\n# the last chapter. If it is left blank doxygen will generate a\n# standard footer. Notice: only use this tag if you know what you are doing!\n\nLATEX_FOOTER           =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated\n# is prepared for conversion to pdf (using ps2pdf). The pdf file will\n# contain links (just like the HTML output) instead of page references\n# This makes the output suitable for online browsing using a pdf viewer.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of\n# plain latex in the generated Makefile. Set this option to YES to get a\n# higher quality PDF documentation.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode.\n# command to the generated LaTeX files. This will instruct LaTeX to keep\n# running if errors occur, instead of asking the user for help.\n# This option is also used when generating formulas in HTML.\n\nLATEX_BATCHMODE        = NO\n\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not\n# include the index chapters (such as File Index, Compound Index, etc.)\n# in the output.\n\nLATEX_HIDE_INDICES     = NO\n\n# If LATEX_SOURCE_CODE is set to YES then doxygen will include\n# source code with syntax highlighting in the LaTeX output.\n# Note that which sources are shown also depends on other settings\n# such as SOURCE_BROWSER.\n\nLATEX_SOURCE_CODE      = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. The default style is \"plain\". See\n# http://en.wikipedia.org/wiki/BibTeX for more info.\n\nLATEX_BIB_STYLE        = plain\n\n#---------------------------------------------------------------------------\n# configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output\n# The RTF output is optimized for Word 97 and may not look very pretty with\n# other RTF readers or editors.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `rtf' will be used as the default path.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact\n# RTF documents. This may be useful for small projects and may help to\n# save some trees in general.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated\n# will contain hyperlink fields. The RTF file will\n# contain links (just like the HTML output) instead of page references.\n# This makes the output suitable for online browsing using WORD or other\n# programs which support those fields.\n# Note: wordpad (write) and others do not support links.\n\nRTF_HYPERLINKS         = NO\n\n# Load style sheet definitions from file. Syntax is similar to doxygen's\n# config file, i.e. a series of assignments. You only have to provide\n# replacements, missing definitions are set to their default value.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an rtf document.\n# Syntax is similar to doxygen's config file.\n\nRTF_EXTENSIONS_FILE    =\n\n#---------------------------------------------------------------------------\n# configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will\n# generate man pages\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `man' will be used as the default path.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to\n# the generated man pages (default is the subroutine's section .3)\n\nMAN_EXTENSION          = .3\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output,\n# then it will generate one additional man file for each entity\n# documented in the real man page(s). These additional files\n# only source the real man page, but without them the man command\n# would be unable to find the correct page. The default is NO.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES Doxygen will\n# generate an XML file that captures the structure of\n# the code including all documentation.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `xml' will be used as the default path.\n\nXML_OUTPUT             = xml\n\n# The XML_SCHEMA tag can be used to specify an XML schema,\n# which can be used by a validating XML parser to check the\n# syntax of the XML files.\n\nXML_SCHEMA             =\n\n# The XML_DTD tag can be used to specify an XML DTD,\n# which can be used by a validating XML parser to check the\n# syntax of the XML files.\n\nXML_DTD                =\n\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will\n# dump the program listings (including syntax highlighting\n# and cross-referencing information) to the XML output. Note that\n# enabling this will significantly increase the size of the XML output.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will\n# generate an AutoGen Definitions (see autogen.sf.net) file\n# that captures the structure of the code including all\n# documentation. Note that this feature is still experimental\n# and incomplete at the moment.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will\n# generate a Perl module file that captures the structure of\n# the code including all documentation. Note that this\n# feature is still experimental and incomplete at the\n# moment.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate\n# the necessary Makefile rules, Perl scripts and LaTeX code to be able\n# to generate PDF and DVI output from the Perl module output.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be\n# nicely formatted so it can be parsed by a human reader.\n# This is useful\n# if you want to understand what is going on.\n# On the other hand, if this\n# tag is set to NO the size of the Perl module output will be much smaller\n# and Perl will parse it just the same.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file\n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.\n# This is useful so different doxyrules.make files included by the same\n# Makefile don't overwrite each other's variables.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will\n# evaluate all C-preprocessor directives found in the sources and include\n# files.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro\n# names in the source code. If set to NO (the default) only conditional\n# compilation will be performed. Macro expansion can be done in a controlled\n# way by setting EXPAND_ONLY_PREDEF to YES.\n\nMACRO_EXPANSION        = YES\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES\n# then the macro expansion is limited to the macros specified with the\n# PREDEFINED and EXPAND_AS_DEFINED tags.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files\n# pointed to by INCLUDE_PATH will be searched when a #include is found.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by\n# the preprocessor.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will\n# be used.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that\n# are defined before the preprocessor is started (similar to the -D option of\n# gcc). The argument of the tag is a list of macros of the form: name\n# or name=definition (no spaces). If the definition and the = are\n# omitted =1 is assumed. To prevent a macro definition from being\n# undefined via #undef or recursively expanded use the := operator\n# instead of the = operator.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then\n# this tag can be used to specify a list of macro names that should be expanded.\n# The macro definition that is found in the sources will be used.\n# Use the PREDEFINED tag if you want to use a different macro definition that\n# overrules the definition found in the source code.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then\n# doxygen's preprocessor will remove all references to function-like macros\n# that are alone on a line, have an all uppercase name, and do not end with a\n# semicolon, because these will confuse the parser if not removed.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES option can be used to specify one or more tagfiles. For each\n# tag file the location of the external documentation should be added. The\n# format of a tag file without this location is as follows:\n#\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n#\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where \"loc1\" and \"loc2\" can be relative or absolute paths\n# or URLs. Note that each tag file must have a unique name (where the name does\n# NOT include the path). If a tag file is not located in the directory in which\n# doxygen is run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create\n# a tag file that is based on the input files it reads.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed\n# in the class index. If set to NO only the inherited external classes\n# will be listed.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will\n# be listed.\n\nEXTERNAL_GROUPS        = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of `which perl').\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will\n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base\n# or super classes. Setting the tag to NO turns the diagrams off. Note that\n# this option also works with HAVE_DOT disabled, but it is recommended to\n# install and use dot, since it yields more powerful graphs.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see\n# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            =\n\n# If set to YES, the inheritance and collaboration graphs will hide\n# inheritance and usage relations if the target is undocumented\n# or is not a class.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz, a graph visualization\n# toolkit from AT&T and Lucent Bell Labs. The other options in this section\n# have no effect if this option is set to NO (the default)\n\nHAVE_DOT               = NO\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is\n# allowed to run in parallel. When set to 0 (the default) doxygen will\n# base this on the number of processors available in the system. You can set it\n# explicitly to a value larger than 0 to get control over the balance\n# between CPU load and processing speed.\n\nDOT_NUM_THREADS        = 0\n\n# By default doxygen will use the Helvetica font for all dot files that\n# doxygen generates. When you want a differently looking font you can specify\n# the font name using DOT_FONTNAME. You need to make sure dot is able to find\n# the font, which can be done by putting it in a standard location or by setting\n# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the\n# directory containing the font.\n\nDOT_FONTNAME           = FreeSans\n\n# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.\n# The default size is 10pt.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the Helvetica font.\n# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to\n# set the path where dot can find it.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen\n# will generate a graph for each documented class showing the direct and\n# indirect inheritance relations. Setting this tag to YES will force the\n# CLASS_DIAGRAMS tag to NO.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen\n# will generate a graph for each documented class showing the direct and\n# indirect implementation dependencies (inheritance, containment, and\n# class references variables) of the class with other documented classes.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen\n# will generate a graph for groups, showing the direct groups dependencies\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside\n# the class node. If there are many fields or methods and many nodes the\n# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS\n# threshold limits the number of items for each type to make the size more\n# managable. Set this to 0 for no limit. Note that the threshold may be\n# exceeded by 50% before the limit is enforced.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If set to YES, the inheritance and collaboration graphs will show the\n# relations between templates and their instances.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT\n# tags are set to YES then doxygen will generate a graph for each documented\n# file showing the direct and indirect include dependencies of the file with\n# other documented files.\n\nINCLUDE_GRAPH          = YES\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and\n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each\n# documented header file showing the documented files that directly or\n# indirectly include this file.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH and HAVE_DOT options are set to YES then\n# doxygen will generate a call dependency graph for every global function\n# or class method. Note that enabling this option will significantly increase\n# the time of a run. So in most cases it will be better to enable call graphs\n# for selected functions only using the \\callgraph command.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then\n# doxygen will generate a caller dependency graph for every global function\n# or class method. Note that enabling this option will significantly increase\n# the time of a run. So in most cases it will be better to enable caller\n# graphs for selected functions only using the \\callergraph command.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen\n# will generate a graphical hierarchy of all classes instead of a textual one.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES\n# then doxygen will show the dependencies a directory has on other directories\n# in a graphical way. The dependency relations are determined by the #include\n# relations between the files in the directories.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. Possible values are svg, png, jpg, or gif.\n# If left blank png will be used. If you choose svg you need to set\n# HTML_FILE_EXTENSION to xhtml in order to make the SVG files\n# visible in IE 9+ (other browsers do not have this requirement).\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n# Note that this requires a modern browser other than Internet Explorer.\n# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you\n# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files\n# visible. Older versions of IE do not have SVG support.\n\nINTERACTIVE_SVG        = NO\n\n# The tag DOT_PATH can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the\n# \\dotfile command).\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the\n# \\mscfile command).\n\nMSCFILE_DIRS           =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of\n# nodes that will be shown in the graph. If the number of nodes in a graph\n# becomes larger than this value, doxygen will truncate the graph, which is\n# visualized by representing a node as a red box. Note that doxygen if the\n# number of direct children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note\n# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the\n# graphs generated by dot. A depth value of 3 means that only nodes reachable\n# from the root by following a path via at most 3 edges will be shown. Nodes\n# that lay further from the root node will be omitted. Note that setting this\n# option to 1 or 2 may greatly reduce the computation time needed for large\n# code bases. Also note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not\n# seem to support this out of the box. Warning: Depending on the platform used,\n# enabling this option may lead to badly anti-aliased labels on the edges of\n# a graph (i.e. they become hard to read).\n\nDOT_TRANSPARENT        = YES\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10)\n# support this, this feature is disabled by default.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will\n# generate a legend page explaining the meaning of the various boxes and\n# arrows in the dot generated graphs.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will\n# remove the intermediate dot files that are used to generate\n# the various graphs.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "stms/tinystm/GNU-LICENSE.txt",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "stms/tinystm/MIT-LICENSE.txt",
    "content": "Copyright (c) 2007-2011\n  Pascal Felber <pascal.felber@unine.ch>\n  Patrick Marlier <patrick.marlier@unine.ch>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "stms/tinystm/Makefile",
    "content": "include Makefile.common\n\n########################################################################\n# TinySTM can be configured in many ways.  The main compilation options\n# are described below.  To read more easily through the code, you can\n# generate a source file stripped from most of the conditional\n# preprocessor directives using:\n#\n#   make src/stm.o.c\n#\n# For more details on the LSA algorithm and the design of TinySTM, refer\n# to:\n#\n# [DISC-06] Torvald Riegel, Pascal Felber, and Christof Fetzer.  A Lazy\n#   Snapshot Algorithm with Eager Validation.  20th International\n#   Symposium on Distributed Computing (DISC), 2006.\n#\n# [PPoPP-08] Pascal Felber, Christof Fetzer, and Torvald Riegel.\n#   Dynamic Performance Tuning of Word-Based Software Transactional\n#   Memory.  Proceedings of the 13th ACM SIGPLAN Symposium on Principles\n#   and Practice of Parallel Programming (PPoPP), 2008.\n########################################################################\n\n########################################################################\n# Three different designs can be chosen from, which differ in when locks\n# are acquired (encounter-time vs. commit-time), and when main memory is\n# updated (write-through vs. write-back).\n#\n# WRITE_BACK_ETL: write-back with encounter-time locking acquires lock\n#   when encountering write operations and buffers updates (they are\n#   committed to main memory at commit time).\n#\n# WRITE_BACK_CTL: write-back with commit-time locking delays acquisition\n#   of lock until commit time and buffers updates.\n#\n# WRITE_THROUGH: write-through (encounter-time locking) directly updates\n#   memory and keeps an undo log for possible rollback.\n#\n# Refer to [PPoPP-08] for more details.\n########################################################################\n\nDEFINES += -DDESIGN=WRITE_BACK_ETL\n# DEFINES += -DDESIGN=WRITE_BACK_CTL\n# DEFINES += -DDESIGN=WRITE_THROUGH\n# DEFINES += -DDESIGN=MODULAR\n\n########################################################################\n# Several contention management strategies are available:\n#\n# CM_SUICIDE: immediately abort the transaction that detects the\n#   conflict.\n#\n# CM_DELAY: like CM_SUICIDE but wait until the contended lock that\n#   caused the abort (if any) has been released before restarting the\n#   transaction.  The intuition is that the transaction will likely try\n#   again to acquire the same lock and might fail once more if it has\n#   not been released.  In addition, this increases the chances that the\n#   transaction can succeed with no interruption upon retry, which\n#   improves execution time on the processor.\n#\n# CM_BACKOFF: like CM_SUICIDE but wait for a random delay before\n#   restarting the transaction.  The delay duration is chosen uniformly\n#   at random from a range whose size increases exponentially with every\n#   restart.\n#\n# CM_MODULAR: supports several built-in contention managers.  At the\n#   time, the following ones are supported:\n#   - SUICIDE: kill current transaction (i.e., the transaction that\n#     discovers the conflict).\n#   - AGGRESSIVE: kill other transaction.\n#   - DELAY: same as SUICIDE but wait for conflict resolution before\n#     restart.\n#   - TIMESTAMP: kill youngest transaction.\n#   One can also register custom contention managers.\n########################################################################\n\n# Pick one contention manager (CM)\nDEFINES += -DCM=CM_SUICIDE\n# DEFINES += -DCM=CM_DELAY\n# DEFINES += -DCM=CM_BACKOFF\n# DEFINES += -DCM=CM_MODULAR\n\n########################################################################\n# Enable irrevocable mode (required for using the library with a\n# compiler).\n########################################################################\n\nDEFINES += -DIRREVOCABLE_ENABLED\n# DEFINES += -UIRREVOCABLE_ENABLED\n\n########################################################################\n# Maintain detailed internal statistics.  Statistics are stored in\n# thread locals and do not add much overhead, so do not expect much gain\n# from disabling them.\n########################################################################\n\n# DEFINES += -DTM_STATISTICS\nDEFINES += -UTM_STATISTICS\n# DEFINES += -DTM_STATISTICS2\nDEFINES += -UTM_STATISTICS2\n\n########################################################################\n# Prevent duplicate entries in read/write sets when accessing the same\n# address multiple times.  Enabling this option may reduce performance\n# so leave it disabled unless transactions repeatedly read or write the\n# same address.\n########################################################################\n\n# DEFINES += -DNO_DUPLICATES_IN_RW_SETS\nDEFINES += -UNO_DUPLICATES_IN_RW_SETS\n\n########################################################################\n# Yield the processor when waiting for a contended lock to be released.\n# This only applies to the DELAY and CM_MODULAR contention managers.\n########################################################################\n\n# DEFINES += -DWAIT_YIELD\nDEFINES += -UWAIT_YIELD\n\n########################################################################\n# Use a (degenerate) bloom filter for quickly checking in the write set\n# whether an address has previously been written.  This approach is\n# directly inspired by TL2.  It only applies to the WRITE_BACK_CTL\n# design.\n########################################################################\n\n# DEFINES += -DUSE_BLOOM_FILTER\nDEFINES += -UUSE_BLOOM_FILTER\n\n########################################################################\n# Use an epoch-based memory allocator and garbage collector to ensure\n# that accesses to the dynamic memory allocated by a transaction from\n# another transaction are valid.  There is a slight overhead from\n# enabling this feature.\n########################################################################\n\n# DEFINES += -DEPOCH_GC\nDEFINES += -UEPOCH_GC\n\n########################################################################\n# Keep track of conflicts between transactions and notifies the\n# application (using a callback), passing the identity of the two\n# conflicting transaction and the associated threads.  This feature\n# requires EPOCH_GC.\n########################################################################\n\n# DEFINES += -DCONFLICT_TRACKING\nDEFINES += -UCONFLICT_TRACKING\n\n########################################################################\n# Allow transactions to read the previous version of locked memory\n# locations, as in the original LSA algorithm (see [DISC-06]).  This is\n# achieved by peeking into the write set of the transaction that owns\n# the lock.  There is a small overhead with non-contended workloads but\n# it may significantly reduce the abort rate, especially with\n# transactions that read much data.  This feature only works with the\n# WRITE_BACK_ETL design and MODULAR contention manager.\n########################################################################\n\n# DEFINES += -DREAD_LOCKED_DATA\nDEFINES += -UREAD_LOCKED_DATA\n\n########################################################################\n# Tweak the hash function that maps addresses to locks so that\n# consecutive addresses do not map to consecutive locks.  This can avoid\n# cache line invalidations for application that perform sequential\n# memory accesses.  The last byte of the lock index is swapped with the\n# previous byte.\n########################################################################\n\n# DEFINES += -DLOCK_IDX_SWAP\nDEFINES += -ULOCK_IDX_SWAP\n\n########################################################################\n# Output many (DEBUG) or even mode (DEBUG2) debugging messages.\n########################################################################\n\n# DEFINES += -DDEBUG\nDEFINES += -UDEBUG\n# DEFINES += -DDEBUG2\nDEFINES += -UDEBUG2\n\n########################################################################\n# Catch SIGBUS and SIGSEGV signals\n########################################################################\n\n# DEFINES += -DSIGNAL_HANDLER\nDEFINES += -USIGNAL_HANDLER\n\n# TODO Enable the construction of 32bit lib on 64bit environment \n\n########################################################################\n# Use COMPILER thread-local storage (TLS) support by default\n# TLS_COMPILER: use __thread keyword\n# TLS_POSIX: use posix (pthread) functions\n# TLS_DARWIN: use posix inline functions\n# TLS_GLIBC: use the space reserved for TM in the GLIBC\n########################################################################\n\nDEFINES += -DTLS_COMPILER\n# DEFINES += -DTLS_POSIX\n# DEFINES += -DTLS_DARWIN\n# DEFINES += -DTLS_GLIBC\n\n########################################################################\n# Enable unit transaction\n########################################################################\n\n# DEFINES += -DUNIT_TX\nDEFINES += -UUNIT_TX\n\n########################################################################\n# Various default values can also be overridden:\n#\n# RW_SET_SIZE (default=4096): initial size of the read and write\n#   sets.  These sets will grow dynamically when they become full.\n#\n# LOCK_ARRAY_LOG_SIZE (default=20): number of bits used for indexes in\n#   the lock array.  The size of the array will be 2 to the power of\n#   LOCK_ARRAY_LOG_SIZE.\n#\n# LOCK_SHIFT_EXTRA (default=2): additional shifts to apply to the\n#   address when determining its index in the lock array.  This controls\n#   how many consecutive memory words will be covered by the same lock\n#   (2 to the power of LOCK_SHIFT_EXTRA).  Higher values will increase\n#   false sharing but reduce the number of CASes necessary to acquire\n#   locks and may avoid cache line invalidations on some workloads.  As\n#   shown in [PPoPP-08], a value of 2 seems to offer best performance on\n#   many benchmarks.\n#\n# MIN_BACKOFF (default=0x04UL) and MAX_BACKOFF (default=0x80000000UL):\n#   minimum and maximum values of the exponential backoff delay.  This\n#   parameter is only used with the CM_BACKOFF contention manager.\n#\n# VR_THRESHOLD_DEFAULT (default=3): number of aborts due to failed\n#   validation before switching to visible reads.  A value of 0\n#   indicates no limit.  This parameter is only used with the\n#   CM_MODULAR contention manager.  It can also be set using an\n#   environment variable of the same name.\n########################################################################\n\n# DEFINES += -DRW_SET_SIZE=4096\n# DEFINES += -DLOCK_ARRAY_LOG_SIZE=20\n# DEFINES += -DLOCK_SHIFT_EXTRA=2\n# DEFINES += -DMIN_BACKOFF=0x04UL\n# DEFINES += -DMAX_BACKOFF=0x80000000UL\n# DEFINES += -DVR_THRESHOLD_DEFAULT=3\n\n########################################################################\n# Do not modify anything below this point!\n########################################################################\n\n# Replace textual values by constants for unifdef...\nD := $(DEFINES)\nD := $(D:WRITE_BACK_ETL=0)\nD := $(D:WRITE_BACK_CTL=1)\nD := $(D:WRITE_THROUGH=2)\nD := $(D:MODULAR=3)\nD += -DWRITE_BACK_ETL=0 -DWRITE_BACK_CTL=1 -DWRITE_THROUGH=2 -DMODULAR=3\nD := $(D:CM_SUICIDE=0)\nD := $(D:CM_DELAY=1)\nD := $(D:CM_BACKOFF=2)\nD := $(D:CM_MODULAR=3)\nD += -DCM_SUICIDE=0 -DCM_DELAY=1 -DCM_BACKOFF=2 -DCM_MODULAR=3\n\nifneq (,$(findstring -DEPOCH_GC,$(DEFINES)))\n  GC := $(SRCDIR)/gc.o\nelse\n  GC :=\nendif\n\nCPPFLAGS += -I$(SRCDIR)\nCPPFLAGS += $(DEFINES)\n\nMODULES := $(patsubst %.c,%.o,$(wildcard $(SRCDIR)/mod_*.c))\n\n.PHONY:\tall doc test abi clean check\n\nall:\t$(TMLIB)\n\n%.o:\t%.c Makefile\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -DCOMPILE_FLAGS=\"$(CPPFLAGS) $(CFLAGS)\" -c -o $@ $<\n\n# Additional dependencies\n$(SRCDIR)/stm.o:\t$(INCDIR)/stm.h\n$(SRCDIR)/stm.o:\t$(SRCDIR)/stm_internal.h $(SRCDIR)/stm_wt.h $(SRCDIR)/stm_wbetl.h $(SRCDIR)/stm_wbctl.h $(SRCDIR)/tls.h $(SRCDIR)/utils.h $(SRCDIR)/atomic.h\n\n%.s:\t%.c Makefile\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -DCOMPILE_FLAGS=\"$(CPPFLAGS) $(CFLAGS)\" -fverbose-asm -S -o $@ $<\n\n%.o.c:\t%.c Makefile\n\t$(UNIFDEF) $(D) $< > $@ || true\n\n$(TMLIB):\t$(SRCDIR)/$(TM).o $(SRCDIR)/wrappers.o $(GC) $(MODULES)\n\t$(AR) crus $@ $^\n\ntest:\t$(TMLIB)\n\t$(MAKE) -C test\n\nabi:\n\t$(MAKE) -C abi\n\nabi-%: \t\n\t$(MAKE) -C abi $(subst abi-,,$@)\n\ndoc:\n\t$(DOXYGEN)\n\ncheck: \t$(TMLIB)\n\t$(MAKE) -C test check\n\n# TODO add an install rule\n#install: \t$(TMLIB)\n\nclean:\n\trm -f $(TMLIB) $(SRCDIR)/*.o\n\t$(MAKE) -C abi clean\n\tTARGET=clean $(MAKE) -C test\n\n"
  },
  {
    "path": "stms/tinystm/Makefile.clang",
    "content": "# Debug/optimization flags (optimized by default)\nifeq ($(CFG),debug)\n  CFLAGS += -O0 -ggdb3\nelse\n  # For Link Time Optimization, it requires gold linker and clang compiled with --enable-gold\n  # CFLAGS += -O4\n  # LDFLAGS += -use-gold-plugin\n  CFLAGS += -O3\n  CFLAGS += -march=native\nendif\n\n# Enable all warnings but unsused functions and labels\nCFLAGS += -Wall\nCFLAGS += -Werror -Wno-unused-label -Wno-unused-function\n"
  },
  {
    "path": "stms/tinystm/Makefile.common",
    "content": "# Path to root directory\nROOT ?= .\n\n# CC, LD and AR are builtin-variables of Make (?= is useless in this case)\n# To override these defines, you must use \"make CC=cc\" or change it here\n# Linker set by default to the CC definition\nLD = $(CC)\n# Other tools\nDOXYGEN ?= doxygen\nUNIFDEF ?= unifdef\n\n# Define global parameters\nTM = stm\nSRCDIR = $(ROOT)/src\nINCDIR = $(ROOT)/include\nLIBDIR = $(ROOT)/lib\nTMLIB = $(LIBDIR)/lib$(TM).a\n\n# Supposing all compilers has -I -L\n# TODO -I$(SRCDIR) only for library build\nCPPFLAGS += -I$(INCDIR) -I$(SRCDIR)\n\n# Disable assert for non-debug build\nifneq ($(CFG),debug)\n  CPPFLAGS += -DNDEBUG\nendif\n\n# TODO Should be only for test binaries\nLDFLAGS += -L$(LIBDIR) -l$(TM)\n\n# Only on linux / TODO make source compatible with non-pthread OS\nLDFLAGS += -lpthread\n\n# Solaris default memory allocator is quite slow, better use mtmalloc\n# LDFLAGS += -lmtmalloc\n\n# Disable additionnal checks from glibc (__longjmp_chk/__printf_chk)\nCPPFLAGS += -U_FORTIFY_SOURCE\n# CPPFLAGS += -D_FORTIFY_SOURCE=0\n# Enable multi-thread support in glibc\nCPPFLAGS += -D_REENTRANT\n\n# Rely on the definition of CC to determine the compiler\n# if the compiler is not detected correctly, use \"gmake COMPILER=your_compiler\"\n# Default: gcc\nCOMPILER ?= $(CC)\nifeq ($(COMPILER),icc)\ninclude $(ROOT)/Makefile.icc\nelse\nifeq ($(COMPILER),suncc)\ninclude $(ROOT)/Makefile.suncc\nelse\nifeq ($(COMPILER),xlc)\nelse\nifeq ($(COMPILER),llvm-gcc)\nelse\nifeq ($(COMPILER),clang)\ninclude $(ROOT)/Makefile.clang\nelse\ninclude $(ROOT)/Makefile.gcc\nendif\nendif\nendif\nendif\nendif\n\n########################################################################\n# libatomic_ops path\n# LIBAO_HOME must be set to the path of libatomic_ops\n# (use the embedded light libatomic_ops if LIBAO_HOME is not defined)\n########################################################################\nifndef LIBAO_HOME\n  LIBAO_HOME = $(SRCDIR)/atomic_ops\n  LIBAO_INC = $(LIBAO_HOME)\nelse\n  LIBAO_INC = $(LIBAO_HOME)/include\nendif\nCPPFLAGS += -I$(LIBAO_INC)\n"
  },
  {
    "path": "stms/tinystm/Makefile.gcc",
    "content": "# Debug/optimization flags (optimized by default)\nifeq ($(CFG),debug)\n  CFLAGS += -O0 -ggdb3\nelse\n  CFLAGS += -O2\n  CFLAGS += -march=native\nendif\n\n# Disable strict aliasing \n# TODO: no-strict-aliasing removes some optimizations but seems required for correctness. need more investigation.\nCFLAGS += -fno-strict-aliasing\n# Disable stack smashing protector (__stack_chk_fail)\nCFLAGS += -fno-stack-protector\n# Enable all warnings but unsused functions and labels\nCFLAGS += -Wall -Wno-unused-function -Wno-unused-label\n# Enable extra warnings\n# CFLAGS += -Wextra\n# Link Time Optimization (LDFLAGS also requires optimization flags)\n# CFLAGS += -flto\n# LDFLAGS += $(CFLAGS) -fwhole-program -fuse-linker-plugin\n\n# Enable profiling mode\n# CFLAGS += -fprofile-generate\n# LDFLAGS += -fprofile-generate\n# Run typical program\n# Use the profiling information to compile\n# CFLAGS += -fprofile-use\n# LDFLAGS += -fprofile-use\n\n"
  },
  {
    "path": "stms/tinystm/Makefile.icc",
    "content": "# Intel compiler has a GCC compatibility mode\n\n# Debug/optimization flags (optimized by default)\nifeq ($(CFG),debug)\n  CFLAGS += -O0 -ggdb3\nelse\n  CFLAGS += -xHOST -O2\nendif\n\n# Full optimizations (IPO, O3, xHOST)\n# CFLAGS += -fast\n\n# Disable strict aliasing (remove some optimization but required for correctness? need more investigation)\nCFLAGS += -fno-strict-aliasing\n# Disable stack smashing protector (__stack_chk_fail)\nCFLAGS += -fno-stack-protector\n# Enable all warnings but unsused functions and labels\nCFLAGS += -Wall\n# Enable inlining information\n# CFLAGS += -Winline\n# Disable intel builtins like _intel_fast_memset\n# CFLAGS += -fno-builtin\n# Align functions on 16-bytes boundary\n# CFLAGS += -falign-functions=16\n\n# Enable profiling mode\n# CFLAGS += -prof-gen\n# LDFLAGS += -prof-gen\n# Run typical program\n# Use the profiled information to compile\n# CFLAGS += -prof-use\n# LDFLAGS += -prof-use\n\n"
  },
  {
    "path": "stms/tinystm/Makefile.suncc",
    "content": "# Debug/optimization flags (optimized by default)\nifeq ($(CFG),debug)\n  CFLAGS += -g\nelse\n  CFLAGS += -xO3\n  CFLAGS += -native\nendif\n\n# Enable all optimizations\n# CFLAGS += -fast\n# Enable Inter-procedural optimization (LTO)\n# CFLAGS += -xipo=2\n# Enable profiling mode\n# CFLAGS += -xprofile=collect\n# Run typical program\n# Use the profiling information to compile\n# CFLAGS += -xprofile=use\n"
  },
  {
    "path": "stms/tinystm/README.md",
    "content": "TinySTM\n=======\n\nOVERVIEW\n--------\n\nTinySTM is a lightweight but efficient word-based STM implementation.\nThis distribution includes three versions of TinySTM: write-back\n(updates are buffered until commit time), write-through (updates are\ndirectly written to memory), and commit-time locking (locks are only\nacquired upon commit).  The version can be selected by editing the\nmakefile, which documents all the different compilation options.\n\nTinySTM compiles and runs on 32 or 64-bit architectures.  It was tested\non various flavors of Unix, on Mac OS X, and on Windows using cygwin.\nIt comes with a few test applications, notably a linked list, a skip\nlist, and a red-black tree.\n\n\nINSTALLATION\n------------\n\nTinySTM requires the 'atomic\\_ops' library, freely available from\n[www.hpl.hp.com](http://www.hpl.hp.com/research/linux/atomic_ops/).\nA stripped-down version of the library is included in the TinySTM \ndistribution.  If you wish to use another version, you must set the \nenvironment variable LIBAO\\_HOME to the installation directory of\n'atomic\\_ops'.\n\nIf your system does not support GCC thread-local storage, modify the\nTLS parameter in the 'Makefile' file.\n\nTo compile TinySTM libraries, execute 'make' in the main directory.  To\ncompile test applications, execute 'make test'.  To check the compiled\nlibrary, execute 'make check'. 'make clean' will remove all compiled\nfiles.\nTo compile the TinySTM GCC compatible library, execute 'make abi-gcc'.\nTo compile test applications, execute 'make abi-gcc-test'.\n\n\nCONTACT\n-------\n\n* E-mail : [tinystm@tinystm.org](mailto:tinystm@tinystm.org)\n* Web    : [http://tinystm.org](http://tinystm.org) and\n [http://www.tmware.org](http://www.tmware.org)\n\n\nACKNOWLEDGEMENT\n---------------\n\nThis library was supported by the European research consortium\n[VELOX](http://www.velox-project.eu).\n"
  },
  {
    "path": "stms/tinystm/abi/Makefile",
    "content": "\n.PHONY:\tall gcc dtmc intel clean test check\n\nall:\tgcc dtmc intel \n\ngcc:\n\t$(MAKE) -C gcc\n\ngcc%:\n\t$(MAKE) -C gcc $(subst -, , $(subst gcc,,$@))\n\ndtmc:\n\t$(MAKE) -C dtmc\n\ndtmc%:\n\t$(MAKE) -C dtmc $(subst -, , $(subst dtmc,,$@))\n\nintel:\n\t$(MAKE) -C intel\n\nintel%:\n\t$(MAKE) -C intel $(subst -, , $(subst intel,,$@))\n\nclean:\n\t$(MAKE) -C test clean\n\t$(MAKE) -C gcc clean\n\t$(MAKE) -C dtmc clean\n\t$(MAKE) -C intel clean\n\n# simple test and check that use explicit calls to gcc libitm library\ntest:\n\t$(MAKE) -C test test\n\ncheck:\n\t$(MAKE) -C test check\n\n# test-all and check-all need TM compilers (INTEL/DTMC/GCC) in the path \ntest-all:\n\t$(MAKE) -C gcc test\n\t$(MAKE) -C dtmc test\n\t$(MAKE) -C intel test\n\ncheck-all:\n\t$(MAKE) -C gcc check\n\t$(MAKE) -C dtmc check\n\t$(MAKE) -C intel check\n\ngcc/libitm.h: libitm.h.tpl.header libitm.h.tpl.unifdef libitm.h.tpl.cpp libitm.h.tpl.footer\n\tcat libitm.h.tpl.header > $@\n\tunifdef -DTM_GCC -UTM_INTEL -UTM_DTMC libitm.h.tpl.unifdef >> $@ || true\n\tcat libitm.h.tpl.cpp >> $@\n\tcat libitm.h.tpl.footer >> $@\n\tsed -i 's/TX_ARGS //g' $@\n\tsed -i 's/TX_ARG//g' $@\n\ndtmc/libitm.h: libitm.h.tpl.header libitm.h.tpl.unifdef libitm.h.tpl.cpp libitm.h.tpl.footer\n\tcat libitm.h.tpl.header > $@\n\tunifdef -UTM_GCC -UTM_INTEL -DTM_DTMC libitm.h.tpl.unifdef >> $@ || true\n\tcat libitm.h.tpl.cpp >> $@\n\tcat libitm.h.tpl.footer >> $@\n\tsed -i 's/TX_ARGS//g' $@\n\tsed -i 's/TX_ARG//g' $@\n\nintel/libitm.h: libitm.h.tpl.header libitm.h.tpl.unifdef libitm.h.tpl.cpp libitm.h.tpl.footer\n\tcat libitm.h.tpl.header > $@\n\tunifdef -UTM_GCC -DTM_INTEL -UTM_DTMC libitm.h.tpl.unifdef >> $@ || true\n\tcat libitm.h.tpl.cpp >> $@\n\tcat libitm.h.tpl.footer >> $@\n\tsed -i 's/TX_ARGS/_ITM_transaction *,/g' $@\n\tsed -i 's/TX_ARG/_ITM_transaction */g' $@\n\n"
  },
  {
    "path": "stms/tinystm/abi/Makefile.common",
    "content": "# Path to tinySTM\nROOT ?= ..\n\n# ROOT must be defined to include Makefile.common\ninclude $(ROOT)/Makefile.common\n\n##############################################################################\n# Compilation options.  Note that the definitions from the main makefile\n# are not used here, so one can use different options here.\n##############################################################################\n\n#TODO test if function are inline or need a specific header to force inlining\n#TODO Flags may changed. I must find a way to keep up to date with current tiny. \n\n# DEFINES += -DDESIGN=WRITE_BACK_ETL\n# DEFINES += -DDESIGN=WRITE_BACK_CTL\nDEFINES += -DDESIGN=WRITE_THROUGH\n\nDEFINES += -DCM=CM_SUICIDE\n# DEFINES += -DCM=CM_DELAY\n# DEFINES += -DCM=CM_BACKOFF\n# DEFINES += -DCM=CM_MODULAR\n\n#DEFINES += -DEPOCH_GC\nDEFINES += -UEPOCH_GC\n# DEFINES += -DREAD_LOCKED_DATA\n\n#DEFINES += -DLOCK_SHIFT_EXTRA=0\nDEFINES += -DTM_STATISTICS\nDEFINES += -UTM_STATISTICS2\n\n# DEFINES += -DNO_STACK_CHECK\n# DEFINES += -DTANGER_STATS\n\nDEFINES += -DIRREVOCABLE_ENABLED\n# DEFINES += -UIRREVOCABLE_ENABLED\n\n# Add wrapper for pthread function \n# DEFINES += -DPTHREAD_WRAPPER\nDEFINES += -UPTHREAD_WRAPPER\n# TODO if THREAD_WRAPPER is defined, library must be linked with -ldl\n\n# Define how TLS is used in ABI (should be removed for next release)\nDEFINES += -DTLS_COMPILER\n\n##############################################################################\n# Do not modify anything below this point!\n##############################################################################\n# TODO Use libtool to generate libraries\n# libtool --mode=compile\n# libtool --mode=link\n# libtool --mode=install \n\n# NOTES\n# Use explicit parameters for Tanger and Intel STM Compiler\n\n# TODO make it MacOS compatible\n\n# Remove the -DEXPLICIT_TX_PARAMETER flag if defined\n# Manage it accordingly to the required library \n# TODO is it useful?\nDEF_ABI = $(subst -DEXPLICIT_TX_PARAMETER,,$(DEFINES))\n\n# Rules for intset benchmarks\nBINS = intset-hs intset-ll intset-rb intset-sl bank\n\nintset-hs.o:\t$(ROOT)/test/intset/intset.c\n\t$(TESTCC) $(TESTCFLAGS) -DUSE_HASHSET -c -o $@ $<\n\nintset-ll.o:\t$(ROOT)/test/intset/intset.c\n\t$(TESTCC) $(TESTCFLAGS) -DUSE_LINKEDLIST -c -o $@ $<\n\nintset-rb.o:\t$(ROOT)/test/intset/intset.c\n\t$(TESTCC) $(TESTCFLAGS) -DUSE_RBTREE -c -o $@ $<\n\nintset-sl.o:\t$(ROOT)/test/intset/intset.c\n\t$(TESTCC) $(TESTCFLAGS) -DUSE_SKIPLIST -c -o $@ $<\n\nbank.o:\t$(ROOT)/test/bank/bank.c\n\t$(TESTCC) $(TESTCFLAGS) -c -o $@ $<\n\n# FIXME in case of ABI $(TMLIB) must be replaced to abi/...\n$(BINS):\t%:\t%.o all\n\t$(TESTLD) -o $@ $< $(TESTLDFLAGS) -lpthread\n\ntest: \tall $(BINS)\n\nintset-clean:\n\trm -f $(BINS)\n\ncheck: \ttest intset-check\n\nintset-check:\n\t@echo Testing Linked List \\(intset-ll\\)\n\t@./intset-ll -d 2000 1>/dev/null 2>&1\n\t@echo Testing Linked List with concurrency \\(intset-ll -n 4\\)\n\t@./intset-ll -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo Testing Red Black Tree \\(intset-rb\\)\n\t@./intset-rb -d 2000 1>/dev/null 2>&1\n\t@echo Testing Red Black Tree with concurrency \\(intset-rb -n 4\\)\n\t@./intset-rb -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo Testing Skip List \\(intset-sl\\)\n\t@./intset-sl -d 2000 1>/dev/null 2>&1\n\t@echo Testing Skip List with concurrency \\(intset-sl -n 4\\)\n\t@./intset-sl -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo Testing Hash Set \\(intset-hs\\)\n\t@./intset-hs -d 2000 1>/dev/null 2>&1\n\t@echo Testing Hash Set with concurrency \\(intset-hs -n 4\\)\n\t@./intset-hs -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo All tests passed\n\n"
  },
  {
    "path": "stms/tinystm/abi/abi.c",
    "content": "/*\n * File:\n *   abi.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   ABI for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#define _GNU_SOURCE\n#include <alloca.h>\n#include <assert.h>\n#include <string.h>\n#include <stdbool.h>\n#include <pthread.h>\n#ifdef __SSE__\n# include <xmmintrin.h>\n#endif /* __SSE__ */\n\n#include \"libitm.h\"\n#include \"utils.h\"\n\n/* FIXME STACK_CHECK: DTMC and GCC can use ITM_W to write on stack variable */\n/* TODO STACK_CHECK: to finish and test */\n\n#include \"stm.h\"\n#include \"atomic.h\"\n#include \"mod_cb.h\"\n#include \"mod_mem.h\"\n#include \"mod_log.h\"\n#include \"wrappers.h\"\n#ifdef TM_DTMC\n# include \"dtmc/tanger-stm-internal.h\"\n# include \"dtmc/tanger.h\"\n#endif\n\n/* Indicates to use _ITM_siglongjmp */\n#ifdef TM_DTMC\n# define CTX_ITM   tanger_stm_restore_stack(); _ITM_siglongjmp\n#else\n# define CTX_ITM   _ITM_siglongjmp\n#endif /* ! TM_DTMC */\nextern void _ITM_CALL_CONVENTION _ITM_siglongjmp(int val, sigjmp_buf env) __attribute__ ((noreturn));\n\n#include \"stm.c\"\n#include \"mod_cb_mem.c\"\n#ifdef TM_GCC\n# include \"gcc/alloc_cpp.c\"\n#endif\n#include \"mod_log.c\"\n#include \"wrappers.c\"\n#ifdef EPOCH_GC\n# include \"gc.c\"\n#endif\n\n/* pthread wrapper */\n#ifdef PTHREAD_WRAPPER\n# include \"pthread_wrapper.h\"\n#endif /* PTHREAD_WRAPPER */\n\n#if defined(TM_GCC) || defined(TM_DTMC)\n# define TX_ARG\n# define TX_ARGS\n# define TX_GET_ABI   stm_tx_t *tx = tls_get_tx()\n#elif defined(TM_INTEL)\n# define TX_ARG       _ITM_transaction *__td\n# define TX_ARGS      _ITM_transaction *__td,\n# define TX_GET_ABI   stm_tx_t *tx = (stm_tx_t *)__td\n#else\n# error \"No ABI defined\"\n#endif\n\n/* ################################################################### *\n * VARIABLES\n * ################################################################### */\n/* Status of the ABI */\nenum {\n  ABI_NOT_INITIALIZED,\n  ABI_INITIALIZING,\n  ABI_INITIALIZED,\n  ABI_FINALIZING,\n};\n\nstatic union {\n  struct {\n    volatile unsigned long status;\n    volatile unsigned long thread_counter;\n  };\n  uint8_t padding[64]; /* TODO should be cacheline related */\n} __attribute__((aligned(64))) global_abi = {{.status = ABI_NOT_INITIALIZED, .thread_counter = 0 }};\n\n\ntypedef struct {\n  int thread_id;\n#ifdef STACK_CHECK\n/* TODO STACK_CHECK could be moved to stm.c and we could calculate a mask to detect if the address is in the stack */\n  void *stack_addr_low;\n  void *stack_addr_high;\n#endif /* STACK_CHECK */\n} thread_abi_t;\n\n/* Statistics */\ntypedef struct stats {\n  int thread_id;\n  unsigned long nb_commits;\n  unsigned long nb_aborts;\n  double nb_retries_avg;\n  unsigned long nb_retries_min;\n  unsigned long nb_retries_max;\n\n  struct stats * next;\n} stats_t;\n\n/* Thread statistics managed as a linked list */\n/* TODO align + padding */\nstats_t * thread_stats = NULL;\n\n\n/* ################################################################### *\n * COMPATIBILITY FUNCTIONS\n * ################################################################### */\n#ifdef STACK_CHECK\nstatic int get_stack_attr(void *low, void *high)\n{\n  /* GNU Pthread specific */\n  pthread_attr_t attr;\n  uintptr_t stackaddr;\n  size_t stacksize;\n  if (pthread_getattr_np(pthread_self(), &attr)) {\n    return 1;\n  }\n  if (pthread_attr_getstack(&attr, (void *)&stackaddr, &stacksize)) {\n    return 1;\n  }\n  *(uintptr_t *)low = stackaddr;\n  *(uintptr_t *)high = stackaddr + stacksize;\n\n  return 0;\n}\n/* Hints for other platforms\n#if PLATFORM(DARWIN) \npthread_get_stackaddr_np(pthread_self()); \n#endif\n#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC) \n// offset 0x18 from the FS segment register gives a pointer to \n// the thread information block for the current thread \nNT_TIB* pTib; \n__asm { \nMOV EAX, FS:[18h] \nMOV pTib, EAX \n} \nreturn (void*)pTib->StackBase; \n#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) \nPNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); \nreturn (void*)pTib->StackBase; \n#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC) \n// offset 0x18 from the FS segment register gives a pointer to \n// the thread information block for the current thread \nNT_TIB* pTib; \nasm ( \"movl %%fs:0x18, %0\\n\" \n: \"=r\" (pTib) \n); \nreturn (void*)pTib->StackBase; \n#endif\n*/\nstatic INLINE int on_stack(void *a)\n{\n#ifdef TLS\n  thread_abi_t *t = thread_abi;\n#else /* ! TLS */\n  thread_abi_t *t = pthread_getspecific(thread_abi);\n#endif /* ! TLS */\n  if ((t->stack_addr_low <= (uintptr_t)a) && ((uintptr_t)a < t->stack_addr_high)) { \n    return 1;\n  } \n  return 0;\n}\n#endif /* STACK_CHECK */\n\n\n#if defined(__APPLE__)\n/* OS X */\n# include <malloc/malloc.h>\nINLINE size_t block_size(void *ptr)\n{\n  return malloc_size(ptr);\n}\n#elif defined(__linux__) || defined(__CYGWIN__)\n/* Linux, WIN32 (CYGWIN) */\n# include <malloc.h>\nINLINE size_t block_size(void *ptr)\n{\n  return malloc_usable_size(ptr);\n}\n#else /* ! (defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__)) */\n# error \"Target OS does not provide size of allocated blocks\"\n#endif /* ! (defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__)) */\n\n\n/* ################################################################### *\n * \n * ################################################################### */\nstatic void abi_init(void);\n\nstatic INLINE stm_tx_t *\nabi_init_thread(void)\n{\n  stm_tx_t *tx = tls_get_tx();\n  if (tx == NULL) {\n    /* Make sure that the main initilization is done */\n    if (ATOMIC_LOAD(&global_abi.status) != ABI_INITIALIZED)\n      _ITM_initializeProcess();\n    //t->thread_id = (int)ATOMIC_FETCH_INC_FULL(&global_abi.thread_counter);\n    tx = stm_init_thread();\n#ifdef STACK_CHECK\n    get_stack_attr(&t->stack_addr_low, &t->stack_addr_high);\n#endif /* STACK_CHECK */\n  }\n  return tx;\n}\n\nstatic void\nabi_exit_thread(struct stm_tx *tx)\n{\n  if (tx == NULL)\n    return;\n#if 0\n  /* FIXME disable during refactoring */\n  if (getenv(\"ITM_STATISTICS\") != NULL) {\n    stats_t * ts = malloc(sizeof(stats_t));\n#ifdef TLS\n    thread_abi_t *t = thread_abi;\n#else /* ! TLS */\n    thread_abi_t *t = pthread_getspecific(thread_abi);\n#endif /* ! TLS */\n    ts->thread_id = t->thread_id;\n    stm_get_local_stats(\"nb_commits\", &ts->nb_commits);\n    stm_get_local_stats(\"nb_aborts\", &ts->nb_aborts);\n    stm_get_local_stats(\"nb_retries_avg\", &ts->nb_retries_avg);\n    stm_get_local_stats(\"nb_retries_min\", &ts->nb_retries_min);\n    stm_get_local_stats(\"nb_retries_max\", &ts->nb_retries_max);\n    /* Register thread-statistics to global */\n    do {\n\tts->next = (stats_t *)ATOMIC_LOAD(&thread_stats);\n    } while (ATOMIC_CAS_FULL(&thread_stats, ts->next, ts) == 0);\n    /* ts will be freed on _ITM_finalizeProcess. */\n#ifdef TLS\n    thread_abi = NULL;\n#else /* ! TLS */\n    pthread_setspecific(thread_abi, NULL);\n#endif\n    /* Free thread_abi_t structure. */\n    free(t);\n  }\n#endif\n\n  stm_exit_thread();\n\n#ifdef TM_DTMC\n  /* Free the saved stack */\n  tanger_stm_free_stack();\n#endif\n}\n\nstatic INLINE void\nabi_init(void)\n{\n  /* thread safe */\nreload:\n  if (ATOMIC_LOAD_ACQ(&global_abi.status) == ABI_NOT_INITIALIZED) {\n    if (ATOMIC_CAS_FULL(&global_abi.status, ABI_NOT_INITIALIZED, ABI_INITIALIZING) != 0) {\n      /* TODO temporary to be sure to use tinySTM */\n      printf(\"TinySTM-ABI v%s.\\n\", _ITM_libraryVersion());\n      atexit((void (*)(void))(_ITM_finalizeProcess));\n\n      /* TinySTM initialization */\n      stm_init();\n      mod_mem_init(0);\n# ifdef TM_GCC\n      mod_alloc_cpp();\n# endif /* TM_GCC */\n      mod_log_init();\n      mod_cb_init();\n      ATOMIC_STORE(&global_abi.status, ABI_INITIALIZED);\n      /* Also initialize thread as specify in the specification */\n      abi_init_thread();\n      return; \n    } else {\n      goto reload;\n    }\n  } else if (ATOMIC_LOAD_ACQ(&global_abi.status) != ABI_INITIALIZED) {\n    /* Wait the end of the initialization */\n    goto reload;\n  }\n\n  return;\n}\n\nstatic INLINE void\nabi_exit(void)\n{\n  TX_GET;\n  char * statistics;\n\n  abi_exit_thread(tx);\n\n  /* Ensure thread safety */\nreload:\n  if (ATOMIC_LOAD_ACQ(&global_abi.status) == ABI_INITIALIZED) {\n    if (ATOMIC_CAS_FULL(&global_abi.status, ABI_INITIALIZED, ABI_FINALIZING) == 0)\n      goto reload;\n  } else {\n    return;\n  }\n\n  if ((statistics = getenv(\"ITM_STATISTICS\")) != NULL) {\n    FILE * f;\n    int i = 0;\n    stats_t * ts;\n    if (statistics[0] == '-')\n      f = stdout;\n    else if ((f = fopen(\"itm.log\", \"w\")) == NULL) {\n      fprintf(stderr, \"can't open itm.log for writing\\n\");\n      goto finishing;\n    }\n    fprintf(f, \"STATS REPORT\\n\");\n    fprintf(f, \"THREAD TOTALS\\n\");\n\n    while (1) {\n      do {\n        ts = (stats_t *)ATOMIC_LOAD(&thread_stats);\n\tif (ts == NULL)\n\t  goto no_more_stat;\n      } while(ATOMIC_CAS_FULL(&thread_stats, ts, ts->next) == 0);\n      /* Skip stats if not a transactional thread */\n      if (ts->nb_commits == 0)\n        continue;\n      fprintf(f, \"Thread %-4i                : %12s %12s %12s %12s\\n\", i, \"Min\", \"Mean\", \"Max\", \"Total\");\n      fprintf(f, \"  Transactions             : %12lu\\n\", ts->nb_commits);\n      fprintf(f, \"  %-25s: %12lu %12.2f %12lu %12lu\\n\", \"Retries\", ts->nb_retries_min, ts->nb_retries_avg, ts->nb_retries_max, ts->nb_aborts);\n      fprintf(f,\"\\n\");\n      /* Free the thread stats structure */\n      free(ts);\n      i++;\n    }\nno_more_stat:\n    if (f != stdout) {\n      fclose(f);\n    }\n  }\nfinishing:\n  stm_exit();\n\n  ATOMIC_STORE(&global_abi.status, ABI_NOT_INITIALIZED);\n}\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n_ITM_transaction * _ITM_CALL_CONVENTION _ITM_getTransaction(void)\n{\n  struct stm_tx *tx = tls_get_tx();\n  if (unlikely(tx == NULL)) {\n    /* Thread not initialized: must create transaction */\n    tx = abi_init_thread();\n  }\n\n  return (_ITM_transaction *)tx;\n}\n\n_ITM_howExecuting _ITM_CALL_CONVENTION _ITM_inTransaction(TX_ARG)\n{\n  TX_GET_ABI;\n  if (stm_irrevocable_tx(tx))\n    return inIrrevocableTransaction;\n  if (stm_active_tx(tx))\n    return inRetryableTransaction;\n  return outsideTransaction;\n}\n\nint _ITM_CALL_CONVENTION _ITM_getThreadnum(void)\n{\n  /* FIXME should be done in stm? */\n  return (int)pthread_self();\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_addUserCommitAction(TX_ARGS\n                              _ITM_userCommitFunction __commit,\n                              _ITM_transactionId resumingTransactionId,\n                              void *__arg)\n{\n  stm_on_commit(__commit, __arg);\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_addUserUndoAction(TX_ARGS\n                            const _ITM_userUndoFunction __undo, void * __arg)\n{\n  stm_on_abort(__undo, __arg);\n}\n\n/*\n * Specification: The getTransactionId function returns a sequence number for\n * the current transaction. Within a transaction, nested transactions are \n * numbered sequentially in the order in which they start, with the outermost\n * transaction getting the lowest number, and non-transactional code the value\n * _ITM_NoTransactionId, which is less than any transaction id for \n * transactional code.\n */\n_ITM_transactionId _ITM_CALL_CONVENTION _ITM_getTransactionId(TX_ARG)\n{\n  TX_GET_ABI;\n  if (tx == NULL)\n    return _ITM_noTransactionId;\n  /* Note that _ITM_noTransactionId is 1 */\n  return (_ITM_transactionId)(tx->nesting + 1);\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_dropReferences(TX_ARGS const void *__start,\n                                              size_t __size)\n{\n  fprintf(stderr, \"%s: not yet implemented\\n\", __func__);\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_userError(const char *errString, int exitCode)\n{\n  fprintf(stderr, \"%s\", errString);\n  exit(exitCode);\n}\n\nconst char * _ITM_CALL_CONVENTION _ITM_libraryVersion(void)\n{\n  return _ITM_VERSION_NO_STR \" using TinySTM \" STM_VERSION \"\";\n}\n\nint _ITM_CALL_CONVENTION _ITM_versionCompatible(int version)\n{\n  return version == _ITM_VERSION_NO;\n}\n\nint _ITM_CALL_CONVENTION _ITM_initializeThread(void)\n{\n  abi_init_thread();\n  return 0;\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_finalizeThread(void)\n{\n  TX_GET;\n  abi_exit_thread(tx);\n}\n\n#ifdef __PIC__\n/* Add call when the library is loaded and unloaded */\n#define ATTR_CONSTRUCTOR __attribute__ ((constructor))  \n#define ATTR_DESTRUCTOR __attribute__ ((destructor))  \n#else\n#define ATTR_CONSTRUCTOR \n#define ATTR_DESTRUCTOR \n#endif\n\nvoid ATTR_DESTRUCTOR _ITM_CALL_CONVENTION _ITM_finalizeProcess(void)\n{\n  abi_exit();\n}\n\nint ATTR_CONSTRUCTOR _ITM_CALL_CONVENTION _ITM_initializeProcess(void)\n{\n  abi_init();\n  return 0;\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_error(const _ITM_srcLocation *__src, int errorCode)\n{\n  fprintf(stderr, \"Error: %s (%d)\\n\", (__src == NULL || __src->psource == NULL ? \"?\" : __src->psource), errorCode);\n  exit(1);\n}\n\n/* The _ITM_beginTransaction is defined in assembly (arch.S)  */\nuint32_t _ITM_CALL_CONVENTION GTM_begin_transaction(TX_ARGS uint32_t attr, jmp_buf * buf) \n{\n  /* FIXME first time return a_saveLiveVariable +> siglongjmp must return a_restoreLiveVariable (and set a_saveLiveVariable)\n   *       check a_abortTransaction attr\n   * */\n  TX_GET_ABI;\n  uint32_t ret;\n  sigjmp_buf * env;\n\n  /* This variable is in the stack but stm_start copies the content. */\n  stm_tx_attr_t _a = (stm_tx_attr_t)0;\n\n#ifdef TM_GCC\n  /* GCC does not call initializeProcess TODO: other fix possible? */\n  if (unlikely(tx == NULL)) {\n    /* Thread not initialized: must create transaction */\n    tx = abi_init_thread();\n  }\n#endif\n  assert(tx != NULL);\n\n#ifdef TM_DTMC\n  /* FIXME this should be fixed with stdcall conv call */\n  /* DTMC prior or equal to Velox R3 did not use regparm(2) with x86-32. */\n  /* TODO to be removed when new release of DTMC fix it. */\n  /* attr = 3; */\n  ret = a_runInstrumentedCode;\n#else /* !TM_DTMC */\n  /* Manage attribute for the transaction */\n  if (unlikely((attr & pr_doesGoIrrevocable) || !(attr & pr_instrumentedCode))) {\n    /* TODO Add an attribute to specify irrevocable TX */\n    stm_set_irrevocable_tx(tx, 1);\n    ret = a_runUninstrumentedCode;\n    if ((attr & pr_multiwayCode) == pr_instrumentedCode)\n      ret = a_runInstrumentedCode;\n  } else {\n#ifdef TM_GCC\n    if (attr & pr_readOnly)\n      _a.read_only = 1;\n#endif /* TM_GCC */\n\n    ret = a_runInstrumentedCode | a_saveLiveVariables;\n  }\n#endif /* !TM_DTMC */\n\n#ifdef TM_DTMC\n  /* if (ret & a_runInstrumentedCode) */\n  tanger_stm_save_stack();\n#endif /* TM_DTMC */\n\n  env = int_stm_start(tx, _a);\n  /* Save thread context only when outermost transaction */\n  /* TODO check that the memcpy is fast. */\n  if (likely(env != NULL))\n    memcpy(env, buf, sizeof(jmp_buf)); /* TODO limit size to real size */\n\n  return ret;\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_commitTransaction(\n#if defined(TM_GCC)\n                             void\n#else /* !TM_GCC */\n                             TX_ARGS const _ITM_srcLocation *__src\n#endif /* !TM_GCC */\n                             )\n{\n  TX_GET_ABI;\n  int_stm_commit(tx);\n#ifdef TM_DTMC\n  tanger_stm_reset_stack();\n#endif /* TM_DTMC */\n}\n\nbool _ITM_CALL_CONVENTION _ITM_tryCommitTransaction(TX_ARGS\n                                   const _ITM_srcLocation *__src)\n{\n  TX_GET_ABI;\n  return (int_stm_commit(tx) != 0);\n}\n\n/**\n * Commits all inner transactions nested within the transaction specified by\n * the transaction id parameter.\n */\nvoid _ITM_CALL_CONVENTION _ITM_commitTransactionToId(TX_ARGS\n                              const _ITM_transactionId tid,\n                              const _ITM_srcLocation *__src)\n{\n  TX_GET_ABI;\n  while ((tx->nesting + 1) > tid)\n    int_stm_commit(tx);\n}\n\n/* TODO: add noreturn attribute. */\nvoid _ITM_CALL_CONVENTION _ITM_abortTransaction(TX_ARGS\n                              _ITM_abortReason __reason,\n                              const _ITM_srcLocation *__src)\n{\n  TX_GET_ABI;\n  if( __reason == userAbort) {\n    /* __tm_abort was invoked. */\n    __reason = STM_ABORT_NO_RETRY;\n  } else if(__reason == userRetry) {\n    /* __tm_retry was invoked. */\n    __reason = STM_ABORT_EXPLICIT;\n  }\n  stm_rollback(tx, __reason);\n}\n\n/* TODO: add noreturn attribute. */\nvoid _ITM_CALL_CONVENTION _ITM_rollbackTransaction(TX_ARGS\n                              const _ITM_srcLocation *__src)\n{\n  /* TODO check exactly the purpose of this function */\n  TX_GET_ABI;\n  stm_rollback(tx, STM_ABORT_EXPLICIT);\n}\n\n\nvoid _ITM_CALL_CONVENTION _ITM_registerThrownObject(TX_ARGS\n                              const void *__obj, size_t __size)\n{\n  // TODO A rollback of the tx will not roll back the registered object\n  fprintf(stderr, \"%s: not yet implemented\\n\", __func__);\n}\n\nvoid _ITM_CALL_CONVENTION _ITM_changeTransactionMode(TX_ARGS\n                              _ITM_transactionState __mode,\n                              const _ITM_srcLocation *__loc)\n{\n  /* FIXME: it seems there is a problem with irrevocable and intel c */\n  switch (__mode) {\n    case modeSerialIrrevocable:\n      stm_set_irrevocable(1);\n      /* TODO a_runUninstrumentedCode must be set at rollback! */\n      break;\n    case modeObstinate:\n    case modeOptimistic:\n    case modePessimistic:\n    default:\n\tfprintf(stderr, \"This mode %d is not implemented yet\\n\", __mode);\n  }\n}\n\n#if defined(TM_GCC) || defined(TM_DTMC)\nvoid * _ITM_malloc(size_t size)\n{\n  stm_tx_t *tx = tls_get_tx();\n  if (tx == NULL || !stm_active_tx(tx))\n    return malloc(size);\n  return stm_malloc_tx(tx, size);\n}\n\nvoid * _ITM_calloc(size_t nm, size_t size)\n{\n  stm_tx_t *tx = tls_get_tx();\n  if (tx == NULL || !stm_active_tx(tx))\n    return calloc(nm, size);\n  return stm_calloc_tx(tx, nm, size);\n}\n\nvoid _ITM_free(void *ptr)\n{\n  stm_tx_t *tx = tls_get_tx();\n  if (tx == NULL || !stm_active_tx(tx)) {\n    free(ptr);\n    return;\n  }\n#ifdef NO_WRITE_ON_FREE\n  stm_free_tx(tx, ptr, 0);\n#else\n  stm_free_tx(tx, ptr, block_size(ptr));\n#endif\n}\n#endif /* defined(TM_GCC) || defined(TM_DTMC) */\n\n\n#ifdef TM_GCC\n# include \"gcc/clone.c\"\n# include \"gcc/eh.c\"\n\n/* TODO This function is not fully compatible, need to delete exception\n * on abort. */\nvoid _ITM_CALL_CONVENTION _ITM_commitTransactionEH(void *exc_ptr)\n{\n  TX_GET_ABI;\n  int_stm_commit(tx);\n}\n#endif /* TM_GCC */\n\n#ifdef TM_INTEL\n# include \"intel/alloc.c\"\n#endif\n\n\n/**** LOAD STORE LOG FUNCTIONS ****/\n\n#define TM_LOAD(F, T, WF, WT) \\\n  T _ITM_CALL_CONVENTION F(TX_ARGS const T *addr) \\\n  { \\\n    return (WT)WF((volatile WT *)addr); \\\n  }\n\n#define TM_LOAD_GENERIC(F, T) \\\n  T _ITM_CALL_CONVENTION F(TX_ARGS const T *addr) \\\n  { \\\n    union { T d; uint8_t s[sizeof(T)]; } c; \\\n    stm_load_bytes((volatile uint8_t *)addr, c.s, sizeof(T)); \\\n    return c.d; \\\n  }\n\n/* TODO if WRITE_BACK/ALL?, write to stack must be saved and written directly\n * TODO must use stm_log is addresses are under the beginTransaction\n  if (on_stack(addr)) { stm_log_u64(addr); *addr = val; } \nnot enough because if we abort and restore -> stack can be corrupted\n*/\n#ifdef STACK_CHECK\n#define TM_STORE(F, T, WF, WT) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS const T *addr, T val) \\\n  { \\\n    if (on_stack(addr)) *((T*)addr) = val; \\\n    else WF((volatile WT *)addr, (WT)val); \\\n  }\n#else /* !STACK_CHECK */\n#define TM_STORE(F, T, WF, WT) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS const T *addr, T val) \\\n  { \\\n    WF((volatile WT *)addr, (WT)val); \\\n  }\n#endif /* !STACK_CHECK */\n\n#define TM_STORE_GENERIC(F, T) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS const T *addr, T val) \\\n  { \\\n    union { T d; uint8_t s[sizeof(T)]; } c; \\\n    c.d = val; \\\n    stm_store_bytes((volatile uint8_t *)addr, c.s, sizeof(T)); \\\n  }\n\n#define TM_LOG(F, T, WF, WT) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS const T *addr) \\\n  { \\\n    WF((WT *)addr); \\\n  }\n\n#define TM_LOG_GENERIC(F, T) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS const T *addr) \\\n  { \\\n    stm_log_bytes((uint8_t *)addr, sizeof(T));    \\\n  }\n\n#define TM_STORE_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, const void *src, size_t size) \\\n  { \\\n    stm_store_bytes((volatile uint8_t *)dst, (uint8_t *)src, size); \\\n  }\n\n#define TM_LOAD_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, const void *src, size_t size) \\\n  { \\\n    stm_load_bytes((volatile uint8_t *)src, (uint8_t *)dst, size); \\\n  }\n\n#define TM_LOG_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS const void *addr, size_t size) \\\n  { \\\n    stm_log_bytes((uint8_t *)addr, size); \\\n  }\n\n#ifdef STACK_CHECK\n#define TM_SET_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, int val, size_t count) \\\n  { \\\n    if (on_stack(dst)) memset(dst, val, count); \\\n    else stm_set_bytes((volatile uint8_t *)dst, val, count); \\\n  }\n#else /* !STACK_CHECK */\n#define TM_SET_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, int val, size_t count) \\\n  { \\\n    stm_set_bytes((volatile uint8_t *)dst, val, count); \\\n  }\n#endif /* !STACK_CHECK */\n\n#ifdef STACK_CHECK\n#define TM_COPY_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, const void *src, size_t size) \\\n  { \\\n    uint8_t *buf = (uint8_t *)alloca(size); \\\n    if (on_stack(src)) memcpy(buf, src, size); \\\n    stm_load_bytes((volatile uint8_t *)src, buf, size); \\\n    if (on_stack(dst)) memcpy(dst, buf, size); \\\n    else stm_store_bytes((volatile uint8_t *)dst, buf, size); \\\n  }\n#else /* !STACK_CHECK */\n#define TM_COPY_BYTES(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, const void *src, size_t size) \\\n  { \\\n    uint8_t *buf = (uint8_t *)alloca(size); \\\n    stm_load_bytes((volatile uint8_t *)src, buf, size); \\\n    stm_store_bytes((volatile uint8_t *)dst, buf, size); \\\n  }\n#endif /* !STACK_CHECK */\n\n#define TM_COPY_BYTES_RN_WT(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, const void *src, size_t size) \\\n  { \\\n    uint8_t *buf = (uint8_t *)alloca(size); \\\n    memcpy(buf, src, size); \\\n    stm_store_bytes((volatile uint8_t *)dst, buf, size); \\\n  }\n\n#define TM_COPY_BYTES_RT_WN(F) \\\n  void _ITM_CALL_CONVENTION F(TX_ARGS void *dst, const void *src, size_t size) \\\n  { \\\n    uint8_t *buf = (uint8_t *)alloca(size); \\\n    stm_load_bytes((volatile uint8_t *)src, buf, size); \\\n    memcpy(dst, buf, size); \\\n  }\n\n#define TM_LOAD_ALL(E, T, WF, WT) \\\n  TM_LOAD(_ITM_R##E, T, WF, WT) \\\n  TM_LOAD(_ITM_RaR##E, T, WF, WT) \\\n  TM_LOAD(_ITM_RaW##E, T, WF, WT) \\\n  TM_LOAD(_ITM_RfW##E, T, WF, WT)\n\n#define TM_LOAD_GENERIC_ALL(E, T) \\\n  TM_LOAD_GENERIC(_ITM_R##E, T) \\\n  TM_LOAD_GENERIC(_ITM_RaR##E, T) \\\n  TM_LOAD_GENERIC(_ITM_RaW##E, T) \\\n  TM_LOAD_GENERIC(_ITM_RfW##E, T)\n\n#define TM_STORE_ALL(E, T, WF, WT) \\\n  TM_STORE(_ITM_W##E, T, WF, WT) \\\n  TM_STORE(_ITM_WaR##E, T, WF, WT) \\\n  TM_STORE(_ITM_WaW##E, T, WF, WT)\n\n#define TM_STORE_GENERIC_ALL(E, T) \\\n  TM_STORE_GENERIC(_ITM_W##E, T) \\\n  TM_STORE_GENERIC(_ITM_WaR##E, T) \\\n  TM_STORE_GENERIC(_ITM_WaW##E, T)\n\n\n/* TODO U1 U2 should not use the inline stm_load to increase locality */\nTM_LOAD_ALL(U1, uint8_t, int_stm_load_u8, uint8_t)\nTM_LOAD_ALL(U2, uint16_t, int_stm_load_u16, uint16_t)\nTM_LOAD_ALL(U4, uint32_t, int_stm_load_u32, uint32_t)\nTM_LOAD_ALL(U8, uint64_t, int_stm_load_u64, uint64_t)\nTM_LOAD_ALL(F, float, stm_load_float, float)\nTM_LOAD_ALL(D, double, stm_load_double, double)\n#ifdef __SSE__\nTM_LOAD_GENERIC_ALL(M64, __m64)\nTM_LOAD_GENERIC_ALL(M128, __m128)\n#endif /* __SSE__ */\nTM_LOAD_GENERIC_ALL(CF, float _Complex)\nTM_LOAD_GENERIC_ALL(CD, double _Complex)\nTM_LOAD_GENERIC_ALL(CE, long double _Complex)\n\nTM_STORE_ALL(U1, uint8_t, int_stm_store_u8, uint8_t)\nTM_STORE_ALL(U2, uint16_t, int_stm_store_u16, uint16_t)\nTM_STORE_ALL(U4, uint32_t, int_stm_store_u32, uint32_t)\nTM_STORE_ALL(U8, uint64_t, int_stm_store_u64, uint64_t)\nTM_STORE_ALL(F, float, stm_store_float, float)\nTM_STORE_ALL(D, double, stm_store_double, double)\n#ifdef __SSE__\nTM_STORE_GENERIC_ALL(M64, __m64)\nTM_STORE_GENERIC_ALL(M128, __m128)\n#endif /* __SSE__ */\nTM_STORE_GENERIC_ALL(CF, float _Complex)\nTM_STORE_GENERIC_ALL(CD, double _Complex)\nTM_STORE_GENERIC_ALL(CE, long double _Complex)\n\nTM_STORE_BYTES(_ITM_memcpyRnWt)\nTM_STORE_BYTES(_ITM_memcpyRnWtaR)\nTM_STORE_BYTES(_ITM_memcpyRnWtaW)\n\nTM_LOAD_BYTES(_ITM_memcpyRtWn)\nTM_LOAD_BYTES(_ITM_memcpyRtaRWn)\nTM_LOAD_BYTES(_ITM_memcpyRtaWWn)\n\nTM_COPY_BYTES(_ITM_memcpyRtWt)\nTM_COPY_BYTES(_ITM_memcpyRtWtaR)\nTM_COPY_BYTES(_ITM_memcpyRtWtaW)\nTM_COPY_BYTES(_ITM_memcpyRtaRWt)\nTM_COPY_BYTES(_ITM_memcpyRtaRWtaR)\nTM_COPY_BYTES(_ITM_memcpyRtaRWtaW)\nTM_COPY_BYTES(_ITM_memcpyRtaWWt)\nTM_COPY_BYTES(_ITM_memcpyRtaWWtaR)\nTM_COPY_BYTES(_ITM_memcpyRtaWWtaW)\n\nTM_LOG(_ITM_LU1, uint8_t, stm_log_u8, uint8_t)\nTM_LOG(_ITM_LU2, uint16_t, stm_log_u16, uint16_t)\nTM_LOG(_ITM_LU4, uint32_t, stm_log_u32, uint32_t)\nTM_LOG(_ITM_LU8, uint64_t, stm_log_u64, uint64_t)\nTM_LOG(_ITM_LF, float, stm_log_float, float)\nTM_LOG(_ITM_LD, double, stm_log_double, double)\nTM_LOG_GENERIC(_ITM_LE, long double)\n#ifdef __SSE__\nTM_LOG_GENERIC(_ITM_LM64, __m64)\nTM_LOG_GENERIC(_ITM_LM128, __m128)\n#endif /* __SSE__ */\nTM_LOG_GENERIC(_ITM_LCF, float _Complex)\nTM_LOG_GENERIC(_ITM_LCD, double _Complex)\nTM_LOG_GENERIC(_ITM_LCE, long double _Complex)\n\nTM_LOG_BYTES(_ITM_LB)\n\nTM_SET_BYTES(_ITM_memsetW)\nTM_SET_BYTES(_ITM_memsetWaR)\nTM_SET_BYTES(_ITM_memsetWaW)\n\nTM_COPY_BYTES_RN_WT(_ITM_memmoveRnWt)\nTM_COPY_BYTES_RN_WT(_ITM_memmoveRnWtaR)\nTM_COPY_BYTES_RN_WT(_ITM_memmoveRnWtaW)\n\nTM_COPY_BYTES_RT_WN(_ITM_memmoveRtWn)\nTM_COPY_BYTES_RT_WN(_ITM_memmoveRtaRWn)\nTM_COPY_BYTES_RT_WN(_ITM_memmoveRtaWWn)\n\nTM_COPY_BYTES(_ITM_memmoveRtWt)\nTM_COPY_BYTES(_ITM_memmoveRtWtaR)\nTM_COPY_BYTES(_ITM_memmoveRtWtaW)\nTM_COPY_BYTES(_ITM_memmoveRtaRWt)\nTM_COPY_BYTES(_ITM_memmoveRtaRWtaR)\nTM_COPY_BYTES(_ITM_memmoveRtaRWtaW)\nTM_COPY_BYTES(_ITM_memmoveRtaWWt)\nTM_COPY_BYTES(_ITM_memmoveRtaWWtaR)\nTM_COPY_BYTES(_ITM_memmoveRtaWWtaW)\n\n#ifdef TM_DTMC\n/* DTMC file uses this macro name for other thing */\n# undef TM_LOAD\n# undef TM_STORE\n# include \"dtmc/tanger.c\"\n#endif /* TM_DTMC */\n\n"
  },
  {
    "path": "stms/tinystm/abi/arch_x86.S",
    "content": "/* Copyright (C) 2008, 2009 Free Software Foundation, Inc.\n   Contributed by Richard Henderson <rth@redhat.com>.\n\n   This file is part of the GNU Transactional Memory Library (libitm).\n\n   Libitm is free software; you can redistribute it and/or modify it\n   under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 3 of the License, or\n   (at your option) any later version.\n\n   Libitm is distributed in the hope that it will be useful, but WITHOUT ANY\n   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n   more details.\n\n   Under Section 7 of GPL version 3, you are granted additional\n   permissions described in the GCC Runtime Library Exception, version\n   3.1, as published by the Free Software Foundation.\n\n   You should have received a copy of the GNU General Public License and\n   a copy of the GCC Runtime Library Exception along with this program;\n   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see\n   <http://www.gnu.org/licenses/>.  */\n/* Modify for TinySTM and Intel STM Compiler */\n\n/* Linux specific, Windows uses a different calling convention. */\n#ifndef __linux__\n#error This file is linux specific.\n#endif\n\n\n\n\t.text\n\t.p2align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n\n_ITM_beginTransaction:\n\t.cfi_startproc\n#ifdef __LP64__\n/* Paramters (in order) is in rdi, rsi, rdx, rcx, r8, r9 */\n/* Temporary registers is r10, r11 (not saved) */\n/* To be saved are rbx, rsp, rbp, r12, r13, r14, r15 */\n/* push register can be also used */\n\tleaq\t8(%rsp), %rax     /* Save stack pointer */ \n\tmovq\t(%rsp), %r8       /* Save return address */\n#if defined(EXPLICIT_TX_PARAMETER)\n/* NOTE we already have transaction descriptor, we copy directly to tx->env (first field of stm_tx_t) and not on the stack */\n\tmovq\t%rax, (%rdi)      /* rax is the original stack pointer */\n\tmovq\t%r8, 8(%rdi)      /* r8 is the return address */\n\tmovq\t%rbx, 16(%rdi)    /* saves all registers needed */\n\tmovq\t%rbp, 24(%rdi)\n\tmovq\t%r12, 32(%rdi)\n\tmovq\t%r13, 40(%rdi)\n\tmovq\t%r14, 48(%rdi)\n\tmovq\t%r15, 56(%rdi)\n        movq    %rdi, %rdx    /* set 3rd parameter, 2nd and 1st is untouched */\n\tcall\tGTM_begin_transaction\n#else\n\tsubq\t$72, %rsp         /* Allocate space from the stack */\n\t.cfi_def_cfa_offset 80    /* Debug info */\n\tmovq\t%rax, (%rsp)      /* rax is the original stack pointer */\n\tmovq\t%r8, 8(%rsp)      /* r8 is the return address */\n\tmovq\t%rbx, 16(%rsp)    /* saves all registers needed */\n\tmovq\t%rbp, 24(%rsp)\n\tmovq\t%r12, 32(%rsp)\n\tmovq\t%r13, 40(%rsp)\n\tmovq\t%r14, 48(%rsp)\n\tmovq\t%r15, 56(%rsp)\n\tmovq\t%rsp, %rsi    /* set 2nd paramter (pointer to the stack where registers are saved), 1st is untouched (rdi) */\n\tcall\tGTM_begin_transaction\n\taddq\t$72, %rsp         /* Remove allocated space from the stack */\n#endif\n\t.cfi_def_cfa_offset 8\n\tret\n#else /* !LP64  */\n/* NOTE attribute regparm(2) has to be set for all itm function and push 3rd argument on stack with icc */\n/* fastcall convention argument: eax, edx, then on the stack (GCC specific) */\n/* TODO: only tested with Intel (tanger could use another calling convention) */\n\t/* eax: tx, edx: attr, stack: __src */\n#if defined(EXPLICIT_TX_PARAMETER)\n\tleal\t4(%esp), %ecx     /* Get esp (stack pointer) */\n\tmovl\t%ecx, (%eax)      /* Save stack pointer */\n\tmovl\t(%esp), %ecx      /* Get return address */\n\tmovl\t%ebx, 4(%eax)     /* Save registers */\n\tmovl\t%esi, 8(%eax)\n\tmovl\t%edi, 12(%eax)\n\tmovl\t%ebp, 16(%eax)\n\tmovl\t%ecx, 20(%eax)    /* Save return address */\n// NOTE third argument is not handle in this case\n\tcall\tGTM_begin_transaction\n#else\n\tleal\t4(%esp), %ecx\n\tsubl\t$28, %esp         /* Reserve space on the stack */\n\t.cfi_def_cfa_offset 32\n\tmovl\t%ecx, 8(%esp)\n\tmovl\t%ebx, 12(%esp)    /* Save registers */\n\tmovl\t%esi, 16(%esp)\n\tmovl\t%edi, 20(%esp)\n\tmovl\t%ebp, 24(%esp)\n\tleal\t8(%esp), %edx\n\tcall\tGTM_begin_transaction\n\taddl\t$28, %esp\n#endif /* EXPLICIT_TX_PARAMETER  */\n\t.cfi_def_cfa_offset 4\n\tret\n#endif /* !LP64 */\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\n\n\n\t.p2align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n\n_ITM_siglongjmp:\n\t.cfi_startproc\n#ifdef __LP64__\n\tmovq\t(%rdi), %rcx\n\tmovq\t8(%rdi), %rdx\n\tmovq\t16(%rdi), %rbx   /* Restore registers */\n\tmovq\t24(%rdi), %rbp\n\tmovq\t32(%rdi), %r12\n\tmovq\t40(%rdi), %r13\n\tmovq\t48(%rdi), %r14\n\tmovq\t56(%rdi), %r15\n\tmovl\t%esi, %eax       /* 2nd paramter (esi) is returned value (eax, int, 32 bit) */\n\t.cfi_def_cfa %rcx, 0\n\t.cfi_register %rip, %rdx\n\tmovq\t%rcx, %rsp\n\tjmp\t*%rdx\n#else\n\txchgl\t%eax, %edx\n\tmovl\t(%edx), %ecx      /* esp (stack pointer) will be restored later */\n\tmovl\t4(%edx), %ebx     /* restore registers */\n\tmovl\t8(%edx), %esi\n\tmovl\t12(%edx), %edi\n\tmovl\t16(%edx), %ebp\n\tmovl\t20(%edx), %edx    /* eip (instruction pointer) will be restored after */\n\t.cfi_def_cfa %ecx, 0\n\t.cfi_register %eip, %edx\n\tmovl\t%ecx, %esp        /* restore esp, stack pointer */\n\tjmp\t*%edx             /* restore eip, instruction pointer */\n#endif\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n// TODO Defined this elsewhere\n#if defined(TM_INTEL) && !defined(__PIC__) \n\n\t.p2align 4\n\t.globl\tmalloc._$WrapTXN\n\t.type\tmalloc._$WrapTXN, @function\n\t.hidden\tmalloc._$WrapTXN\n\t.globl\tmalloc._$TXN\n\t.type\tmalloc._$TXN, @function\n\t.hidden\tmalloc._$TXN\n\nmalloc._$WrapTXN:\nmalloc._$TXN:\n\t.cfi_startproc\n#ifdef __LP64__\n\tjmp _ITM_malloc\n#else\n\t/* NOTE: unfortunately icc-32bit doesn't recognized it as regparm(2)\n\t   TODO: a way to defined it?\n\t*/\n\tmovl \t4(%esp), %eax  /* Set 1st param */\n\tcall \t_ITM_malloc\n\tmovl \t%eax, 4(%esp)  /* Set return value */\n\tret\n#endif\n\t.cfi_endproc\n\t.size\tmalloc._$TXN, .-malloc._$TXN\n\t.size\tmalloc._$WrapTXN, .-malloc._$WrapTXN\n\n\n\n\t.p2align 4\n\t.globl\tfree._$WrapTXN\n\t.type\tfree._$WrapTXN, @function\n\t.hidden\tfree._$WrapTXN\n\t.globl\tfree._$TXN\n\t.type\tfree._$TXN, @function\n\t.hidden\tfree._$TXN\n\nfree._$WrapTXN:\nfree._$TXN:\n\t.cfi_startproc\n#ifdef __LP64__\n\tjmp _ITM_free\n#else\n\t/* NOTE: unfortunately icc-32bit doesn't recognized it as regparm(2)\n\t   TODO: a way to defined it?\n\t*/\n\tmovl \t4(%esp), %eax  /* Set 1st param */\n\tcall \t_ITM_free\n\tmovl \t%eax, 4(%esp)  /* Set return value */\n\tret\n#endif\n\t.cfi_endproc\n\t.size\tfree._$WrapTXN, .-free._$WrapTXN\n\t.size\tfree._$TXN, .-free._$TXN\n\n#endif\n\n.section .note.GNU-stack, \"\", @progbits\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/Makefile",
    "content": "# Path to tinySTM\nROOT = ../..\n\n.PHONY:\tdtmc all clean check\n\nall: \tdtmc\n\n# ROOT must be defined to include Makefile.common\ninclude $(ROOT)/abi/Makefile.common\n\n##############################################################################\n## DTMC\n##############################################################################\nLLVMCC ?= llvm-gcc\nLLVMLD ?= llvm-ld\nLLC    ?= llc\n\nCPPFLAGS += -DTM_DTMC -I. \n\n# TODO find a way to avoid compiling not\n#LLVMCC_OK = $(shell $(LLVMCC) ; if [ $$? -neq 0 ] ; then echo \"no differences\" ; fi)\n#@$(echo) \"TEST\"\n#if [ $$? -eq 0 ] ; then echo \"no differences\" ; fi\n#$(shell echo $(LLVMCC_OK))\n\n# -DNO_STACK_CHECK => shouldn't be used\n# TODO Add possibility to create 32 bits lib => llvm-ld needs -m32?\n# TODO find a good way to add dependencies abi.c tanger.c arch.S and also the lib (otherwise it will not be built or updated)\n#%.bc:   ../%.c\n#\t$(LLVMCC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -emit-llvm -c -o $@ $<\n\ndtmc: \tdtmc-bc dtmc-static\n\nlibtanger-stm.bc: \t../abi.c tanger.c tanger.h\n\t$(LLVMCC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -emit-llvm -c -o abi.bc ../abi.c\n\t$(LLVMLD) -link-as-library -o $@ abi.bc\n\narch.o: \tarch.S\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<\n\ndtmc-static: \tlibtanger-stm.bc arch.o \n\t$(LLC) libtanger-stm.bc -o libtanger-stm.s\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -c libtanger-stm.s -o libtanger-stm.o\n\t$(AR) cru libitm.a libtanger-stm.o arch.o\n\ndtmc-bc: \tlibtanger-stm.bc arch.o\n\t$(AR) cru libtanger-stm.a arch.o\n\n##############################################################################\n\nTANGERDIR       ?= YOU_DID_NOT_SET_TANGERDIR\nLLVMBUILD       ?= $(shell llvm-config --build-mode)\nifeq ($(shell uname),Darwin)\n  LIBTYPE       ?= dylib\nelse\n  LIBTYPE       ?= so\nendif\n#STMLIBDIR       ?= $(TANGERDIR)/$(LLVMBUILD)/lib/\nSTMLIBDIR       ?= .\nSTMSUPPORTDIR   ?= $(TANGERDIR)/$(LLVMBUILD)/lib/\nTANGERPASS      ?= $(TANGERDIR)/$(LLVMBUILD)/lib/libtanger.$(LIBTYPE)\nTMLINK          ?= $(TANGERDIR)/$(LLVMBUILD)/bin/tmlink\nTMLINKFLAGS     ?= -stmsupport=$(STMSUPPORTDIR) -stmlib=$(STMLIBDIR)\nLLVMCCFLAGS     ?= --gnu-tm -emit-llvm\n\nTESTCC          ?= $(LLVMCC)\nTESTCFLAGS      += $(LLVMCCFLAGS) -DTM_DTMC\n\nTESTLD          ?= $(TMLINK)\nTESTLDFLAGS     := $(TMLINKFLAGS) $(TESTLDFLAGS) \n# TESTLDFLAGS     += -static \n\nclean: \tintset-clean\n\trm -f *.bc *.o libtanger-stm.bc libtanger-stm.a libitm.a libtanger-stm.s\n\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/arch.S",
    "content": "#ifndef __linux__\n/* Linux specific, Windows uses a different calling convention. */\n/* TODO probably solaris is fine with it. */\n# error This file is linux specific.\n#endif\n\n\t.text\n\n#if defined(__x86_64__)\n\t.align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n\n_ITM_beginTransaction:\n\t.cfi_startproc\n/* Paramters (in order) is in rdi, rsi, rdx, rcx, r8, r9 */\n/* Temporary registers is r10, r11 (not saved) */\n/* To be saved are rbx, rsp, rbp, r12, r13, r14, r15 */\n\tleaq\t8(%rsp), %rax    /* Save stack pointer */\n\tsubq\t$56, %rsp\n\t.cfi_def_cfa_offset 64\n\tmovq\t%rax, (%rsp)\n\tmovq\t%rbx, 8(%rsp)\n\tmovq\t%rbp, 16(%rsp)\n\tmovq\t%r12, 24(%rsp)\n\tmovq\t%r13, 32(%rsp)\n\tmovq\t%r14, 40(%rsp)\n\tmovq\t%r15, 48(%rsp)\n\tmovq\t%rsp, %rsi\n\tcall\tGTM_begin_transaction\n\taddq\t$56, %rsp\n\t.cfi_def_cfa_offset 8\n\tret\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovq\t(%rsi), %rcx\n\tmovq\t8(%rsi), %rbx\n\tmovq\t16(%rsi), %rbp\n\tmovq\t24(%rsi), %r12\n\tmovq\t32(%rsi), %r13\n\tmovq\t40(%rsi), %r14\n\tmovq\t48(%rsi), %r15\n\tmovl\t%edi, %eax\n\tandq    $0x03, %rax \t\t\t/* DTMC uses highest bits for multiple code path */\n\t.cfi_def_cfa %rsi, 0\n\t.cfi_offset %rip, 56\n\t.cfi_register %rsp, %rcx\n\tmovq\t%rcx, %rsp\n\tjmp\t*56(%rsi)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__i386__)\n\t.align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n_ITM_beginTransaction:\n\t.cfi_startproc\n\tleal\t4(%esp), %ecx\n\tmovl\t4(%esp), %eax\n\tsubl\t$28, %esp\n\t.cfi_def_cfa_offset 32\n\tmovl\t%ecx, 8(%esp)\n\tmovl\t%ebx, 12(%esp)\n\tmovl\t%esi, 16(%esp)\n\tmovl\t%edi, 20(%esp)\n\tmovl\t%ebp, 24(%esp)\n\tleal\t8(%esp), %edx\n\tcall\tGTM_begin_transaction\n\taddl\t$28, %esp\n\t.cfi_def_cfa_offset 4\n\tret\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovl\t(%edx), %ecx\n\tmovl\t4(%edx), %ebx\n\tmovl\t8(%edx), %esi\n\tmovl\t12(%edx), %edi\n\tmovl\t16(%edx), %ebp\n\tandl    $0x03, %eax \t\t\t/* DTMC uses highest bits for multiple code path */\n\t.cfi_def_cfa %edx, 0\n\t.cfi_offset %eip, 20\n\t.cfi_register %esp, %ecx\n\tmovl\t%ecx, %esp\n\tjmp\t*20(%edx)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__sparc__)\n# error SPARC arch is not yet supported\n#else\n# error Unsupported architecture\n#endif\n\n#ifdef __linux__\n.section .note.GNU-stack, \"\", @progbits\n#endif\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/libitm.h",
    "content": "/*\n * File:\n *   libitm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   ABI for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _LIBITM_H_\n#define _LIBITM_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#include <stdint.h>\n#include <stdbool.h>\n#ifdef __SSE__\n# include <xmmintrin.h>\n#endif\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n#define _ITM_VERSION_NO_STR \"1.0.4\"\n#define _ITM_VERSION_NO 104\n\n#if defined(__i386__)\n# define _ITM_CALL_CONVENTION __attribute__((regparm(2)))\n#else\n# define _ITM_CALL_CONVENTION\n#endif\n\n#define _ITM_noTransactionId 1\t\t/* Id for non-transactional code. */\n\n\n#define _ITM_TRANSACTION_PURE __attribute__((transaction_pure))\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef void *_ITM_transaction;\n\ntypedef void (*_ITM_userUndoFunction)(void *);\ntypedef void (*_ITM_userCommitFunction)(void *);\n\ntypedef uint32_t _ITM_transactionId;\n\ntypedef enum\n{\n  outsideTransaction = 0,\n  inRetryableTransaction,\n  inIrrevocableTransaction\n} _ITM_howExecuting;\n\nstruct _ITM_srcLocationS\n{\n  int32_t reserved_1;\n  int32_t flags;\n  int32_t reserved_2;\n  int32_t reserved_3;\n  const char *psource;\n};\n\ntypedef struct _ITM_srcLocationS _ITM_srcLocation;\n\ntypedef enum {\n  pr_instrumentedCode = 0x0001,\n  pr_uninstrumentedCode = 0x0002,\n  pr_multiwayCode = pr_instrumentedCode | pr_uninstrumentedCode,\n  pr_hasNoXMMUpdate = 0x0004,\n  pr_hasNoAbort = 0x0008,\n  pr_hasNoRetry = 0x0010,\n  pr_hasNoIrrevocable = 0x0020,\n  pr_doesGoIrrevocable = 0x0040,\n  pr_hasNoSimpleReads = 0x0080,\n  pr_aWBarriersOmitted = 0x0100,\n  pr_RaRBarriersOmitted = 0x0200,\n  pr_undoLogCode = 0x0400,\n  pr_preferUninstrumented = 0x0800,\n  pr_exceptionBlock = 0x1000,\n  pr_hasElse = 0x2000,\n  pr_readOnly = 0x4000 /* GNU gcc specific */\n} _ITM_codeProperties;\n\ntypedef enum {\n  a_runInstrumentedCode = 0x01,\n  a_runUninstrumentedCode = 0x02,\n  a_saveLiveVariables = 0x04,\n  a_restoreLiveVariables = 0x08,\n  a_abortTransaction = 0x10,\n} _ITM_actions;\n\ntypedef enum {\n  modeSerialIrrevocable,\n  modeObstinate,\n  modeOptimistic,\n  modePessimistic,\n} _ITM_transactionState;\n\ntypedef enum {\n  unknown = 0,\n  userAbort = 1,\n  userRetry = 2,\n  TMConflict= 4,\n  exceptionBlockAbort = 8\n} _ITM_abortReason;\n\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transaction * _ITM_CALL_CONVENTION _ITM_getTransaction(void);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_howExecuting _ITM_CALL_CONVENTION _ITM_inTransaction();\n\nextern _ITM_TRANSACTION_PURE\nint _ITM_CALL_CONVENTION _ITM_getThreadnum(void);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserCommitAction( \n                             _ITM_userCommitFunction __commit,\n                             _ITM_transactionId resumingTransactionId,\n                             void *__arg);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserUndoAction( \n                             const _ITM_userUndoFunction __undo, void * __arg);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transactionId _ITM_CALL_CONVENTION _ITM_getTransactionId();\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_dropReferences( \n                             const void *__start, size_t __size);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_userError(const char *errString, int exitCode);\n\nextern const char * _ITM_CALL_CONVENTION _ITM_libraryVersion(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_versionCompatible(int version);\n\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeProcess(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeProcess(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_error(const _ITM_srcLocation *__src,\n                             int errorCode);\n\nextern uint32_t _ITM_CALL_CONVENTION _ITM_beginTransaction( \n                             uint32_t __properties,\n                             const _ITM_srcLocation *__src)\n                             __attribute__((returns_twice));\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransaction( \n                             const _ITM_srcLocation *__src);\n\n\nextern bool _ITM_CALL_CONVENTION _ITM_tryCommitTransaction( \n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransactionToId( \n                             const _ITM_transactionId tid,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_abortTransaction( \n                             _ITM_abortReason __reason,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_rollbackTransaction( \n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_registerThrownObject( \n                             const void *__obj,\n                             size_t __size);\n\nextern void _ITM_CALL_CONVENTION _ITM_changeTransactionMode( \n                             _ITM_transactionState __mode,\n                             const _ITM_srcLocation *__loc);\n\n\nextern void * _ITM_malloc(size_t);\nextern void * _ITM_calloc(size_t, size_t);\nextern void _ITM_free(void *);\n\n/*** Loads ***/\n\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RU1( const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaRU1( const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaWU1( const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RfWU1( const uint8_t *);\n\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RU2( const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaRU2( const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaWU2( const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RfWU2( const uint16_t *);\n\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RU4( const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaRU4( const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaWU4( const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RfWU4( const uint32_t *);\n\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RU8( const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaRU8( const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaWU8( const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RfWU8( const uint64_t *);\n\nextern float _ITM_CALL_CONVENTION _ITM_RF( const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaRF( const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaWF( const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RfWF( const float *);\n\nextern double _ITM_CALL_CONVENTION _ITM_RD( const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaRD( const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaWD( const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RfWD( const double *);\n\n#ifdef __SSE__\nextern __m64 _ITM_CALL_CONVENTION _ITM_RM64( const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaRM64( const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaWM64( const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RfWM64( const __m64 *);\n\nextern __m128 _ITM_CALL_CONVENTION _ITM_RM128( const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaRM128( const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaWM128( const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RfWM128( const __m128 *);\n#endif /* __SSE__ */\n\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RCF( const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaRCF( const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaWCF( const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RfWCF( const float _Complex *);\n\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RCD( const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaRCD( const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaWCD( const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RfWCD( const double _Complex *);\n\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RCE( const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaRCE( const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaWCE( const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RfWCE( const long double _Complex *);\n\n\n/*** Stores ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_WU1( const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU1( const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU1( const uint8_t *, uint8_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU2( const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU2( const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU2( const uint16_t *, uint16_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU4( const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU4( const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU4( const uint32_t *, uint32_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU8( const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU8( const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU8( const uint64_t *, uint64_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WF( const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaRF( const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaWF( const float *, float);\n\nextern void _ITM_CALL_CONVENTION _ITM_WD( const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaRD( const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaWD( const double *, double);\n\n#ifdef __SSE__\nextern void _ITM_CALL_CONVENTION _ITM_WM64( const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM64( const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM64( const __m64 *, __m64);\n\nextern void _ITM_CALL_CONVENTION _ITM_WM128( const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM128( const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM128( const __m128 *, __m128);\n#endif /* __SSE__ */\n\nextern void _ITM_CALL_CONVENTION _ITM_WCF( const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCF( const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCF( const float _Complex *, float _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCD( const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCD( const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCD( const double _Complex *, double _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCE( const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCE( const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCE( const long double _Complex *, long double _Complex);\n\n\n/*** Logging functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_LU1( const uint8_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU2( const uint16_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU4( const uint32_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU8( const uint64_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LF( const float *);\nextern void _ITM_CALL_CONVENTION _ITM_LD( const double *);\nextern void _ITM_CALL_CONVENTION _ITM_LE( const long double *);\nextern void _ITM_CALL_CONVENTION _ITM_LM64( const __m64 *);\nextern void _ITM_CALL_CONVENTION _ITM_LM128( const __m128 *);\nextern void _ITM_CALL_CONVENTION _ITM_LCF( const float _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCD( const double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCE( const long double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LB( const void *, size_t);\n\n\n/*** memcpy functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaW( void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWn( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWn( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWn( void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaW( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaW( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaW( void *, const void *, size_t);\n\n\n/*** memset functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memsetW( void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaR( void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaW( void *, int, size_t);\n\n\n/*** memmove functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaW( void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWn( void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWn( void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWn( void *, const void *, size_t); \n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaW( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaW( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWt( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaR( void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaW( void *, const void *, size_t);\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif /* __cplusplus */\n\n#endif /* _LIBITM_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/libtanger-stm.public-symbols",
    "content": "main\nGTM_begin_transaction\n\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/libtanger-stm.support",
    "content": ",1\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/tanger-stm-internal.h",
    "content": "/* Copyright (C) 2007-2009  Torvald Riegel\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n */\n/**\n * Internal STM interface. Contains the interface that an STM has to implement\n * for Tanger. The part of the interface that is visible in the application is\n * in tanger-stm.h.\n */\n#ifndef TANGERSTMINTERNAL_H_\n#define TANGERSTMINTERNAL_H_\n\n#include <stdint.h>\n#include <stddef.h>\n#include <stdbool.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** A transaction descriptor/handle/... */\ntypedef void tanger_stm_tx_t;\n\n#ifndef TANGER_LOADSTORE_ATTR\n/* FIXME: LLVM seems to have a bug when inlining these functions. Check if fixed with newer version. */\n//#define TANGER_LOADSTORE_ATTR __attribute__((nothrow,always_inline))\n#define TANGER_LOADSTORE_ATTR __attribute__((nothrow,noinline))\n#endif\n\n#if defined(__i386__)\n/* XXX This is not supported by LLVM yet. */\n#define ITM_REGPARM __attribute__((regparm(2)))\n#else\n#define ITM_REGPARM\n#endif\n\n/* Load and store functions access a certain number of bits.\n * 1b loads/stores are currently assumed to actually go to full 8 bits.\n * Addresses being accessed are not necessarily aligned (e.g., a 16b load\n * might target memory address 1). If it is known at compile time that the\n * access is aligned, then different functions are called.\n */\nuint8_t tanger_stm_load1(tanger_stm_tx_t* tx, uint8_t *addr) TANGER_LOADSTORE_ATTR;\nuint8_t tanger_stm_load8(tanger_stm_tx_t* tx, uint8_t *addr) TANGER_LOADSTORE_ATTR;\nuint16_t tanger_stm_load16(tanger_stm_tx_t* tx, uint16_t *addr) TANGER_LOADSTORE_ATTR;\nuint32_t tanger_stm_load32(tanger_stm_tx_t* tx, uint32_t *addr) TANGER_LOADSTORE_ATTR;\nuint64_t tanger_stm_load64(tanger_stm_tx_t* tx, uint64_t *addr) TANGER_LOADSTORE_ATTR;\nuint16_t tanger_stm_load16aligned(tanger_stm_tx_t* tx, uint16_t *addr) TANGER_LOADSTORE_ATTR;\nuint32_t tanger_stm_load32aligned(tanger_stm_tx_t* tx, uint32_t *addr) TANGER_LOADSTORE_ATTR;\nuint64_t tanger_stm_load64aligned(tanger_stm_tx_t* tx, uint64_t *addr) TANGER_LOADSTORE_ATTR;\n\n/** Loads a number of bytes from src and copies them to dest\n * src is shared data, dest must point to thread-private data */\nvoid tanger_stm_loadregion(tanger_stm_tx_t* tx, uint8_t *src, uintptr_t bytes, uint8_t *dest);\n/** Starts reading a number of bytes from addr.\n * Mostly useful for creating wrappers for library functions. Use with care!\n * The function returns an address that you can read the data from. Depending\n * on the STM algorithm, it might be different from addr or not.\n * You must call tanger_stm_loadregionpost after calling this function.\n * You must not call any other STM function between the pre and post calls.\n * Data read from addr between the two calls is not guaranteed to be a\n * consistent snapshot. */\nvoid* tanger_stm_loadregionpre(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes);\n/** See tanger_stm_loadregionpre */\nvoid tanger_stm_loadregionpost(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes);\n/** This is like tanger_stm_loadregionpre() except that it assumes that addr\n * points to a zero-terminated string and thus reads all bytes up to and\n * including the final zero. It returns the size of the string (including the\n * terminating zero) in bytes. The size is guaranteed to be derived from a\n * consistent snapshot. If you read the strings' contents, you must call\n * tanger_stm_loadregionpost() afterwards.\n */\nvoid* tanger_stm_loadregionstring(tanger_stm_tx_t* tx, char *addr, uintptr_t *bytes);\n\nvoid tanger_stm_store1(tanger_stm_tx_t* tx, uint8_t *addr, uint8_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store8(tanger_stm_tx_t* tx, uint8_t *addr, uint8_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store16(tanger_stm_tx_t* tx, uint16_t *addr, uint16_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store32(tanger_stm_tx_t* tx, uint32_t *addr, uint32_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store64(tanger_stm_tx_t* tx, uint64_t *addr, uint64_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store16aligned(tanger_stm_tx_t* tx, uint16_t *addr, uint16_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store32aligned(tanger_stm_tx_t* tx, uint32_t *addr, uint32_t value) TANGER_LOADSTORE_ATTR;\nvoid tanger_stm_store64aligned(tanger_stm_tx_t* tx, uint64_t *addr, uint64_t value) TANGER_LOADSTORE_ATTR;\n/** Reads a number of bytes from src and writes them to dest\n * dest is shared data, src must point to thread-private data */\nvoid tanger_stm_storeregion(tanger_stm_tx_t* tx, uint8_t *src, uintptr_t bytes, uint8_t *dest);\n/** Prepares writing a number of bytes to addr.\n * The function returns an address that you can write the data to. Depending\n * on the STM algorithm, it might be different from addr or not.\n * The memory starting at addr does not necessarily contain a consistent\n * snapshot or the data previously located at this memory region. */\nvoid* tanger_stm_storeregionpre(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes);\n/** Prepares updating a number of bytes starting at addr.\n * The function returns an address that you can write the data to. Depending\n * on the STM algorithm, it might be different from addr or not.\n * The memory starting at the returned address will contain a consistent\n * snapshot of the previous values of the region. */\nvoid* tanger_stm_updateregionpre(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes);\n\n\n/**\n * Returns the calling thread's transaction descriptor.\n * ABI note: Remove this once we have efficient TLS.\n */\ntanger_stm_tx_t* tanger_stm_get_tx(void);\n\n/**\n * Saves or restores the stack, depending on whether the current txn was\n * started or restarted. The STM will save/restore everything in the range\n * [low_addr, high_addr). The STM's implementation of this function must be\n * marked as no-inline, so it will get a new stack frame that does not\n * overlap the [low_addr, high_addr) region.\n * To avoid corrupting stack space of rollback functions, the STM should skip\n * undoing changes to addresses that are between the current stack pointer\n * during execution of the undo function and the [low_addr, high_addr)\n * area (i.e., all newer stack frames, including the current one).\n */\nvoid tanger_stm_save_restore_stack(void* low_addr, void* high_addr);\n\n/**\n * Replacement function for malloc calls in transactions.\n */\nvoid *tanger_stm_malloc(size_t size);\n\n/**\n * Replacement function for free calls in transactions.\n */\nvoid tanger_stm_free(void *ptr);\n\n/**\n * Replacement function for calloc calls in transactions.\n */\nvoid *tanger_stm_calloc(size_t nmemb, size_t size);\n\n/**\n * Replacement function for realloc calls in transactions.\n */\nvoid *tanger_stm_realloc(void *ptr, size_t size);\n\n/**\n * Returns the transactional version of the function passed as argument.\n * If no transactional version has been registered, it aborts.\n */\nvoid* tanger_stm_indirect_resolve(void *nontxnal_function);\n\n/**\n * Called before transactional versions are registered for nontransactional\n * functions.\n * The parameter returns the exact number of functions that will be registered.\n */\nvoid tanger_stm_indirect_init(uint32_t number_of_call_targets);\n\n/**\n * Registers a transactional versions for a nontransactional function.\n */\nvoid tanger_stm_indirect_register(void* nontxnal, void* txnal);\n\n/* ABI: Additionnal declarations */\nvoid tanger_stm_stack_restorehack();\nvoid tanger_stm_stack_savehack();\n//void tanger_stm_threadstack_init();\n//void tanger_stm_threadstack_fini();\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*TANGERSTMINTERNAL_H_*/\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/tanger.c",
    "content": "/*\n * File:\n *   tanger.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Tanger adapter for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/* This file is designed to work with DTMC (Tanger/LLVM).\n * DTMC is not 100% compatible with Intel ABI yet thus this file \n * permits to propose a workaround.\n */\n\n#define _GNU_SOURCE\n#include <assert.h>\n#include <string.h>\n#include <pthread.h>\n#include <bits/wordsize.h>\n\n/* A transaction descriptor/handle/... */\n//typedef void tanger_stm_tx_t;\n\n#ifndef TANGER_LOADSTORE_ATTR\n/* FIXME: LLVM seems to have a bug when inlining these functions. Check if fixed with newer version. */\n//# define TANGER_LOADSTORE_ATTR __attribute__((nothrow,always_inline))\n# define TANGER_LOADSTORE_ATTR __attribute__((nothrow,noinline))\n#endif /* TANGER_LOADSTORE_ATTR */\n\n#define TM_LOAD    stm_load\n#define TM_STORE   stm_store\n\n/* TODO manage properly TLS but llvm-gcc should do */\n__thread appstack_t appstack;\n\n/* ################################################################### *\n * TANGER FUNCTIONS\n * ################################################################### */\n\n#ifdef EXPLICIT_TX_PARAMETER\n# define TX_PARAM (struct stm_tx *)tx,\n#else\n# define TX_PARAM\n#endif\n\nTANGER_LOADSTORE_ATTR\nuint8_t tanger_stm_load1(tanger_stm_tx_t *tx, uint8_t *addr)\n{\n#ifdef STACK_CHECK\n  /* TODO add unlikely */\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n  return stm_load_u8(TX_PARAM addr);\n}\n\nTANGER_LOADSTORE_ATTR\nuint8_t tanger_stm_load8(tanger_stm_tx_t *tx, uint8_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n  return stm_load_u8(TX_PARAM addr);\n}\n\nTANGER_LOADSTORE_ATTR\nuint16_t tanger_stm_load16(tanger_stm_tx_t *tx, uint16_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n  return stm_load_u16(TX_PARAM addr);\n}\n\nTANGER_LOADSTORE_ATTR\nuint32_t tanger_stm_load32(tanger_stm_tx_t *tx, uint32_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n  return stm_load_u32(TX_PARAM addr);\n}\n\nTANGER_LOADSTORE_ATTR\nuint64_t tanger_stm_load64(tanger_stm_tx_t *tx, uint64_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n  return stm_load_u64(TX_PARAM addr);\n}\n\nTANGER_LOADSTORE_ATTR\nuint16_t tanger_stm_load16aligned(tanger_stm_tx_t *tx, uint16_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n  return stm_load_u16(TX_PARAM addr);\n}\n\nTANGER_LOADSTORE_ATTR\nuint32_t tanger_stm_load32aligned(tanger_stm_tx_t *tx, uint32_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n#if __WORDSIZE == 32\n  return (uint32_t)TM_LOAD(TX_PARAM (volatile stm_word_t *)addr);\n#else\n  return stm_load_u32(TX_PARAM addr);\n#endif\n}\n\nTANGER_LOADSTORE_ATTR\nuint64_t tanger_stm_load64aligned(tanger_stm_tx_t *tx, uint64_t *addr)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr))\n    return *addr;\n#endif /* STACK_CHECK */\n#if __WORDSIZE == 64\n  return (uint64_t)TM_LOAD(TX_PARAM (volatile stm_word_t *)addr);\n#else \n  return stm_load_u64(TX_PARAM addr);\n#endif \n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_loadregion(tanger_stm_tx_t* tx, uint8_t *src, uintptr_t bytes, uint8_t *dest)\n{\n#ifdef STACK_CHECK\n  if (on_stack(src))\n    memcpy(dest, src, bytes);\n#endif /* STACK_CHECK */\n  stm_load_bytes(TX_PARAM src, dest, bytes);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid* tanger_stm_loadregionpre(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes)\n{\n  fprintf(stderr, \"%s: not yet implemented\\n\", __func__);\n  return NULL;\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_loadregionpost(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes)\n{\n  fprintf(stderr, \"%s: not yet implemented\\n\", __func__);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store1(tanger_stm_tx_t *tx, uint8_t *addr, uint8_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_u8(TX_PARAM addr, value);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store8(tanger_stm_tx_t *tx, uint8_t *addr, uint8_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_u8(TX_PARAM addr, value);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store16(tanger_stm_tx_t *tx, uint16_t *addr, uint16_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_u16(TX_PARAM addr, value);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store32(tanger_stm_tx_t *tx, uint32_t *addr, uint32_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_u32(TX_PARAM addr, value);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store64(tanger_stm_tx_t *tx, uint64_t *addr, uint64_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_u64(TX_PARAM addr, value);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store16aligned(tanger_stm_tx_t *tx, uint16_t *addr, uint16_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_u16(TX_PARAM addr, value);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store32aligned(tanger_stm_tx_t *tx, uint32_t *addr, uint32_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n#if __WORDSIZE == 32\n  TM_STORE(TX_PARAM (volatile stm_word_t *)addr, (stm_word_t)value);\n#else\n  stm_store_u32(TX_PARAM addr, value);\n#endif\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_store64aligned(tanger_stm_tx_t *tx, uint64_t *addr, uint64_t value)\n{\n#ifdef STACK_CHECK\n  if (on_stack(addr)) {\n    *addr = value;\n    return;\n  }\n#endif /* STACK_CHECK */\n#if __WORD_SIZE == 64\n  TM_STORE(TX_PARAM (volatile stm_word_t *)addr, (stm_word_t)value);\n#else\n  stm_store_u64(TX_PARAM addr, value);\n#endif\n}\n\nTANGER_LOADSTORE_ATTR\nvoid tanger_stm_storeregion(tanger_stm_tx_t* tx, uint8_t *src, uintptr_t bytes, uint8_t *dest)\n{\n#ifdef STACK_CHECK\n  if (on_stack(dest)) {\n    memcpy(dest, src, bytes);\n    return;\n  }\n#endif /* STACK_CHECK */\n  stm_store_bytes(TX_PARAM src, dest, bytes);\n}\n\nTANGER_LOADSTORE_ATTR\nvoid* tanger_stm_storeregionpre(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes)\n{\n  fprintf(stderr, \"%s: not yet implemented\\n\", __func__);\n  return NULL;\n}\n\nTANGER_LOADSTORE_ATTR\nvoid* tanger_stm_updateregionpre(tanger_stm_tx_t* tx, uint8_t *addr, uintptr_t bytes)\n{\n  fprintf(stderr, \"%s: not yet implemented\\n\", __func__);\n  return NULL;\n}\n\ntanger_stm_tx_t *tanger_stm_get_tx()\n{\n  struct stm_tx *tx = stm_current_tx();\n  if (unlikely(tx == NULL)) {\n    /* Thread not initialized: must create transaction */\n    _ITM_initializeThread();\n    tx = stm_current_tx();\n  }\n\n  return (tanger_stm_tx_t *)tx;\n}\n\n\n/* TODO manage nesting */\nvoid tanger_stm_save_restore_stack(void* low_addr, void* high_addr) __attribute__((noinline));\nvoid tanger_stm_save_restore_stack(void* low_addr, void* high_addr)\n{\n  /* Saving stack info and backup the stack in beginTransaction because LLVM\n   *  can add code between this function and beginTransaction. */\n  appstack.stack_addr = low_addr;\n  appstack.stack_size = (size_t)high_addr - (size_t)low_addr;\n}\n\nvoid tanger_stm_init()\n{\n  _ITM_initializeProcess();\n}\n\nvoid tanger_stm_shutdown()\n{\n  _ITM_finalizeProcess();\n}\n\nvoid tanger_stm_thread_init()\n{\n  _ITM_initializeThread();\n}\n\nvoid tanger_stm_thread_shutdown()\n{\n  _ITM_finalizeThread();\n}\n\n/* TODO check if ok */\n//void *tanger_stm_malloc(size_t size, tanger_stm_tx_t* tx)\nvoid *tanger_stm_malloc(size_t size)\n{\n  return _ITM_malloc(size);\n}\n\nvoid tanger_stm_free(void *ptr)\n{\n  _ITM_free(ptr);\n}\n\nvoid *tanger_stm_calloc(size_t nmemb, size_t size)\n{\n  void *p = _ITM_malloc(nmemb * size);\n  memset(p, 0, nmemb * size);\n  return p;\n}\n\nvoid *tanger_stm_realloc(void *ptr, size_t size)\n{\n  /* TODO to ITM_imize */\n  void *p;\n#ifdef EXPLICIT_TX_PARAMETER\n  struct stm_tx * tx = stm_current_tx();\n#endif /* EXPLICIT_TX_PARAMETER */\n  if (ptr == NULL) {\n    /* Equivalent to malloc */\n    return tanger_stm_malloc(size);\n  }\n  if (size == 0) {\n    /* Equivalent to free */\n    tanger_stm_free(ptr);\n    return NULL;\n  }\n  /* Allocate new region */\n  p = tanger_stm_malloc(size);\n  /* Copy old content to new region */\n  stm_load_bytes(TX_PARAM ptr, p, malloc_usable_size(ptr));\n  /* Free old region */\n  tanger_stm_free(ptr);\n\n  return p;\n}\n\n/* Cleaning macros */\n#undef TM_LOAD\n#undef TM_STORE\n\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/tanger.h",
    "content": "/*\n * File:\n *   tanger.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Tanger adapter for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _TANGER_H_\n# define _TANGER_H_\n\ntypedef struct {\n  void *stack_addr;\n  size_t stack_size;\n  void *data;\n  size_t data_size;\n} appstack_t;\n\nextern __thread appstack_t appstack;\n\nstatic inline void tanger_stm_save_stack()\n{\n  // Is the data big enough?\n  if (appstack.stack_size > appstack.data_size) {\n    // TODO round to 4096+\n    appstack.data_size = appstack.stack_size;\n    appstack.data = realloc(appstack.data, appstack.data_size);\n  }\n  __builtin_memcpy(appstack.data, appstack.stack_addr, appstack.stack_size);\n}\n\nstatic inline void tanger_stm_restore_stack()\n{\n  __builtin_memcpy(appstack.stack_addr, appstack.data, appstack.stack_size);\n}\n\nstatic inline void tanger_stm_reset_stack()\n{\n  appstack.stack_addr = NULL;\n}\n\nstatic inline void tanger_stm_free_stack()\n{\n  if (appstack.data) {\n    free(appstack.data);\n    appstack.data = NULL;\n  }\n}\n\n#endif /* _TANGER_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/dtmc/tm_macros.h",
    "content": "/*\n * File:\n *   tm_macros.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Defines macros for transactional operations.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _TM_MACROS_H_\n# define _TM_MACROS_H_\n\n# define TM_START(id,ro)                    __tm_atomic {\n# define TM_LOAD(x)                         *x\n# define TM_STORE(x,y)                      *x=y\n# define TM_COMMIT                          }\n# define TM_MALLOC(size)                    malloc(size)\n# define TM_FREE(addr)                      free(addr)\n# define TM_FREE2(addr, size)               free(addr)\n\n# define TM_INIT\n# define TM_EXIT\n# define TM_INIT_THREAD\n# define TM_EXIT_THREAD\n\n/* Define Annotations */\n# define TM_PURE                            __attribute__((tm_pure))\n# define TM_SAFE                            __attribute__((tm_callable))\n\n/* FIXME to be removed when DTMC will support annotations */\nstatic double tanger_wrapperpure_erand48(unsigned short int __xsubi[3]) __attribute__ ((weakref(\"erand48\")));\n\n#endif /* _TM_MACROS_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/Makefile",
    "content": "# Path to TinySTM\nROOT = ../..\n\n.PHONY:\tgcc all clean check test\n\nall:\tgcc\n\n# ROOT must be defined to include Makefile.common\ninclude $(ROOT)/abi/Makefile.common\n\n\n##############################################################################\n## GCC\n##############################################################################\nCPPFLAGS += -DTM_GCC -I.\nINCLUDES += $(wildcard ../../src/*.h)\n\n# NOTES\n#   lib.map enables to export only some functions\ngcc: \tlibitm.so libitm.a \n\narch.o: arch.S\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.do: \t../%.c $(INCLUDES)\n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.o: \t../%.c $(INCLUDES)\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.s: \t../%.c \n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -fverbose-asm -S -o $@ $<\n\nlibitm.a: abi.o arch.o \n\t$(AR) cru $@ $^\n\nlibitm.so: \tabi.do arch.o \n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) -shared -Wl,--version-script,../lib.map -o $@ $^\n# TODO Check if strip is really needed\n#\tstrip $@\n#\tcp libitm.so libitm.so.1\n#\tln -s libitm.so libitm.so.1\n#TODO for FAT filesystem, ln doesn't work\n##############################################################################\n\nTESTCC       ?= $(CC)\nTESTCFLAGS   += $(CPPFLAGS) $(CFLAGS) -DTM_GCC -fgnu-tm\nTESTLD       ?= $(LD)\nTESTLDFLAGS  += -Wl,-rpath=$(shell pwd)\nTESTLDFLAGS  += -L$(ROOT)/abi/gcc \nTESTLDFLAGS  += -static -litm\n\nclean: \tintset-clean\n\trm -f *.o *.do libitm.a libitm.so\n\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/alloc_cpp.c",
    "content": "/*\n * File:\n *   alloc_cpp.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for C++ dynamic memory management.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"stm.h\"\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef struct mod_alloc_block {          /* Block of allocated memory */\n  void *addr;                             /* Address of memory */\n  void (*rev_func)(void*);                /* Undo/Defered function */\n  struct mod_alloc_block *next;           /* Next block */\n} mod_alloc_block_t;\n\ntypedef struct mod_alloc_info {           /* Memory descriptor */\n  mod_alloc_block_t *allocated;           /* Memory allocated by this transation (freed upon abort) */\n  mod_alloc_block_t *freed;               /* Memory freed by this transation (freed upon commit) */\n} mod_alloc_info_t;\n\nstatic int mod_alloc_key;\nstatic int mod_alloc_initialized = 0;\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/* TODO this is only true on linux amd64/ia32 */\n#ifdef __LP64__\n# define CREATENAME(A,B) A##m##B\n#else /* ! __LP64__ */\n# define CREATENAME(A,B) A##j##B\n#endif /* ! __LP64__ */\n\n\ntypedef const struct nothrow_t { } *c_nothrow_p;\nextern void *CREATENAME(_Znw,) (size_t) __attribute__((weak));\nextern void *CREATENAME(_Zna,) (size_t) __attribute__((weak));\nextern void *CREATENAME(_Znw,RKSt9nothrow_t) (size_t, c_nothrow_p) __attribute__((weak));\nextern void *CREATENAME(_Zna,RKSt9nothrow_t) (size_t, c_nothrow_p) __attribute__((weak));\n\nextern void _ZdlPv (void *) __attribute__((weak));\nextern void _ZdaPv (void *) __attribute__((weak));\nextern void _ZdlPvRKSt9nothrow_t (void *, c_nothrow_p) __attribute__((weak));\nextern void _ZdaPvRKSt9nothrow_t (void *, c_nothrow_p) __attribute__((weak));\n\nstatic void mod_alloc_record(void *ptr, void (*rev_func)(void*))\n{\n  /* Memory will be freed upon abort */\n  mod_alloc_info_t *mi;\n  mod_alloc_block_t *mb;\n\n  if (!mod_alloc_initialized) {\n    fprintf(stderr, \"Module mod_alloc not initialized\\n\");\n    exit(1);\n  }\n\n  mi = (mod_alloc_info_t *)stm_get_specific(mod_alloc_key);\n  assert(mi != NULL);\n\n  if ((mb = (mod_alloc_block_t *)malloc(sizeof(mod_alloc_block_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mb->addr = ptr;\n  mb->rev_func = rev_func;\n  mb->next = mi->allocated;\n  mi->allocated = mb;\n}\n\nstatic void mod_free_record(void *addr, void (*rev_func)(void*))\n{\n  /* Memory disposal is delayed until commit */\n  mod_alloc_info_t *mi;\n  mod_alloc_block_t *mb;\n\n  if (!mod_alloc_initialized) {\n    fprintf(stderr, \"Module mod_alloc not mod_alloc_initialized\\n\");\n    exit(1);\n  }\n\n  mi = (mod_alloc_info_t *)stm_get_specific(mod_alloc_key);\n  assert(mi != NULL);\n\n  /* Overwrite to prevent inconsistent reads */\n  /* TODO delete operators doesn't give the allocated size */\n  /* Acquire lock and update version number */\n  stm_store2(addr, 0, 0);\n  /* Schedule for removal */\n  if ((mb = (mod_alloc_block_t *)malloc(sizeof(mod_alloc_block_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mb->addr = addr;\n  mb->rev_func = rev_func;\n  mb->next = mi->freed;\n  mi->freed = mb;\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void mod_alloc_on_thread_init(void *arg)\n{\n  mod_alloc_info_t *mi;\n\n  if ((mi = (mod_alloc_info_t *)malloc(sizeof(mod_alloc_info_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  mi->allocated = mi->freed = NULL;\n\n  stm_set_specific(mod_alloc_key, mi);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void mod_alloc_on_thread_exit(void *arg)\n{\n  free(stm_get_specific(mod_alloc_key));\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void mod_alloc_on_commit(void *arg)\n{\n  mod_alloc_info_t *mi;\n  mod_alloc_block_t *mb, *next;\n\n  mi = (mod_alloc_info_t *)stm_get_specific(mod_alloc_key);\n  assert(mi != NULL);\n\n  /* Keep memory allocated during transaction */\n  if (mi->allocated != NULL) {\n    mb = mi->allocated;\n    while (mb != NULL) {\n      next = mb->next;\n      free(mb);\n      mb = next;\n    }\n    mi->allocated = NULL;\n  }\n\n  /* Dispose of memory freed during transaction */\n  if (mi->freed != NULL) {\n    mb = mi->freed;\n    while (mb != NULL) {\n      next = mb->next;\n      mb->rev_func(mb->addr);\n      free(mb);\n      mb = next;\n    }\n    mi->freed = NULL;\n  }\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void mod_alloc_on_abort(void *arg)\n{\n  mod_alloc_info_t *mi;\n  mod_alloc_block_t *mb, *next;\n\n  mi = (mod_alloc_info_t *)stm_get_specific(mod_alloc_key);\n  assert (mi != NULL);\n\n  /* Dispose of memory allocated during transaction */\n  if (mi->allocated != NULL) {\n    mb = mi->allocated;\n    while (mb != NULL) {\n      next = mb->next;\n      mb->rev_func(mb->addr);\n      free(mb);\n      mb = next;\n    }\n    mi->allocated = NULL;\n  }\n\n  /* Keep memory freed during transaction */\n  if (mi->freed != NULL) {\n    mb = mi->freed;\n    while (mb != NULL) {\n      next = mb->next;\n      free(mb);\n      mb = next;\n    }\n    mi->freed = NULL;\n  }\n}\n\n/* New operators */\n\nvoid *CREATENAME(_ZGTtnw,) (size_t sz)\n{\n  void *alloc;\n  alloc = CREATENAME(_Znw,)(sz);\n  mod_alloc_record(alloc, _ZdlPv);\n  return alloc;\n}\n\nvoid *CREATENAME(_ZGTtna,) (size_t sz)\n{\n  void *alloc;\n  alloc = CREATENAME(_Zna,)(sz);\n  mod_alloc_record(alloc, _ZdaPv);\n  return alloc;\n}\n\nstatic void _ZdlPvRKSt9nothrow_t1(void *ptr)\n{ \n  _ZdlPvRKSt9nothrow_t (ptr, NULL);\n}\n\nvoid *CREATENAME(_ZGTtnw,RKSt9nothrow_t) (size_t sz, c_nothrow_p nt)\n{\n  void *alloc;\n  alloc = CREATENAME(_Znw,RKSt9nothrow_t)(sz, nt);\n  mod_alloc_record(alloc, _ZdlPvRKSt9nothrow_t1);\n  return alloc;\n}\n\nstatic void _ZdaPvRKSt9nothrow_t1(void *ptr)\n{\n  _ZdaPvRKSt9nothrow_t(ptr, NULL);\n}\n\nvoid *CREATENAME(_ZGTtna,RKSt9nothrow_t)(size_t sz, c_nothrow_p nt)\n{\n  void *alloc;\n  alloc = CREATENAME(_Zna,RKSt9nothrow_t)(sz, nt);\n  mod_alloc_record(alloc, _ZdaPvRKSt9nothrow_t1);\n  return alloc;\n}\n\n/* Delete operators */\n\nvoid\n_ZGTtdlPv (void *ptr)\n{\n  mod_free_record(ptr, _ZdlPv);\n}\n\nvoid\n_ZGTtdlPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt)\n{ \n  mod_free_record(ptr, _ZdlPvRKSt9nothrow_t1);\n}\n\nvoid _ZGTtdaPv(void *ptr)\n{\n  mod_free_record(ptr, _ZdaPv);\n}\n\nvoid\n_ZGTtdaPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt)\n{\n  mod_free_record(ptr, _ZdaPvRKSt9nothrow_t1);\n}\n\n/*\n * Initialize module.\n */\nvoid mod_alloc_cpp()\n{\n  if (mod_alloc_initialized)\n    return;\n\n  stm_register(mod_alloc_on_thread_init, mod_alloc_on_thread_exit, NULL, NULL, mod_alloc_on_commit, mod_alloc_on_abort, NULL);\n  mod_alloc_key = stm_create_specific();\n  if (mod_alloc_key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  mod_alloc_initialized = 1;\n}\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/arch.S",
    "content": "#ifndef __linux__\n/* Linux specific, Windows uses a different calling convention. */\n/* TODO probably solaris is fine with it. */\n# error This file is linux specific.\n#endif\n\n\t.text\n\n#if defined(__x86_64__)\n\t.align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n\n_ITM_beginTransaction:\n\t.cfi_startproc\n/* Paramters (in order) is in rdi, rsi, rdx, rcx, r8, r9 */\n/* Temporary registers is r10, r11 (not saved) */\n/* To be saved are rbx, rsp, rbp, r12, r13, r14, r15 */\n\tleaq\t8(%rsp), %rax    /* Save stack pointer */\n\tsubq\t$56, %rsp\n\t.cfi_def_cfa_offset 64\n\tmovq\t%rax, (%rsp)\n\tmovq\t%rbx, 8(%rsp)\n\tmovq\t%rbp, 16(%rsp)\n\tmovq\t%r12, 24(%rsp)\n\tmovq\t%r13, 32(%rsp)\n\tmovq\t%r14, 40(%rsp)\n\tmovq\t%r15, 48(%rsp)\n\tmovq\t%rsp, %rsi\n\tcall\tGTM_begin_transaction\n\taddq\t$56, %rsp\n\t.cfi_def_cfa_offset 8\n\tret\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovq\t(%rsi), %rcx\n\tmovq\t8(%rsi), %rbx\n\tmovq\t16(%rsi), %rbp\n\tmovq\t24(%rsi), %r12\n\tmovq\t32(%rsi), %r13\n\tmovq\t40(%rsi), %r14\n\tmovq\t48(%rsi), %r15\n\tmovl\t%edi, %eax\n\t.cfi_def_cfa %rsi, 0\n\t.cfi_offset %rip, 56\n\t.cfi_register %rsp, %rcx\n\tmovq\t%rcx, %rsp\n\tjmp\t*56(%rsi)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__i386__)\n\t.align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n_ITM_beginTransaction:\n\t.cfi_startproc\n\tleal\t4(%esp), %ecx\n\tmovl\t4(%esp), %eax\n\tsubl\t$28, %esp\n\t.cfi_def_cfa_offset 32\n\tmovl\t%ecx, 8(%esp)\n\tmovl\t%ebx, 12(%esp)\n\tmovl\t%esi, 16(%esp)\n\tmovl\t%edi, 20(%esp)\n\tmovl\t%ebp, 24(%esp)\n\tleal\t8(%esp), %edx\n\tcall\tGTM_begin_transaction\n\taddl\t$28, %esp\n\t.cfi_def_cfa_offset 4\n\tret\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovl\t(%edx), %ecx\n\tmovl\t4(%edx), %ebx\n\tmovl\t8(%edx), %esi\n\tmovl\t12(%edx), %edi\n\tmovl\t16(%edx), %ebp\n\t.cfi_def_cfa %edx, 0\n\t.cfi_offset %eip, 20\n\t.cfi_register %esp, %ecx\n\tmovl\t%ecx, %esp\n\tjmp\t*20(%edx)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__sparc__)\n# error SPARC arch is not yet supported\n#else\n# error Unsupported architecture\n#endif\n\n#ifdef __linux__\n.section .note.GNU-stack, \"\", @progbits\n#endif\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/clone.c",
    "content": "/* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.\n   Contributed by Richard Henderson <rth@redhat.com>.\n\n   This file is part of the GNU Transactional Memory Library (libitm).\n\n   Libitm is free software; you can redistribute it and/or modify it\n   under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 3 of the License, or\n   (at your option) any later version.\n\n   Libitm is distributed in the hope that it will be useful, but WITHOUT ANY\n   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n   more details.\n\n   Under Section 7 of GPL version 3, you are granted additional\n   permissions described in the GCC Runtime Library Exception, version\n   3.1, as published by the Free Software Foundation.\n\n   You should have received a copy of the GNU General Public License and\n   a copy of the GCC Runtime Library Exception along with this program;\n   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see\n   <http://www.gnu.org/licenses/>.\n\n   This file was modified to allow compatibility with the GNU Transactional\n   Memory Library (libitm). */\n\n/* No include needed since the file is included */\n\nstruct clone_entry\n{\n  void *orig, *clone;\n};\n\nstruct clone_table\n{\n  struct clone_entry *table;\n  size_t size;\n  struct clone_table *next;\n};\n\nstatic struct clone_table *all_tables;\n\nstatic void *\nfind_clone (void *ptr)\n{\n  struct clone_table *table;\n\n  for (table = all_tables; table ; table = table->next)\n    {\n      struct clone_entry *t = table->table;\n      size_t lo = 0, hi = table->size, i;\n\n      /* Quick test for whether PTR is present in this table.  */\n      if (ptr < t[0].orig || ptr > t[hi - 1].orig)\n\tcontinue;\n\n      /* Otherwise binary search.  */\n      while (lo < hi)\n\t{\n\t  i = (lo + hi) / 2;\n\t  if (ptr < t[i].orig)\n\t    hi = i;\n\t  else if (ptr > t[i].orig)\n\t    lo = i + 1;\n\t  else\n\t    {\n\t      return t[i].clone;\n\t    }\n\t}\n\n      /* Given the quick test above, if we don't find the entry in\n\t this table then it doesn't exist.  */\n      break;\n    }\n  return NULL;\n}\n\n\nvoid * _ITM_CALL_CONVENTION\n_ITM_getTMCloneOrIrrevocable (void *ptr)\n{\n  // if the function (ptr) have a TM version, give the pointer to the TM function \n  // otherwise, set transaction to irrevocable mode\n  void *ret = find_clone (ptr);\n  if (ret)\n    return ret;\n\n  /* TODO Check we are in an active transaction */\n  //  if (stm_current_tx() != NULL && stm_is_active(tx))\n    /* GCC always use implicit transaction descriptor */\n    stm_set_irrevocable(1);\n\n  return ptr;\n}\n\nvoid * _ITM_CALL_CONVENTION\n_ITM_getTMCloneSafe (void *ptr)\n{\n  void *ret = find_clone(ptr);\n  if (ret == NULL) {\n    fprintf(stderr, \"libitm: cannot find clone for %p\\n\", ptr);\n    abort();\n  }\n  return ret;\n}\n\nstatic int\nclone_entry_compare (const void *a, const void *b)\n{\n  const struct clone_entry *aa = (const struct clone_entry *)a;\n  const struct clone_entry *bb = (const struct clone_entry *)b;\n\n  if (aa->orig < bb->orig)\n    return -1;\n  else if (aa->orig > bb->orig)\n    return 1;\n  else\n    return 0;\n}\n\nvoid\n_ITM_registerTMCloneTable (void *xent, size_t size)\n{\n  struct clone_entry *ent = (struct clone_entry *)(xent);\n  struct clone_table *old, *table;\n\n  table = (struct clone_table *) malloc (sizeof (struct clone_table));\n  table->table = ent;\n  table->size = size;\n\n  qsort (ent, size, sizeof (struct clone_entry), clone_entry_compare);\n\n  old = all_tables;\n  do\n    {\n      table->next = old;\n      /* TODO Change to use AtomicOps wrapper */\n      old = __sync_val_compare_and_swap (&all_tables, old, table);\n    }\n  while (old != table);\n}\n\nvoid\n_ITM_deregisterTMCloneTable (void *xent)\n{\n  struct clone_entry *ent = (struct clone_entry *)(xent);\n  struct clone_table **pprev = &all_tables;\n  struct clone_table *tab;\n\n  /* FIXME: we must make sure that no transaction is active at this point. */\n\n  for (pprev = &all_tables;\n       tab = *pprev, tab->table != ent;\n       pprev = &tab->next)\n    continue;\n  *pprev = tab->next;\n\n  free (tab);\n}\n\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/eh.c",
    "content": "/* Copyright (C) 2009, 2011, 2012 Free Software Foundation, Inc.\n   Contributed by Richard Henderson <rth@redhat.com>.\n\n   This file is part of the GNU Transactional Memory Library (libitm).\n\n   Libitm is free software; you can redistribute it and/or modify it\n   under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 3 of the License, or\n   (at your option) any later version.\n\n   Libitm is distributed in the hope that it will be useful, but WITHOUT ANY\n   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n   more details.\n\n   Under Section 7 of GPL version 3, you are granted additional\n   permissions described in the GCC Runtime Library Exception, version\n   3.1, as published by the Free Software Foundation.\n\n   You should have received a copy of the GNU General Public License and\n   a copy of the GCC Runtime Library Exception along with this program;\n   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see\n   <http://www.gnu.org/licenses/>.\n\n   This file was modified to allow compatibility with the GNU Transactional\n   Memory Library (libitm). */\n\n/* FIXME Exception support with GCC is not working. */\n\nextern void *__cxa_allocate_exception (size_t) __attribute__((weak));\nextern void __cxa_throw (void *, void *, void *) __attribute__((weak));\nextern void *__cxa_begin_catch (void *) __attribute__((weak));\nextern void *__cxa_end_catch (void) __attribute__((weak));\n/* TODO check if TM_ABI -> no problem of dependancy of gcc-tm  */\nextern void __cxa_tm_cleanup (void *, void *, unsigned int) __attribute__((weak));\n\n\nvoid *_ITM_cxa_allocate_exception (size_t size)\n{\n  void *r = __cxa_allocate_exception (size);\n  /*tx->cxa_unthrown = r;*/\n  return r;\n}\n\nvoid _ITM_cxa_throw (void *obj, void *tinfo, void *dest)\n{\n  /*tx->cxa_unthrown = NULL;*/\n  __cxa_throw (obj, tinfo, dest);\n}\n\nvoid *_ITM_cxa_begin_catch (void *exc_ptr)\n{\n  /*tx->cxa_catch_count++;*/\n  return __cxa_begin_catch (exc_ptr);\n}\n\nvoid _ITM_cxa_end_catch (void)\n{\n  /*tx->cxa_catch_count--;*/\n  __cxa_end_catch ();\n}\n\n/* On rollback */\n/*\n * TODO integrate this to completely makes work exception with GCC-TM\nvoid stm_revert_cpp_exceptions (void)\n{   \n  if (tx->cxa_unthrown || tx->cxa_catch_count) {\n    __cxa_tm_cleanup (tx->cxa_unthrown, tx->eh_in_flight,\n                      tx->cxa_catch_count);\n    tx->cxa_catch_count = 0;\n    tx->cxa_unthrown = NULL;\n    tx->eh_in_flight = NULL;\n  }\n  if (tx->eh_in_flight) {\n    _Unwind_DeleteException ((_Unwind_Exception *) tx->eh_in_flight);\n    tx->eh_in_flight = NULL;\n  }\n}\n\nin _ITM_commitTransactionEH\ntx->eh_in_flight = exc_ptr;\nin _ITM_beginTransaction (no nesting)\ntx->eh_in_flight = NULL;\n*/\n\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/libitm.h",
    "content": "/*\n * File:\n *   libitm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   ABI for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _LIBITM_H_\n#define _LIBITM_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#include <stdint.h>\n#include <stdbool.h>\n#ifdef __SSE__\n# include <xmmintrin.h>\n#endif\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n#define _ITM_VERSION_NO_STR \"1.0.4\"\n#define _ITM_VERSION_NO 104\n\n#if defined(__i386__)\n# define _ITM_CALL_CONVENTION __attribute__((regparm(2)))\n#else\n# define _ITM_CALL_CONVENTION\n#endif\n\n#define _ITM_noTransactionId 1\t\t/* Id for non-transactional code. */\n\n\n#define _ITM_TRANSACTION_PURE __attribute__((transaction_pure))\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef void *_ITM_transaction;\n\ntypedef void (*_ITM_userUndoFunction)(void *);\ntypedef void (*_ITM_userCommitFunction)(void *);\n\ntypedef uint32_t _ITM_transactionId;\n\ntypedef enum\n{\n  outsideTransaction = 0,\n  inRetryableTransaction,\n  inIrrevocableTransaction\n} _ITM_howExecuting;\n\nstruct _ITM_srcLocationS\n{\n  int32_t reserved_1;\n  int32_t flags;\n  int32_t reserved_2;\n  int32_t reserved_3;\n  const char *psource;\n};\n\ntypedef struct _ITM_srcLocationS _ITM_srcLocation;\n\ntypedef enum {\n  pr_instrumentedCode = 0x0001,\n  pr_uninstrumentedCode = 0x0002,\n  pr_multiwayCode = pr_instrumentedCode | pr_uninstrumentedCode,\n  pr_hasNoXMMUpdate = 0x0004,\n  pr_hasNoAbort = 0x0008,\n  pr_hasNoRetry = 0x0010,\n  pr_hasNoIrrevocable = 0x0020,\n  pr_doesGoIrrevocable = 0x0040,\n  pr_hasNoSimpleReads = 0x0080,\n  pr_aWBarriersOmitted = 0x0100,\n  pr_RaRBarriersOmitted = 0x0200,\n  pr_undoLogCode = 0x0400,\n  pr_preferUninstrumented = 0x0800,\n  pr_exceptionBlock = 0x1000,\n  pr_hasElse = 0x2000,\n  pr_readOnly = 0x4000 /* GNU gcc specific */\n} _ITM_codeProperties;\n\ntypedef enum {\n  a_runInstrumentedCode = 0x01,\n  a_runUninstrumentedCode = 0x02,\n  a_saveLiveVariables = 0x04,\n  a_restoreLiveVariables = 0x08,\n  a_abortTransaction = 0x10,\n} _ITM_actions;\n\ntypedef enum {\n  modeSerialIrrevocable,\n  modeObstinate,\n  modeOptimistic,\n  modePessimistic,\n} _ITM_transactionState;\n\ntypedef enum {\n  unknown = 0,\n  userAbort = 1,\n  userRetry = 2,\n  TMConflict= 4,\n  exceptionBlockAbort = 8\n} _ITM_abortReason;\n\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transaction * _ITM_CALL_CONVENTION _ITM_getTransaction(void);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_howExecuting _ITM_CALL_CONVENTION _ITM_inTransaction();\n\nextern _ITM_TRANSACTION_PURE\nint _ITM_CALL_CONVENTION _ITM_getThreadnum(void);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserCommitAction(\n                             _ITM_userCommitFunction __commit,\n                             _ITM_transactionId resumingTransactionId,\n                             void *__arg);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserUndoAction(\n                             const _ITM_userUndoFunction __undo, void * __arg);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transactionId _ITM_CALL_CONVENTION _ITM_getTransactionId();\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_dropReferences(\n                             const void *__start, size_t __size);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_userError(const char *errString, int exitCode);\n\nextern const char * _ITM_CALL_CONVENTION _ITM_libraryVersion(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_versionCompatible(int version);\n\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeProcess(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeProcess(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_error(const _ITM_srcLocation *__src,\n                             int errorCode);\n\nextern uint32_t _ITM_beginTransaction(uint32_t __properties, ...)\n                             __attribute__((returns_twice));\nextern void _ITM_CALL_CONVENTION _ITM_commitTransaction(void);\n\n\n\nextern bool _ITM_CALL_CONVENTION _ITM_tryCommitTransaction(\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransactionToId(\n                             const _ITM_transactionId tid,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_abortTransaction(\n                             _ITM_abortReason __reason,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_rollbackTransaction(\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_registerThrownObject(\n                             const void *__obj,\n                             size_t __size);\n\nextern void _ITM_CALL_CONVENTION _ITM_changeTransactionMode(\n                             _ITM_transactionState __mode,\n                             const _ITM_srcLocation *__loc);\n\n/**** GCC Specific ****/\nextern _ITM_CALL_CONVENTION void *_ITM_getTMCloneOrIrrevocable(void *);\nextern _ITM_CALL_CONVENTION void *_ITM_getTMCloneSafe(void *);\nextern void _ITM_registerTMCloneTable(void *, size_t);\nextern void _ITM_deregisterTMCloneTable(void *);\nextern _ITM_CALL_CONVENTION void _ITM_commitTransactionEH(void *);\n\nextern void * _ITM_malloc(size_t);\nextern void * _ITM_calloc(size_t, size_t);\nextern void _ITM_free(void *);\n\n/*** Loads ***/\n\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RU1(const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaRU1(const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaWU1(const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RfWU1(const uint8_t *);\n\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RU2(const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaRU2(const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaWU2(const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RfWU2(const uint16_t *);\n\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RU4(const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaRU4(const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaWU4(const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RfWU4(const uint32_t *);\n\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RU8(const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaRU8(const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaWU8(const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RfWU8(const uint64_t *);\n\nextern float _ITM_CALL_CONVENTION _ITM_RF(const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaRF(const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaWF(const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RfWF(const float *);\n\nextern double _ITM_CALL_CONVENTION _ITM_RD(const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaRD(const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaWD(const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RfWD(const double *);\n\n#ifdef __SSE__\nextern __m64 _ITM_CALL_CONVENTION _ITM_RM64(const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaRM64(const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaWM64(const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RfWM64(const __m64 *);\n\nextern __m128 _ITM_CALL_CONVENTION _ITM_RM128(const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaRM128(const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaWM128(const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RfWM128(const __m128 *);\n#endif /* __SSE__ */\n\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RCF(const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaRCF(const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaWCF(const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RfWCF(const float _Complex *);\n\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RCD(const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaRCD(const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaWCD(const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RfWCD(const double _Complex *);\n\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RCE(const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaRCE(const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaWCE(const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RfWCE(const long double _Complex *);\n\n\n/*** Stores ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_WU1(const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU1(const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU1(const uint8_t *, uint8_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU2(const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU2(const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU2(const uint16_t *, uint16_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU4(const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU4(const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU4(const uint32_t *, uint32_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU8(const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU8(const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU8(const uint64_t *, uint64_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WF(const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaRF(const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaWF(const float *, float);\n\nextern void _ITM_CALL_CONVENTION _ITM_WD(const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaRD(const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaWD(const double *, double);\n\n#ifdef __SSE__\nextern void _ITM_CALL_CONVENTION _ITM_WM64(const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM64(const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM64(const __m64 *, __m64);\n\nextern void _ITM_CALL_CONVENTION _ITM_WM128(const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM128(const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM128(const __m128 *, __m128);\n#endif /* __SSE__ */\n\nextern void _ITM_CALL_CONVENTION _ITM_WCF(const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCF(const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCF(const float _Complex *, float _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCD(const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCD(const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCD(const double _Complex *, double _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCE(const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCE(const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCE(const long double _Complex *, long double _Complex);\n\n\n/*** Logging functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_LU1(const uint8_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU2(const uint16_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU4(const uint32_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU8(const uint64_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LF(const float *);\nextern void _ITM_CALL_CONVENTION _ITM_LD(const double *);\nextern void _ITM_CALL_CONVENTION _ITM_LE(const long double *);\nextern void _ITM_CALL_CONVENTION _ITM_LM64(const __m64 *);\nextern void _ITM_CALL_CONVENTION _ITM_LM128(const __m128 *);\nextern void _ITM_CALL_CONVENTION _ITM_LCF(const float _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCD(const double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCE(const long double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LB(const void *, size_t);\n\n\n/*** memcpy functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaW(void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWn(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWn(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWn(void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaW(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaW(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaW(void *, const void *, size_t);\n\n\n/*** memset functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memsetW(void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaR(void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaW(void *, int, size_t);\n\n\n/*** memmove functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaW(void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWn(void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWn(void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWn(void *, const void *, size_t); \n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaW(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaW(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWt(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaR(void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaW(void *, const void *, size_t);\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif /* __cplusplus */\n\n#endif /* _LIBITM_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/gcc/tm_macros.h",
    "content": "/*\n * File:\n *   tm_macros.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Defines macros for transactional operations.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n#ifndef _TM_MACROS_H_\n# define _TM_MACROS_H_\n\n# define TM_START(id,ro)                    __transaction_atomic {\n# define TM_LOAD(x)                         *x\n# define TM_STORE(x,y)                      *x=y\n# define TM_COMMIT                          }\n# define TM_MALLOC(size)                    malloc(size)\n// TODO is it possible to do TM_FREE(addr ...)  free(addr) ? //__VA_ARGS__\n# define TM_FREE(addr)                      free(addr)\n# define TM_FREE2(addr, size)               free(addr)\n\n# define TM_INIT\n# define TM_EXIT\n# define TM_INIT_THREAD\n# define TM_EXIT_THREAD\n\n/* Define Annotations */\n# define TM_PURE                            __attribute__((transaction_pure))\n# define TM_SAFE                            __attribute__((transaction_safe))\n\n#endif /* _TM_MACROS_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/intel/Makefile",
    "content": "# Path to tinySTM\nROOT = ../..\n\n.PHONY:\tintel all clean check test\n\nall:\tintel \n\n# ROOT must be defined to include Makefile.common\ninclude $(ROOT)/abi/Makefile.common\n\n\n##############################################################################\n## INTEL\n##############################################################################\nCPPFLAGS += -DTM_INTEL -I.\n\n# NOTES\n#   Intel STM Compiler uses explicit transaction descriptor\n#   Two ways to use:\n#   - Compile STM application using libitm.a\n#   - Compile STM application using Intel STM and change LD_LIBRARY_PATH to use tiny's libitmdyn.so\n# FIXME \n#   .so version need minor modification to stm_tx_t structure (add vtable at 0x10)\n# intel/libitmdyn.so\nintel: \tlibitm.a\n\n%.do: \t../%.c \n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.o: \t../%.c \n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n# TODO the dependency of arch_x86.S is not set\narch.o: \tarch.S\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<\n\nlibitm.a: \tabi.o arch.o alloc.o \n\t$(AR) cru $@ $^\n\n# TODO check the dynamic version (not really needed)\narch.do: \tarch.S\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<\n\nabi_dyn.o:\tabi.c\n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\nlibitmdyn.so: \tabi_dyn.o arch.do\n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) -shared -Wl,--version-script,../lib.map -o $@ $^ \n##############################################################################\n\nTESTCC          ?= icc\nTESTCFLAGS      += -Qtm_enabled -DTM_INTEL\n\nTESTLD          ?= icc\nTESTLDFLAGS     += -Qtm_enabled -litm -L. \n\nclean: \tintset-clean\n\trm -f *.o *.do libitm.a libitmdyn.so\n\n"
  },
  {
    "path": "stms/tinystm/abi/intel/alloc.c",
    "content": "#include <stdlib.h>\n#include \"mod_mem.h\"\n\n/* TODO make inline calls */\n\nvoid *malloc_txn(size_t size) __asm__(\"malloc._$TXN\");\nvoid *malloc_txn(size_t size)\n{\n  return stm_malloc(size);\n}\n\nvoid *malloc_wraptxn(size_t size) __asm__(\"malloc._$WrapTXN\");\nvoid *malloc_wraptxn(size_t size)\n{\n  __asm__ __volatile__(\"jmp 1f\\nmov $0xf0f0f0f0,%eax\\n1:\");\n  return malloc_txn(size);\n}\n\nvoid *calloc_txn(size_t nmemb, size_t size) __asm__(\"calloc._$TXN\");\nvoid *calloc_txn(size_t nmemb, size_t size)\n{\n  return stm_calloc(nmemb, size);\n}\n\nvoid *calloc_wraptxn(size_t nmemb, size_t size) __asm__(\"calloc._$WrapTXN\");\nvoid *calloc_wraptxn(size_t nmemb, size_t size)\n{\n  __asm__ __volatile__(\"jmp 1f\\nmov $0xf0f0f0f0,%eax\\n1:\");\n  return calloc_txn(nmemb, size);\n}\n\nvoid free_txn(void *addr) __asm__(\"free._$TXN\");\nvoid free_txn(void *addr)\n{\n  stm_free(addr, sizeof(void *));\n}\n\nvoid free_wraptxn(void *addr) __asm__(\"free._$WrapTXN\");\nvoid free_wraptxn(void *addr)\n{\n  __asm__ __volatile__(\"jmp 1f\\nmov $0xf0f0f0f0,%eax\\n1:\");\n  free_txn(addr);\n}\n\n#if 0\n/* TODO */\n_mm_free._$TXN\n_mm_free._$WrapTXN\n_mm_malloc._$TXN\n_mm_malloc._$WrapTXN\n\nvoid* _mm_malloc (int size, int align)\nvoid _mm_free (void *p)\n\n_ZdaPv._$TXN\n_ZdaPv._$WrapTXN\n_ZdlPv._$TXN\n_ZdlPv._$WrapTXN\n_Znam._$TXN\n_Znam._$WrapTXN\n_Znwm._$TXN\n_Znwm._$WrapTXN\n#endif \n\n"
  },
  {
    "path": "stms/tinystm/abi/intel/arch.S",
    "content": "#ifndef __linux__\n/* Linux specific, Windows uses a different calling convention. */\n/* TODO probably solaris is fine with it. */\n# error This file is linux specific.\n#endif\n\n\t.text\n\n#if defined(__x86_64__)\n\t.align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n\n_ITM_beginTransaction:\n\t.cfi_startproc\n/* Parameters (in order) is in rdi, rsi, rdx, rcx, r8, r9 */\n/* Temporary registers is r10, r11 (not saved) */\n/* To be saved are rbx, rsp, rbp, r12, r13, r14, r15 */\n\tleaq\t8(%rsp), %rax    /* Save stack pointer */\n\tsubq\t$56, %rsp\n\t.cfi_def_cfa_offset 64\n\tmovq\t%rax, (%rsp)\n\tmovq\t%rbx, 8(%rsp)\n\tmovq\t%rbp, 16(%rsp)\n\tmovq\t%r12, 24(%rsp)\n\tmovq\t%r13, 32(%rsp)\n\tmovq\t%r14, 40(%rsp)\n\tmovq\t%r15, 48(%rsp)\n\tmovq\t%rsp, %rdx\n\tcall\tGTM_begin_transaction\n\taddq\t$56, %rsp\n\t.cfi_def_cfa_offset 8\n\tret\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovq\t(%rsi), %rcx\n\tmovq\t8(%rsi), %rbx\n\tmovq\t16(%rsi), %rbp\n\tmovq\t24(%rsi), %r12\n\tmovq\t32(%rsi), %r13\n\tmovq\t40(%rsi), %r14\n\tmovq\t48(%rsi), %r15\n\tmovl\t%edi, %eax\n\t.cfi_def_cfa %rsi, 0\n\t.cfi_offset %rip, 56\n\t.cfi_register %rsp, %rcx\n\tmovq\t%rcx, %rsp\n\t/* a_restoreLiveVariables = 0x08 */\n\torq \t$8, %rax\n\tjmp\t*56(%rsi)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__i386__)\n\t.align 4\n\t.globl\t_ITM_beginTransaction\n\t.type\t_ITM_beginTransaction, @function\n_ITM_beginTransaction:\n\t.cfi_startproc\n\t/* eax: tx, edx: attr, stack: __src */\n\tleal\t4(%esp), %ecx\n\tsubl\t$28, %esp\n\t.cfi_def_cfa_offset 32\n\tmovl\t%ecx, 8(%esp)\n\tmovl\t%ebx, 12(%esp)\n\tmovl\t%esi, 16(%esp)\n\tmovl\t%edi, 20(%esp)\n\tmovl\t%ebp, 24(%esp)\n\tleal\t8(%esp), %ecx\n\tpush\t%ecx\n\t/* GTM_begin_transaction(eax: tx, edx: attr, stack: jmp_buf) */\n\tcall\tGTM_begin_transaction\n\taddl\t$32, %esp\n\t.cfi_def_cfa_offset 4\n\tret\n\t.cfi_endproc\n\t.size\t_ITM_beginTransaction, .-_ITM_beginTransaction\n\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovl\t(%edx), %ecx\n\tmovl\t4(%edx), %ebx\n\tmovl\t8(%edx), %esi\n\tmovl\t12(%edx), %edi\n\tmovl\t16(%edx), %ebp\n\t.cfi_def_cfa %edx, 0\n\t.cfi_offset %eip, 20\n\t.cfi_register %esp, %ecx\n\tmovl\t%ecx, %esp\n\t/* TODO check correctness of this behaviour, a_restoreLiveVariables = 0x08 */\n\torl \t$8, %eax\n\tjmp\t*20(%edx)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#else\n# error Unsupported architecture\n#endif\n\n#ifdef __linux__\n.section .note.GNU-stack, \"\", @progbits\n#endif\n"
  },
  {
    "path": "stms/tinystm/abi/intel/libitm.h",
    "content": "/*\n * File:\n *   libitm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   ABI for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _LIBITM_H_\n#define _LIBITM_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#include <stdint.h>\n#include <stdbool.h>\n#ifdef __SSE__\n# include <xmmintrin.h>\n#endif\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n#define _ITM_VERSION_NO_STR \"1.0.4\"\n#define _ITM_VERSION_NO 104\n\n#if defined(__i386__)\n# define _ITM_CALL_CONVENTION __attribute__((regparm(2)))\n#else\n# define _ITM_CALL_CONVENTION\n#endif\n\n#define _ITM_noTransactionId 1\t\t/* Id for non-transactional code. */\n\n\n#define _ITM_TRANSACTION_PURE __attribute__((tm_pure))\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef void *_ITM_transaction;\n\ntypedef void (*_ITM_userUndoFunction)(void *);\ntypedef void (*_ITM_userCommitFunction)(void *);\n\ntypedef uint32_t _ITM_transactionId;\n\ntypedef enum\n{\n  outsideTransaction = 0,\n  inRetryableTransaction,\n  inIrrevocableTransaction\n} _ITM_howExecuting;\n\nstruct _ITM_srcLocationS\n{\n  int32_t reserved_1;\n  int32_t flags;\n  int32_t reserved_2;\n  int32_t reserved_3;\n  const char *psource;\n};\n\ntypedef struct _ITM_srcLocationS _ITM_srcLocation;\n\ntypedef enum {\n  pr_instrumentedCode = 0x0001,\n  pr_uninstrumentedCode = 0x0002,\n  pr_multiwayCode = pr_instrumentedCode | pr_uninstrumentedCode,\n  pr_hasNoXMMUpdate = 0x0004,\n  pr_hasNoAbort = 0x0008,\n  pr_hasNoRetry = 0x0010,\n  pr_hasNoIrrevocable = 0x0020,\n  pr_doesGoIrrevocable = 0x0040,\n  pr_hasNoSimpleReads = 0x0080,\n  pr_aWBarriersOmitted = 0x0100,\n  pr_RaRBarriersOmitted = 0x0200,\n  pr_undoLogCode = 0x0400,\n  pr_preferUninstrumented = 0x0800,\n  pr_exceptionBlock = 0x1000,\n  pr_hasElse = 0x2000,\n  pr_readOnly = 0x4000 /* GNU gcc specific */\n} _ITM_codeProperties;\n\ntypedef enum {\n  a_runInstrumentedCode = 0x01,\n  a_runUninstrumentedCode = 0x02,\n  a_saveLiveVariables = 0x04,\n  a_restoreLiveVariables = 0x08,\n  a_abortTransaction = 0x10,\n} _ITM_actions;\n\ntypedef enum {\n  modeSerialIrrevocable,\n  modeObstinate,\n  modeOptimistic,\n  modePessimistic,\n} _ITM_transactionState;\n\ntypedef enum {\n  unknown = 0,\n  userAbort = 1,\n  userRetry = 2,\n  TMConflict= 4,\n  exceptionBlockAbort = 8\n} _ITM_abortReason;\n\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transaction * _ITM_CALL_CONVENTION _ITM_getTransaction(void);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_howExecuting _ITM_CALL_CONVENTION _ITM_inTransaction(_ITM_transaction *);\n\nextern _ITM_TRANSACTION_PURE\nint _ITM_CALL_CONVENTION _ITM_getThreadnum(void);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserCommitAction(_ITM_transaction *, \n                             _ITM_userCommitFunction __commit,\n                             _ITM_transactionId resumingTransactionId,\n                             void *__arg);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserUndoAction(_ITM_transaction *, \n                             const _ITM_userUndoFunction __undo, void * __arg);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transactionId _ITM_CALL_CONVENTION _ITM_getTransactionId(_ITM_transaction *);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_dropReferences(_ITM_transaction *, \n                             const void *__start, size_t __size);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_userError(const char *errString, int exitCode);\n\nextern const char * _ITM_CALL_CONVENTION _ITM_libraryVersion(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_versionCompatible(int version);\n\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeProcess(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeProcess(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_error(const _ITM_srcLocation *__src,\n                             int errorCode);\n\nextern uint32_t _ITM_CALL_CONVENTION _ITM_beginTransaction(_ITM_transaction *, \n                             uint32_t __properties,\n                             const _ITM_srcLocation *__src)\n                             __attribute__((returns_twice));\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransaction(_ITM_transaction *, \n                             const _ITM_srcLocation *__src);\n\n\nextern bool _ITM_CALL_CONVENTION _ITM_tryCommitTransaction(_ITM_transaction *, \n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransactionToId(_ITM_transaction *, \n                             const _ITM_transactionId tid,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_abortTransaction(_ITM_transaction *, \n                             _ITM_abortReason __reason,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_rollbackTransaction(_ITM_transaction *, \n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_registerThrownObject(_ITM_transaction *, \n                             const void *__obj,\n                             size_t __size);\n\nextern void _ITM_CALL_CONVENTION _ITM_changeTransactionMode(_ITM_transaction *, \n                             _ITM_transactionState __mode,\n                             const _ITM_srcLocation *__loc);\n\n\n\n/*** Loads ***/\n\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RU1(_ITM_transaction *, const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaRU1(_ITM_transaction *, const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaWU1(_ITM_transaction *, const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RfWU1(_ITM_transaction *, const uint8_t *);\n\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RU2(_ITM_transaction *, const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaRU2(_ITM_transaction *, const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaWU2(_ITM_transaction *, const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RfWU2(_ITM_transaction *, const uint16_t *);\n\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RU4(_ITM_transaction *, const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaRU4(_ITM_transaction *, const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaWU4(_ITM_transaction *, const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RfWU4(_ITM_transaction *, const uint32_t *);\n\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RU8(_ITM_transaction *, const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaRU8(_ITM_transaction *, const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaWU8(_ITM_transaction *, const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RfWU8(_ITM_transaction *, const uint64_t *);\n\nextern float _ITM_CALL_CONVENTION _ITM_RF(_ITM_transaction *, const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaRF(_ITM_transaction *, const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaWF(_ITM_transaction *, const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RfWF(_ITM_transaction *, const float *);\n\nextern double _ITM_CALL_CONVENTION _ITM_RD(_ITM_transaction *, const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaRD(_ITM_transaction *, const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaWD(_ITM_transaction *, const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RfWD(_ITM_transaction *, const double *);\n\n#ifdef __SSE__\nextern __m64 _ITM_CALL_CONVENTION _ITM_RM64(_ITM_transaction *, const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaRM64(_ITM_transaction *, const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaWM64(_ITM_transaction *, const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RfWM64(_ITM_transaction *, const __m64 *);\n\nextern __m128 _ITM_CALL_CONVENTION _ITM_RM128(_ITM_transaction *, const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaRM128(_ITM_transaction *, const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaWM128(_ITM_transaction *, const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RfWM128(_ITM_transaction *, const __m128 *);\n#endif /* __SSE__ */\n\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RCF(_ITM_transaction *, const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaRCF(_ITM_transaction *, const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaWCF(_ITM_transaction *, const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RfWCF(_ITM_transaction *, const float _Complex *);\n\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RCD(_ITM_transaction *, const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaRCD(_ITM_transaction *, const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaWCD(_ITM_transaction *, const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RfWCD(_ITM_transaction *, const double _Complex *);\n\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RCE(_ITM_transaction *, const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaRCE(_ITM_transaction *, const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaWCE(_ITM_transaction *, const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RfWCE(_ITM_transaction *, const long double _Complex *);\n\n\n/*** Stores ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_WU1(_ITM_transaction *, const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU1(_ITM_transaction *, const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU1(_ITM_transaction *, const uint8_t *, uint8_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU2(_ITM_transaction *, const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU2(_ITM_transaction *, const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU2(_ITM_transaction *, const uint16_t *, uint16_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU4(_ITM_transaction *, const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU4(_ITM_transaction *, const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU4(_ITM_transaction *, const uint32_t *, uint32_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU8(_ITM_transaction *, const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU8(_ITM_transaction *, const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU8(_ITM_transaction *, const uint64_t *, uint64_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WF(_ITM_transaction *, const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaRF(_ITM_transaction *, const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaWF(_ITM_transaction *, const float *, float);\n\nextern void _ITM_CALL_CONVENTION _ITM_WD(_ITM_transaction *, const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaRD(_ITM_transaction *, const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaWD(_ITM_transaction *, const double *, double);\n\n#ifdef __SSE__\nextern void _ITM_CALL_CONVENTION _ITM_WM64(_ITM_transaction *, const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM64(_ITM_transaction *, const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM64(_ITM_transaction *, const __m64 *, __m64);\n\nextern void _ITM_CALL_CONVENTION _ITM_WM128(_ITM_transaction *, const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM128(_ITM_transaction *, const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM128(_ITM_transaction *, const __m128 *, __m128);\n#endif /* __SSE__ */\n\nextern void _ITM_CALL_CONVENTION _ITM_WCF(_ITM_transaction *, const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCF(_ITM_transaction *, const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCF(_ITM_transaction *, const float _Complex *, float _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCD(_ITM_transaction *, const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCD(_ITM_transaction *, const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCD(_ITM_transaction *, const double _Complex *, double _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCE(_ITM_transaction *, const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCE(_ITM_transaction *, const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCE(_ITM_transaction *, const long double _Complex *, long double _Complex);\n\n\n/*** Logging functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_LU1(_ITM_transaction *, const uint8_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU2(_ITM_transaction *, const uint16_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU4(_ITM_transaction *, const uint32_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU8(_ITM_transaction *, const uint64_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LF(_ITM_transaction *, const float *);\nextern void _ITM_CALL_CONVENTION _ITM_LD(_ITM_transaction *, const double *);\nextern void _ITM_CALL_CONVENTION _ITM_LE(_ITM_transaction *, const long double *);\nextern void _ITM_CALL_CONVENTION _ITM_LM64(_ITM_transaction *, const __m64 *);\nextern void _ITM_CALL_CONVENTION _ITM_LM128(_ITM_transaction *, const __m128 *);\nextern void _ITM_CALL_CONVENTION _ITM_LCF(_ITM_transaction *, const float _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCD(_ITM_transaction *, const double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCE(_ITM_transaction *, const long double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LB(_ITM_transaction *, const void *, size_t);\n\n\n/*** memcpy functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaW(_ITM_transaction *, void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWn(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWn(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWn(_ITM_transaction *, void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaW(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaW(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaW(_ITM_transaction *, void *, const void *, size_t);\n\n\n/*** memset functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memsetW(_ITM_transaction *, void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaR(_ITM_transaction *, void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaW(_ITM_transaction *, void *, int, size_t);\n\n\n/*** memmove functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaW(_ITM_transaction *, void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWn(_ITM_transaction *, void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWn(_ITM_transaction *, void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWn(_ITM_transaction *, void *, const void *, size_t); \n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaW(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaW(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWt(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaR(_ITM_transaction *, void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaW(_ITM_transaction *, void *, const void *, size_t);\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif /* __cplusplus */\n\n#endif /* _LIBITM_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/intel/tm_macros.h",
    "content": "/*\n * File:\n *   tm_macros.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Defines macros for transactional operations.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _TM_MACROS_H_\n# define _TM_MACROS_H_\n/* TODO check for exit() and perror() */\n/* TODO check function pointer in rbtree */\n/* 3.0 #define __INTEL_COMPILER_BUILD_DATE 20081204 */\n/* 4.0 #define __INTEL_COMPILER_BUILD_DATE 20100806 */\n# if __INTEL_COMPILER_BUILD_DATE < 20100806\n#  define TM_START(id,ro)                   __tm_atomic {\n# else /* __INTEL_COMPILER_BUILD_DATE >= 20100806 */\n#  define TM_START(id,ro)                   __transaction [[atomic]] {\n# endif /* __INTEL_COMPILER_BUILD_DATE >= 20100806 */\n# define TM_LOAD(x)                         *x\n# define TM_STORE(x,y)                      *x=y\n# define TM_COMMIT                          }\n# define TM_MALLOC(size)                    malloc(size)\n# define TM_FREE(addr)                      free(addr)\n# define TM_FREE2(addr, size)               free(addr)\n\n# define TM_INIT\n# define TM_EXIT\n# define TM_INIT_THREAD\n# define TM_EXIT_THREAD\n\n/* Define Annotations */\n# if __INTEL_COMPILER_BUILD_DATE < 20100806\n#  define TM_PURE                           __attribute__((tm_pure))\n#  define TM_SAFE                           __attribute__((tm_callable))\n# else /* __INTEL_COMPILER_BUILD_DATE >= 20100806 */\n#  define TM_PURE                           [[transaction_pure]]\n#  define TM_SAFE                           [[transaction_safe]]\n\n/* error: non [[transaction_safe]] function \"malloc\" called inside [[transaction_safe]] routine */\nTM_SAFE\nvoid *malloc(size_t);\n\nTM_SAFE\nvoid free(void *);\n\n# endif /* __INTEL_COMPILER_BUILD_DATE >= 20100806 */\n\n#endif /* _TM_MACROS_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/libitm.h.tpl.cpp",
    "content": "/*** Loads ***/\n\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RU1(TX_ARGS const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaRU1(TX_ARGS const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RaWU1(TX_ARGS const uint8_t *);\nextern uint8_t _ITM_CALL_CONVENTION _ITM_RfWU1(TX_ARGS const uint8_t *);\n\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RU2(TX_ARGS const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaRU2(TX_ARGS const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RaWU2(TX_ARGS const uint16_t *);\nextern uint16_t _ITM_CALL_CONVENTION _ITM_RfWU2(TX_ARGS const uint16_t *);\n\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RU4(TX_ARGS const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaRU4(TX_ARGS const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RaWU4(TX_ARGS const uint32_t *);\nextern uint32_t _ITM_CALL_CONVENTION _ITM_RfWU4(TX_ARGS const uint32_t *);\n\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RU8(TX_ARGS const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaRU8(TX_ARGS const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RaWU8(TX_ARGS const uint64_t *);\nextern uint64_t _ITM_CALL_CONVENTION _ITM_RfWU8(TX_ARGS const uint64_t *);\n\nextern float _ITM_CALL_CONVENTION _ITM_RF(TX_ARGS const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaRF(TX_ARGS const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RaWF(TX_ARGS const float *);\nextern float _ITM_CALL_CONVENTION _ITM_RfWF(TX_ARGS const float *);\n\nextern double _ITM_CALL_CONVENTION _ITM_RD(TX_ARGS const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaRD(TX_ARGS const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RaWD(TX_ARGS const double *);\nextern double _ITM_CALL_CONVENTION _ITM_RfWD(TX_ARGS const double *);\n\n#ifdef __SSE__\nextern __m64 _ITM_CALL_CONVENTION _ITM_RM64(TX_ARGS const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaRM64(TX_ARGS const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RaWM64(TX_ARGS const __m64 *);\nextern __m64 _ITM_CALL_CONVENTION _ITM_RfWM64(TX_ARGS const __m64 *);\n\nextern __m128 _ITM_CALL_CONVENTION _ITM_RM128(TX_ARGS const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaRM128(TX_ARGS const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RaWM128(TX_ARGS const __m128 *);\nextern __m128 _ITM_CALL_CONVENTION _ITM_RfWM128(TX_ARGS const __m128 *);\n#endif /* __SSE__ */\n\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RCF(TX_ARGS const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaRCF(TX_ARGS const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RaWCF(TX_ARGS const float _Complex *);\nextern float _Complex _ITM_CALL_CONVENTION _ITM_RfWCF(TX_ARGS const float _Complex *);\n\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RCD(TX_ARGS const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaRCD(TX_ARGS const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RaWCD(TX_ARGS const double _Complex *);\nextern double _Complex _ITM_CALL_CONVENTION _ITM_RfWCD(TX_ARGS const double _Complex *);\n\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RCE(TX_ARGS const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaRCE(TX_ARGS const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RaWCE(TX_ARGS const long double _Complex *);\nextern long double _Complex _ITM_CALL_CONVENTION _ITM_RfWCE(TX_ARGS const long double _Complex *);\n\n\n/*** Stores ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_WU1(TX_ARGS const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU1(TX_ARGS const uint8_t *, uint8_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU1(TX_ARGS const uint8_t *, uint8_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU2(TX_ARGS const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU2(TX_ARGS const uint16_t *, uint16_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU2(TX_ARGS const uint16_t *, uint16_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU4(TX_ARGS const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU4(TX_ARGS const uint32_t *, uint32_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU4(TX_ARGS const uint32_t *, uint32_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WU8(TX_ARGS const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaRU8(TX_ARGS const uint64_t *, uint64_t);\nextern void _ITM_CALL_CONVENTION _ITM_WaWU8(TX_ARGS const uint64_t *, uint64_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_WF(TX_ARGS const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaRF(TX_ARGS const float *, float);\nextern void _ITM_CALL_CONVENTION _ITM_WaWF(TX_ARGS const float *, float);\n\nextern void _ITM_CALL_CONVENTION _ITM_WD(TX_ARGS const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaRD(TX_ARGS const double *, double);\nextern void _ITM_CALL_CONVENTION _ITM_WaWD(TX_ARGS const double *, double);\n\n#ifdef __SSE__\nextern void _ITM_CALL_CONVENTION _ITM_WM64(TX_ARGS const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM64(TX_ARGS const __m64 *, __m64);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM64(TX_ARGS const __m64 *, __m64);\n\nextern void _ITM_CALL_CONVENTION _ITM_WM128(TX_ARGS const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaRM128(TX_ARGS const __m128 *, __m128);\nextern void _ITM_CALL_CONVENTION _ITM_WaWM128(TX_ARGS const __m128 *, __m128);\n#endif /* __SSE__ */\n\nextern void _ITM_CALL_CONVENTION _ITM_WCF(TX_ARGS const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCF(TX_ARGS const float _Complex *, float _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCF(TX_ARGS const float _Complex *, float _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCD(TX_ARGS const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCD(TX_ARGS const double _Complex *, double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCD(TX_ARGS const double _Complex *, double _Complex);\n\nextern void _ITM_CALL_CONVENTION _ITM_WCE(TX_ARGS const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaRCE(TX_ARGS const long double _Complex *, long double _Complex);\nextern void _ITM_CALL_CONVENTION _ITM_WaWCE(TX_ARGS const long double _Complex *, long double _Complex);\n\n\n/*** Logging functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_LU1(TX_ARGS const uint8_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU2(TX_ARGS const uint16_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU4(TX_ARGS const uint32_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LU8(TX_ARGS const uint64_t *);\nextern void _ITM_CALL_CONVENTION _ITM_LF(TX_ARGS const float *);\nextern void _ITM_CALL_CONVENTION _ITM_LD(TX_ARGS const double *);\nextern void _ITM_CALL_CONVENTION _ITM_LE(TX_ARGS const long double *);\nextern void _ITM_CALL_CONVENTION _ITM_LM64(TX_ARGS const __m64 *);\nextern void _ITM_CALL_CONVENTION _ITM_LM128(TX_ARGS const __m128 *);\nextern void _ITM_CALL_CONVENTION _ITM_LCF(TX_ARGS const float _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCD(TX_ARGS const double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LCE(TX_ARGS const long double _Complex *);\nextern void _ITM_CALL_CONVENTION _ITM_LB(TX_ARGS const void *, size_t);\n\n\n/*** memcpy functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRnWtaW(TX_ARGS void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWn(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWn(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWn(TX_ARGS void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtWtaW(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaRWtaW(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memcpyRtaWWtaW(TX_ARGS void *, const void *, size_t);\n\n\n/*** memset functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memsetW(TX_ARGS void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaR(TX_ARGS void *, int, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memsetWaW(TX_ARGS void *, int, size_t);\n\n\n/*** memmove functions ***/\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRnWtaW(TX_ARGS void *, const void *, size_t);\n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWn(TX_ARGS void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWn(TX_ARGS void *, const void *, size_t); \nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWn(TX_ARGS void *, const void *, size_t); \n\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtWtaW(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaRWtaW(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWt(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaR(TX_ARGS void *, const void *, size_t);\nextern void _ITM_CALL_CONVENTION _ITM_memmoveRtaWWtaW(TX_ARGS void *, const void *, size_t);\n\n"
  },
  {
    "path": "stms/tinystm/abi/libitm.h.tpl.footer",
    "content": "\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif /* __cplusplus */\n\n#endif /* _LIBITM_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/abi/libitm.h.tpl.header",
    "content": "/*\n * File:\n *   libitm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   ABI for tinySTM.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _LIBITM_H_\n#define _LIBITM_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#include <stdint.h>\n#include <stdbool.h>\n#ifdef __SSE__\n# include <xmmintrin.h>\n#endif\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n#define _ITM_VERSION_NO_STR \"1.0.4\"\n#define _ITM_VERSION_NO 104\n\n#if defined(__i386__)\n# define _ITM_CALL_CONVENTION __attribute__((regparm(2)))\n#else\n# define _ITM_CALL_CONVENTION\n#endif\n\n#define _ITM_noTransactionId 1\t\t/* Id for non-transactional code. */\n\n\n"
  },
  {
    "path": "stms/tinystm/abi/libitm.h.tpl.unifdef",
    "content": "#if defined(TM_GCC) || defined(TM_DTMC)\n#define _ITM_TRANSACTION_PURE __attribute__((transaction_pure))\n#elif defined(TM_INTEL)\n#define _ITM_TRANSACTION_PURE __attribute__((tm_pure))\n/* TODO [[transaction_pure]] */\n#endif\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef void *_ITM_transaction;\n\ntypedef void (*_ITM_userUndoFunction)(void *);\ntypedef void (*_ITM_userCommitFunction)(void *);\n\ntypedef uint32_t _ITM_transactionId;\n\ntypedef enum\n{\n  outsideTransaction = 0,\n  inRetryableTransaction,\n  inIrrevocableTransaction\n} _ITM_howExecuting;\n\nstruct _ITM_srcLocationS\n{\n  int32_t reserved_1;\n  int32_t flags;\n  int32_t reserved_2;\n  int32_t reserved_3;\n  const char *psource;\n};\n\ntypedef struct _ITM_srcLocationS _ITM_srcLocation;\n\ntypedef enum {\n  pr_instrumentedCode = 0x0001,\n  pr_uninstrumentedCode = 0x0002,\n  pr_multiwayCode = pr_instrumentedCode | pr_uninstrumentedCode,\n  pr_hasNoXMMUpdate = 0x0004,\n  pr_hasNoAbort = 0x0008,\n  pr_hasNoRetry = 0x0010,\n  pr_hasNoIrrevocable = 0x0020,\n  pr_doesGoIrrevocable = 0x0040,\n  pr_hasNoSimpleReads = 0x0080,\n  pr_aWBarriersOmitted = 0x0100,\n  pr_RaRBarriersOmitted = 0x0200,\n  pr_undoLogCode = 0x0400,\n  pr_preferUninstrumented = 0x0800,\n  pr_exceptionBlock = 0x1000,\n  pr_hasElse = 0x2000,\n  pr_readOnly = 0x4000 /* GNU gcc specific */\n} _ITM_codeProperties;\n\ntypedef enum {\n  a_runInstrumentedCode = 0x01,\n  a_runUninstrumentedCode = 0x02,\n  a_saveLiveVariables = 0x04,\n  a_restoreLiveVariables = 0x08,\n  a_abortTransaction = 0x10,\n} _ITM_actions;\n\ntypedef enum {\n  modeSerialIrrevocable,\n  modeObstinate,\n  modeOptimistic,\n  modePessimistic,\n} _ITM_transactionState;\n\ntypedef enum {\n  unknown = 0,\n  userAbort = 1,\n  userRetry = 2,\n  TMConflict= 4,\n  exceptionBlockAbort = 8\n} _ITM_abortReason;\n\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transaction * _ITM_CALL_CONVENTION _ITM_getTransaction(void);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_howExecuting _ITM_CALL_CONVENTION _ITM_inTransaction(TX_ARG);\n\nextern _ITM_TRANSACTION_PURE\nint _ITM_CALL_CONVENTION _ITM_getThreadnum(void);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserCommitAction(TX_ARGS \n                             _ITM_userCommitFunction __commit,\n                             _ITM_transactionId resumingTransactionId,\n                             void *__arg);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_addUserUndoAction(TX_ARGS \n                             const _ITM_userUndoFunction __undo, void * __arg);\n\nextern _ITM_TRANSACTION_PURE\n_ITM_transactionId _ITM_CALL_CONVENTION _ITM_getTransactionId(TX_ARG);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_dropReferences(TX_ARGS \n                             const void *__start, size_t __size);\n\nextern _ITM_TRANSACTION_PURE\nvoid _ITM_CALL_CONVENTION _ITM_userError(const char *errString, int exitCode);\n\nextern const char * _ITM_CALL_CONVENTION _ITM_libraryVersion(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_versionCompatible(int version);\n\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeThread(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_finalizeProcess(void);\n\nextern int _ITM_CALL_CONVENTION _ITM_initializeProcess(void);\n\nextern void _ITM_CALL_CONVENTION _ITM_error(const _ITM_srcLocation *__src,\n                             int errorCode);\n\n#if defined(TM_GCC)\nextern uint32_t _ITM_beginTransaction(uint32_t __properties, ...)\n                             __attribute__((returns_twice));\nextern void _ITM_CALL_CONVENTION _ITM_commitTransaction(void);\n\n#elif defined(TM_INTEL) || defined(TM_DTMC)\nextern uint32_t _ITM_CALL_CONVENTION _ITM_beginTransaction(TX_ARGS \n                             uint32_t __properties,\n                             const _ITM_srcLocation *__src)\n                             __attribute__((returns_twice));\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransaction(TX_ARGS \n                             const _ITM_srcLocation *__src);\n#endif /* TM_INTEL */\n\n/* TODO only Intel tryCommit + _ITM_srcLocation  */\nextern bool _ITM_CALL_CONVENTION _ITM_tryCommitTransaction(TX_ARGS \n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_commitTransactionToId(TX_ARGS \n                             const _ITM_transactionId tid,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_abortTransaction(TX_ARGS \n                             _ITM_abortReason __reason,\n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_rollbackTransaction(TX_ARGS \n                             const _ITM_srcLocation *__src);\n\nextern void _ITM_CALL_CONVENTION _ITM_registerThrownObject(TX_ARGS \n                             const void *__obj,\n                             size_t __size);\n\nextern void _ITM_CALL_CONVENTION _ITM_changeTransactionMode(TX_ARGS \n                             _ITM_transactionState __mode,\n                             const _ITM_srcLocation *__loc);\n\n#if defined(TM_GCC)\n/**** GCC Specific ****/\nextern _ITM_CALL_CONVENTION void *_ITM_getTMCloneOrIrrevocable(void *);\nextern _ITM_CALL_CONVENTION void *_ITM_getTMCloneSafe(void *);\nextern void _ITM_registerTMCloneTable(void *, size_t);\nextern void _ITM_deregisterTMCloneTable(void *);\nextern _ITM_CALL_CONVENTION void _ITM_commitTransactionEH(void *);\n#endif /* defined(TM_GCC) */\n\n#if defined(TM_GCC) || defined(TM_DTMC)\nextern void * _ITM_malloc(size_t);\nextern void * _ITM_calloc(size_t, size_t);\nextern void _ITM_free(void *);\n#endif /* defined(TM_GCC) || defined(TM_DTMC) */\n\n"
  },
  {
    "path": "stms/tinystm/abi/oracle/Makefile",
    "content": "# Path to TinySTM\nROOT = ../..\n\n.PHONY:\toracletm all clean check test\n\nall:\toracletm\n\n# ROOT must be defined to include Makefile.common\ninclude $(ROOT)/abi/Makefile.common\n\n\n##############################################################################\n## Oracle TM \n##############################################################################\nCPPFLAGS += -DTM_ORACLE -I.\n\noracletm: \tlibitm.a \n\narch.o: arch.S\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.o: \t%.c \n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.s: \t%.c \n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -fverbose-asm -S -o $@ $<\n\nlibitm.a: otm.o arch.o \n\t$(AR) cru $@ $^\n\nclean:\n\trm -f *.o *.do libitm.a\n\n"
  },
  {
    "path": "stms/tinystm/abi/oracle/arch.S",
    "content": "#ifndef __linux__\n/* Linux specific, Windows uses a different calling convention. */\n/* TODO probably solaris is fine with it. */\n# error This file is linux specific.\n#endif\n\n\t.text\n\n#if defined(__x86_64__)\n\t.align 4\n\t.globl\tSTM_BeginTransaction\n\t.type\tSTM_BeginTransaction, @function\n\nSTM_BeginTransaction:\n\t.cfi_startproc\n/* Paramters (in order) is in rdi, rsi, rdx, rcx, r8, r9 */\n/* Temporary registers is r10, r11 (not saved) */\n/* To be saved are rbx, rsp, rbp, r12, r13, r14, r15 */\n\tleaq\t8(%rsp), %rax    /* Save stack pointer */\n\tsubq\t$56, %rsp\n\t.cfi_def_cfa_offset 64\n\tmovq\t%rax, (%rsp)\n\tmovq\t%rbx, 8(%rsp)\n\tmovq\t%rbp, 16(%rsp)\n\tmovq\t%r12, 24(%rsp)\n\tmovq\t%r13, 32(%rsp)\n\tmovq\t%r14, 40(%rsp)\n\tmovq\t%r15, 48(%rsp)\n\tmovq\t%rsp, %rsi\n\tcall\t_STM_BeginTransaction\n\taddq\t$56, %rsp\n\t.cfi_def_cfa_offset 8\n\tret\n\t.cfi_endproc\n\t.size\tSTM_BeginTransaction, .-STM_BeginTransaction\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovq\t(%rsi), %rcx\n\tmovq\t8(%rsi), %rbx\n\tmovq\t16(%rsi), %rbp\n\tmovq\t24(%rsi), %r12\n\tmovq\t32(%rsi), %r13\n\tmovq\t40(%rsi), %r14\n\tmovq\t48(%rsi), %r15\n\tmovl\t%edi, %eax\n\t.cfi_def_cfa %rsi, 0\n\t.cfi_offset %rip, 56\n\t.cfi_register %rsp, %rcx\n\tmovq\t%rcx, %rsp\n\tjmp\t*56(%rsi)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__i386__)\n\t.align 4\n\t.globl\tSTM_BeginTransaction\n\t.type\tSTM_BeginTransaction, @function\nSTM_BeginTransaction:\n\t.cfi_startproc\n\tleal\t4(%esp), %ecx\n\tmovl\t4(%esp), %eax\n\tsubl\t$28, %esp\n\t.cfi_def_cfa_offset 32\n\tmovl\t%ecx, 8(%esp)\n\tmovl\t%ebx, 12(%esp)\n\tmovl\t%esi, 16(%esp)\n\tmovl\t%edi, 20(%esp)\n\tmovl\t%ebp, 24(%esp)\n\tleal\t8(%esp), %edx\n\tcall\t_STM_BeginTransaction\n\taddl\t$28, %esp\n\t.cfi_def_cfa_offset 4\n\tret\n\t.cfi_endproc\n\t.size\tSTM_BeginTransaction, .-STM_BeginTransaction\n\n\n\t.align 4\n\t.globl\t_ITM_siglongjmp\n\t.type\t_ITM_siglongjmp, @function\n\t.hidden\t_ITM_siglongjmp\n_ITM_siglongjmp:\n\t.cfi_startproc\n\tmovl\t(%edx), %ecx\n\tmovl\t4(%edx), %ebx\n\tmovl\t8(%edx), %esi\n\tmovl\t12(%edx), %edi\n\tmovl\t16(%edx), %ebp\n\t.cfi_def_cfa %edx, 0\n\t.cfi_offset %eip, 20\n\t.cfi_register %esp, %ecx\n\tmovl\t%ecx, %esp\n\tjmp\t*20(%edx)\n\t.cfi_endproc\n\t.size\t_ITM_siglongjmp, .-_ITM_siglongjmp\n\n#elif defined(__sparc__)\n# error SPARC arch is not yet supported\n#else\n# error Unsupported architecture\n#endif\n\n#ifdef __linux__\n.section .note.GNU-stack, \"\", @progbits\n#endif\n"
  },
  {
    "path": "stms/tinystm/abi/oracle/otm.c",
    "content": "#include <stdint.h>\n#include \"stm.h\"\n#include \"wrappers.h\"\n#include \"mod_mem.h\"\n\n#define CTX_ITM   _ITM_siglongjmp\n#define _ITM_CALL_CONVENTION __attribute__((regparm(2)))\nextern void _ITM_CALL_CONVENTION _ITM_siglongjmp(int val, sigjmp_buf env) __attribute__ ((noreturn));\n\n#include \"stm.c\"\n#include \"mod_cb_mem.c\"\n#include \"wrappers.c\"\n\n/* TODO __FUNCTION__ is not available with Oracle Studio if -Xc () and -Xs (K&R mode) but should not be a problem. */\n/* __FUNCTION__ and __PRETTY_FUNCTION__ are predefined identifiers that contain the name of the lexically-enclosing function. They are functionally equivalent to the c99 predefined identifier, __func__. On Solaris platforms, __FUNCTION__ and __PRETTY_FUNCTION__ are not available in -Xs and -Xc modes. */\n\nstm_tx_t *STM_GetMyTransId(void)\n{\n  stm_tx_t *tx = stm_current_tx();\n  PRINT_DEBUG(\"==> %s()\\n\", __FUNCTION__);\n  if (tx == NULL) {\n    stm_init();\n    mod_mem_init(0);\n    tx = stm_init_thread();\n    /* TODO save stack high and low addr */\n  }\n  PRINT_DEBUG(\"==> %s() -> 0x%p\\n\", __FUNCTION__, tx);\n  return tx;\n}\n\n__attribute__((regparm(2)))\nint _STM_BeginTransaction(stm_tx_t *tx, jmp_buf *buf)\n{\n  sigjmp_buf * env;\n  PRINT_DEBUG(\"==> %s(0x%p)\\n\", __FUNCTION__, tx);\n  /* TODO see how the ctx is saved and rollback. */\n  env = int_stm_start(tx, (stm_tx_attr_t)0);\n  if (likely(env != NULL))\n    memcpy(env, buf, sizeof(jmp_buf)); /* TODO limit size to real size */\n  return 1;\n}\n\nint STM_ValidateTransaction(stm_tx_t *tx)\n{\n  /*int ret;*/\n  PRINT_DEBUG(\"==> %s(0x%p)\\n\", __FUNCTION__, tx);\n  /*ret = stm_validate(tx);*/\n  return 1 /*ret*/;\n}\n\nint STM_CommitTransaction(stm_tx_t *tx)\n{\n  int ret;\n  PRINT_DEBUG(\"==> %s(tx=0x%p)\\n\", __FUNCTION__, tx);\n  ret = stm_commit_tx(tx);\n  /* Returned value are : Abort no retry=-1 / Abort retry=0 / Committed no retry=1 */\n  return ret;\n}\n\n/* API uses many steps: acquisition, then transactional read\n * to apply this to tinySTM it requires to split stm_load function in many pieces */\n\ntypedef void * RdHandle;\ntypedef void * WrHandle;\n\nRdHandle *STM_AcquireReadPermission(stm_tx_t *tx, stm_word_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,addr=0x%p,valid=%d)\\n\", tx, addr, valid);\n  return NULL;\n}\n\nWrHandle *STM_AcquireWritePermission(stm_tx_t *tx, stm_word_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,addr=0x%p,valid=%d)\\n\", tx, addr, valid);\n  return NULL;\n}\n\nWrHandle* STM_AcquireReadWritePermission(stm_tx_t *tx, stm_word_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, addr, valid);\n  return NULL;\n}\n\n\n/* Transactional loads */\n\nuint8_t STM_TranRead8(stm_tx_t *tx, RdHandle *theRdHandle, uint8_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, theRdHandle, addr, valid);\n  return stm_load_u8(/*tx,*/ addr);\n}\n\nuint16_t STM_TranRead16(stm_tx_t *tx, RdHandle *theRdHandle, uint16_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, theRdHandle, addr, valid);\n  return stm_load_u16(/*tx,*/ addr);\n}\n\nuint32_t STM_TranRead32(stm_tx_t *tx, RdHandle *theRdHandle, uint32_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, theRdHandle, addr, valid);\n  /* TODO can it be more efficient with #ifdef _LP64 and stm_load(). */\n  return stm_load_u32(/*tx,*/ addr);\n}\n\ndouble STM_TranReadFloat32(stm_tx_t *tx, RdHandle *theRdHandle, float *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, theRdHandle, addr, valid);\n  return stm_load_float(/*tx,*/ addr);\n}\n\nuint64_t STM_TranRead64(stm_tx_t *tx, RdHandle *theRdHandle, uint64_t *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, theRdHandle, addr, valid);\n  return stm_load_u64(/*tx,*/ addr);\n}\n\ndouble STM_TranReadFloat64(stm_tx_t *tx, RdHandle *theRdHandle, double *addr, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,valid=%d)\\n\", __FUNCTION__, tx, theRdHandle, addr, valid);\n  return stm_load_double(/*tx,*/ addr);\n}\n\n\n/* Transactional stores */\n\nint STM_TranWrite8(stm_tx_t *tx, WrHandle* theWrHandle, uint8_t *addr,  uint8_t val, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,val=%u,valid=%d)\\n\", __FUNCTION__, tx, theWrHandle, addr, val, valid);\n  stm_store_u8(/*tx,*/ addr, val);\n  return 1;\n}\nint STM_TranWrite16(stm_tx_t *tx, WrHandle* theWrHandle, uint16_t *addr, uint16_t val, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,val=%u,valid=%d)\\n\", __FUNCTION__, tx, theWrHandle, addr, val, valid);\n  stm_store_u16(/*tx,*/ addr, val);\n  return 1;\n}\n\nint STM_TranWrite32(stm_tx_t *tx, WrHandle *theWrHandle, uint32_t *addr, uint32_t val, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,val=%u,valid=%d)\\n\", __FUNCTION__, tx, theWrHandle, addr, val, valid);\n  stm_store_u32(/*tx,*/ addr, val);\n  return 1;\n}\n\nint STM_TranWrite64(stm_tx_t *tx, WrHandle *theWrHandle, uint64_t *addr, uint64_t val, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,val=%lu,valid=%d)\\n\", __FUNCTION__, tx, theWrHandle, addr, val, valid);\n  stm_store_u64(/*tx,*/ addr, val);\n  return 1;\n}\n\nint STM_TranWriteFloat32(stm_tx_t *tx, WrHandle *theWrHandle, float *addr, float val, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,val=%f,valid=%d)\\n\", __FUNCTION__, tx, theWrHandle, addr, val, valid);\n  stm_store_float(/*tx,*/ addr, val);\n  return 1;\n}\n\nint STM_TranWriteFloat64(stm_tx_t *tx, WrHandle *theWrHandle, double *addr, double val, int valid)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,handle=0x%p,addr=0x%p,val=%f,valid=%d)\\n\", __FUNCTION__, tx, theWrHandle, addr, val, valid);\n  stm_store_double(/*tx,*/ addr, val);\n  return 1;\n}\n\n\n/* Transactional memory management */\n\nvoid *STM_TranMalloc(stm_tx_t *tx, size_t sz)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,size=%d)\\n\", __FUNCTION__, tx, sz);\n  return stm_malloc_tx(tx, sz);\n}\n\nvoid *STM_TranCalloc(stm_tx_t *tx, size_t elem, size_t sz)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,elem=%d,size=%d)\\n\", __FUNCTION__, tx, elem, sz);\n  return stm_calloc_tx(tx, elem, sz);\n}\n\nvoid STM_TranMFree(stm_tx_t *tx, void *addr)\n{\n  PRINT_DEBUG(\"==> %s(tx=0x%p,addr=%p)\\n\", __FUNCTION__, tx, addr);\n  /* TODO: guess the size... use as in itm block_size(ptr)? is it available in Solaris? */\n  stm_free_tx(tx, addr, sizeof(stm_word_t));\n}\n\nvoid *STM_TranMemAlign(stm_tx_t *tx, size_t alignment, size_t sz)\n{\n  assert(0);\n  return NULL;\n}\n\nvoid *STM_TranValloc(stm_tx_t *tx, size_t sz)\n{\n  assert(0);\n  return NULL;\n}\n\n/* TODO check if sz is size_t? same for alignment? */\nvoid STM_TranMemCpy(stm_tx_t *tx, void* src, void* dst, size_t sz, uint32_t alignment)\n{\n  /* TODO what to do with alignment? */\n  uint8_t *buf = (uint8_t *)alloca(sz);\n  stm_load_bytes(/*tx,*/ (volatile uint8_t *)src, buf, sz);\n  stm_store_bytes(/*tx,*/ (volatile uint8_t *)dst, buf, sz);\n}\n\nint STM_CurrentlyUsingDecoratedPath(stm_tx_t* tx)\n{\n  if (tx == NULL)\n    return 0;\n  /* TODO check that the nesting is != 0 */\n  return 1; \n}\n\n\n"
  },
  {
    "path": "stms/tinystm/abi/pthread_wrapper.h",
    "content": "/*\n * File:\n *   pthread_wrapper.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Pthread wrapper to handle thread creation.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <dlfcn.h> \n\n/* Original pthread function */\nstatic int (*pthread_create_orig)(pthread_t *__restrict,\n                                  __const pthread_attr_t *__restrict,\n                                  void *(*)(void *),\n                                  void *__restrict) = NULL; \n\ntypedef struct {\n  void * (*start_routine)(void *);\n  void * arg;\n} wrapper_t; \n\nstatic void * wpthread_create(void * data)\n{\n  void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine;\n  void * arg = ((wrapper_t*)data)->arg; \n  void * ret;\n  /* Free the allocated memory by the wrapper */\n  free(data);\n  /* Initialize thread */\n  _ITM_initializeThread();\n  /* Call user function */\n  ret = start_routine(arg);\n  /* Finalizing thread */\n  _ITM_finalizeThread();\n  return ret;\n}\n\nint pthread_create(pthread_t *__restrict thread,\n                   __const pthread_attr_t *__restrict attr,\n                   void * (*start_routine)(void *),\n                   void *__restrict arg)\n{ \n  int i_return;\n  /* Allocate memory to pass as argument (we can't assume that stack will not be modified) */\n  wrapper_t * wdata = malloc(sizeof(wrapper_t));\n  wdata->start_routine = start_routine;\n  wdata->arg = arg;\n  /* Solving link to original pthread_create */\n  if (pthread_create_orig == NULL) {\n    pthread_create_orig = dlsym(RTLD_NEXT, \"pthread_create\");\n    if (pthread_create_orig == NULL) {\n      char *error = dlerror();\n      if (error == NULL) {\n        error = \"pthread_create can't be solved.\";\n      }  \n      fprintf(stderr, \"%s\\n\", error);\n      exit(EXIT_FAILURE);\n    }\n  }\n  /* Call original pthread function */\n  i_return = pthread_create_orig(thread, attr, wpthread_create, wdata);\n  return i_return;\n}\n"
  },
  {
    "path": "stms/tinystm/abi/test/Makefile",
    "content": "# Path to TinySTM\nROOT = ../..\n\n.PHONY:\tgcc all clean test check\n\nall:\tgcc\n\n# ROOT must be defined to include Makefile.common\ninclude $(ROOT)/abi/Makefile.common\n\n##############################################################################\n## GCC\n##############################################################################\n# TODO Currently it is a copy of GCC-TM Makefile but I didn't find a best way\n# to do that until now\nCPPFLAGS += -DTM_GCC -I../gcc\n\n# NOTES\n#   lib.map enables to export only some functions\ngcc: \tlibitm.so libitm.a \n\narch.o: ../gcc/arch.S\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.do: \t../%.c \n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\n%.o: \t../%.c \n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEF_ABI) -c -o $@ $<\n\nlibitm.a: abi.o arch.o \n\t$(AR) cru $@ $^\n\nlibitm.so: \tabi.do arch.o \n\t$(CC) -fPIC $(CPPFLAGS) $(CFLAGS) -shared -Wl,--version-script,../lib.map -o $@ $^\n# TODO Check if strip is really needed\n#\tstrip $@\n#\tcp libitm.so libitm.so.1\n#\tln -s libitm.so libitm.so.1\n#TODO for FAT filesystem, ln doesn't work\n##############################################################################\n\nTESTCC       ?= gcc\nTESTCFLAGS   += -Wall -O2 -march=native -DTM_ABI -I../gcc/ -DTLS \nTESTLD       ?= gcc\nTESTLDFLAGS  += -Wl,-rpath=$(shell pwd)\nTESTLDFLAGS  += -L$(shell pwd) \n# TESTLDFLAGS  += libitm.a\n# FIXME: see why big perf degradation with shared library\nTESTLDFLAGS  += -litm\n\nclean: \tintset-clean\n\trm -f *.o *.do libitm.a libitm.so\n\n"
  },
  {
    "path": "stms/tinystm/abi/tm_macros.h",
    "content": "/*\n * File:\n *   tm_macros.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Defines macros for transactional operations.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _TM_MACROS_H_\n# define _TM_MACROS_H_\n/* Compile with explicit calls to ITM library */\n# include <bits/wordsize.h>\n# include \"libitm.h\"\n\n/* Define TM_MACROS */\n# ifdef EXPLICIT_TX_PARAMETER\n#  define TXARG                         __td\n#  define TXARGS                        __td,\n#  define TM_START(id, ro)              { _ITM_transaction* __td = _ITM_getTransaction(); \\\n                                          _ITM_beginTransaction(TXARGS ro == RO ? pr_readOnly | pr_instrumentedCode : pr_instrumentedCode, NULL);\n# else\n#  define TXARG\n#  define TXARGS\n#  define TM_START(id, ro)              { _ITM_beginTransaction(ro == RO ? pr_readOnly | pr_instrumentedCode : pr_instrumentedCode, NULL);\n# endif\n// TODO check if __LP64__ is better?\n# if __WORDSIZE == 64\n#  define TM_LOAD(addr)                 _ITM_RU8(TXARGS (uint64_t *)addr)\n#  define TM_STORE(addr, value)         _ITM_WU8(TXARGS (uint64_t *)addr, (uint64_t)value)\n# else /* __WORDSIZE == 32 */\n#  define TM_LOAD(addr)                 _ITM_RU4(TXARGS (uint32_t *)addr)\n#  define TM_STORE(addr, value)         _ITM_WU4(TXARGS (uint32_t *)addr, (uint32_t)value)\n# endif /* __WORDSIZE == 32 */\n# define TM_COMMIT                      _ITM_commitTransaction(TXARGS); }\n/* TODO Wrong for Intel */\n# define TM_MALLOC(size)                _ITM_malloc(TXARGS size)\n# define TM_FREE(addr)                  _ITM_free(TXARGS addr)\n# define TM_FREE2(addr, size)           _ITM_free(TXARGS addr)\n\n# define TM_INIT                        _ITM_initializeProcess()\n# define TM_EXIT                        _ITM_finalizeProcess()\n# define TM_INIT_THREAD                 _ITM_initializeThread()\n# define TM_EXIT_THREAD                 _ITM_finalizeThread()\n\n/* Annotations used in this benchmark */\n# define TM_SAFE\n# define TM_PURE\n\n#endif /* _TM_MACROS_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/include/mod_ab.h",
    "content": "/*\n * File:\n *   mod_ab.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for gathering statistics about atomic blocks.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module for gathering statistics about transactions.  This module\n *   maintains aggregate statistics about all threads for every atomic\n *   block in the application (distinguished using the identifier part\n *   of the transaction attributes).\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_AB_H_\n# define _MOD_AB_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Statistics associated with an atomic block.\n */\ntypedef struct stm_ab_stats {\n  /**\n   * Number of samples collected.\n   */\n  unsigned long samples;\n  /**\n   * Arithmetic mean of the samples.\n   */\n  double mean;\n  /**\n   * Variance of the samples.\n   */\n  double variance;\n  /**\n   * Minimum value among all samples.\n   */\n  double min;\n  /**\n   * Maximum value among all samples.\n   */\n  double max;\n  /**\n   * 75th percentile (median).\n   */\n  double percentile_50;\n  /**\n   * 90th percentile.\n   */\n  double percentile_90;\n  /**\n   * 95th percentile.\n   */\n  double percentile_95;\n  /**\n   * Sorted ramdom subset of the samples (Vitter's reservoir).\n   */\n  double *reservoir;\n  /**\n   * Number of smaples in the reservoir.\n   */\n  unsigned int reservoir_size;\n} stm_ab_stats_t;\n\n/**\n * Get statistics about an atomic block.\n *\n * @param id\n *   Identifier of the atomic block (as specified in transaction\n *   attributes).\n * @param stats\n *   Pointer to the variable to should hold the statistics of the atomic\n *   block.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_ab_stats(int id, stm_ab_stats_t *stats);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n *\n * @param freq\n *   Inverse sampling frequency (1 to keep all samples).\n * @param check\n *   Pointer to a function that will be called to check if a sample is\n *   valid and should be kept.  The event will be discarded if and only\n *   if the function returns 0.  If no function is provided, all samples\n *   will be kept.\n */\nvoid mod_ab_init(int freq, int (*check)(void));\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_AB_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/mod_cb.h",
    "content": "/*\n * File:\n *   mod_cb.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for user callbacks.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module for user callbacks.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_CB_H_\n# define _MOD_CB_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Register an application-specific callback triggered when the current\n * transaction commits.  The callback is automatically unregistered once\n * the transaction commits or aborts.  If the transaction aborts, the\n * callback is never triggered.\n *\n * @param on_commit\n *   Function called upon successful transaction commit.\n * @param arg\n *   Parameter to be passed to the callback function.\n * @return\n *   1 if the callbacks have been successfully registered, 0 otherwise.\n */\nint stm_on_commit(void (*on_commit)(void *arg), void *arg);\n\n/**\n * Register an application-specific callback triggered when the current\n * transaction aborts.  The callback is automatically unregistered once\n * the transaction commits or aborts.  If the transaction commits, the\n * callback is never triggered.\n *\n * @param on_abort\n *   Function called upon transaction abort.\n * @param arg\n *   Parameter to be passed to the callback function.\n * @return\n *   1 if the callbacks have been successfully registered, 0 otherwise.\n */\nint stm_on_abort(void (*on_abort)(void *arg), void *arg);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n *\n */\nvoid mod_cb_init(void);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_CB_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/mod_log.h",
    "content": "/*\n * File:\n *   mod_log.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for logging memory accesses.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module for logging memory accesses.  Data is stored in an undo log.\n *   Upon abort, modifications are reverted.  Note that this module\n *   should not be used for updating shared data as there are no\n *   mechanisms to deal with concurrent accesses.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_LOG_H_\n# define _MOD_LOG_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Log word-sized value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log(stm_word_t *addr);\n\n/**\n * Log char 8-bit value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_u8(uint8_t *addr);\n\n/**\n * Log char 16-bit value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_u16(uint16_t *addr);\n\n/**\n * Log char 32-bit value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_u32(uint32_t *addr);\n\n/**\n * Log char 64-bit value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_u64(uint64_t *addr);\n\n/**\n * Log char value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_char(char *addr);\n\n/**\n * Log unsigned char value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_uchar(unsigned char *addr);\n\n/**\n * Log short value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_short(short *addr);\n\n/**\n * Log unsigned short value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_ushort(unsigned short *addr);\n\n/**\n * Log int value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_int(int *addr);\n\n/**\n * Log unsigned int value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_uint(unsigned int *addr);\n\n/**\n * Log long value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_long(long *addr);\n\n/**\n * Log unsigned long value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_ulong(unsigned long *addr);\n\n/**\n * Log float value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_float(float *addr);\n\n/**\n * Log double value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_double(double *addr);\n\n/**\n * Log pointer value in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n */\nvoid stm_log_ptr(void **addr);\n\n/**\n * Log memory region in transaction log.\n *\n * @param addr\n *   Address of the memory location.\n * @param size\n *   Number of bytes to log.\n */\nvoid stm_log_bytes(uint8_t *addr, size_t size);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before performing\n * any transactional operation.\n */\nvoid mod_log_init(void);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_LOG_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/mod_mem.h",
    "content": "/*\n * File:\n *   mod_mem.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for dynamic memory management.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module for dynamic memory management.  This module provides\n *   functions for allocations and freeing memory inside transactions.\n *   A block allocated inside the transaction will be implicitly freed\n *   upon abort, and a block freed inside a transaction will only be\n *   returned to the system upon commit.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_MEM_H_\n# define _MOD_MEM_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n//@{\n/**\n * Allocate memory from inside a transaction.  Allocated memory is\n * implicitly freed upon abort.\n *\n * @param size\n *   Number of bytes to allocate.\n * @return\n *   Pointer to the allocated memory block.\n */\nvoid *stm_malloc(size_t size);\nvoid *stm_malloc_tx(struct stm_tx *tx, size_t size);\n//@}\n\n//@{\n/**\n * Allocate initialized memory from inside a transaction.  Allocated\n * memory is implicitly freed upon abort.\n *\n * @param nm\n *   Size of the array to allocate.\n * @param size\n *   Number of bytes to allocate.\n * @return\n *   Pointer to the allocated memory block.\n */\nvoid *stm_calloc(size_t nm, size_t size);\nvoid *stm_calloc_tx(struct stm_tx *tx, size_t nm, size_t size);\n//@}\n\n//@{\n/**\n * Free memory from inside a transaction.  Freed memory is only returned\n * to the system upon commit and can optionally be overwritten (more\n * precisely, the locks protecting the memory are acquired) to prevent\n * another transaction from accessing the freed memory and observe\n * inconsistent states.\n *\n * @param addr\n *   Address of the memory block.\n * @param size\n *   Number of bytes to overwrite.\n */\nvoid stm_free(void *addr, size_t size);\nvoid stm_free_tx(struct stm_tx *tx, void *addr, size_t size);\n//@}\n\n//@{\n/**\n * Free memory from inside a transaction.  Freed memory is only returned\n * to the system upon commit and can optionally be overwritten (more\n * precisely, the locks protecting the memory are acquired) to prevent\n * another transaction from accessing the freed memory and observe\n * inconsistent states.\n *\n * @param addr\n *   Address of the memory block.\n * @param idx\n *   Index of the first byte to overwrite.\n * @param size\n *   Number of bytes to overwrite.\n */\nvoid stm_free2(void *addr, size_t idx, size_t size);\nvoid stm_free2_tx(struct stm_tx *tx, void *addr, size_t idx, size_t size);\n//@}\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n *\n * @param gc\n *   True (non-zero) to enable epoch-based garbage collector when\n *   freeing memory in transactions.\n */\nvoid mod_mem_init(int gc);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_MEM_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/mod_order.h",
    "content": "/*\n * File:\n *   mod_order.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module to force transactions to commit in order.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module to force transactions to commit in order. The first transaction that\n *   starts will be the first one to commit. This module requires CM_MODULAR.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_PRINT_H_\n# define _MOD_PRINT_H_\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_order_init(void);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_PRINT_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/mod_print.h",
    "content": "/*\n * File:\n *   mod_print.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module to test callbacks.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module to test callbacks.  This module simply prints a message at\n *   each invocation of a callback.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_PRINT_H_\n# define _MOD_PRINT_H_\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_print_init(void);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_PRINT_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/mod_stats.h",
    "content": "/*\n * File:\n *   mod_stats.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for gathering statistics about transactions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   Module for gathering statistics about transactions.  This module\n *   maintains both aggregate statistics about all threads (aggregates\n *   are updated upon thread cleanup) and per-thread statistics.  The\n *   built-in statistics of the core STM library are more efficient and\n *   detailed but this module is useful in case the library is compiled\n *   without support for statistics.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _MOD_STATS_H_\n# define _MOD_STATS_H_\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Get various statistics about the transactions of all threads.  See\n * the source code (mod_stats.c) for a list of supported statistics.\n *\n * @param name\n *   Name of the statistics.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   statistics.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_global_stats(const char *name, void *val);\n\n/**\n * Get various statistics about the transactions of the current thread.\n * See the source code (mod_stats.c) for a list of supported statistics.\n *\n * @param name\n *   Name of the statistics.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   statistics.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_local_stats(const char *name, void *val);\n\n/**\n * Initialize the module.  This function must be called once, from the\n * main thread, after initializing the STM library and before\n * performing any transactional operation.\n */\nvoid mod_stats_init(void);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _MOD_STATS_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/stm.h",
    "content": "/*\n * File:\n *   stm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM functions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   STM functions.  This library contains the core functions for\n *   programming with STM.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n/**\n * @mainpage TinySTM\n *\n * @section overview_sec Overview\n *\n *   TinySTM is a lightweight but efficient word-based STM\n *   implementation.  This distribution includes three versions of\n *   TinySTM: write-back (updates are buffered until commit time),\n *   write-through (updates are directly written to memory), and\n *   commit-time locking (locks are only acquired upon commit).  The\n *   version can be selected by editing the makefile, which documents\n *   all the different compilation options.\n *\n *   TinySTM compiles and runs on 32 or 64-bit architectures.  It was\n *   tested on various flavors of Unix, on Mac OS X, and on Windows\n *   using cygwin.  It comes with a few test applications, notably a\n *   linked list, a skip list, and a red-black tree.\n *\n * @section install_sec Installation\n *\n *   TinySTM requires the atomic_ops library, freely available from\n *   http://www.hpl.hp.com/research/linux/atomic_ops/.  A stripped-down\n *   version of the library is included in the TinySTM distribution.  If you\n *   wish to use another version, you must set the environment variable\n *   <c>LIBAO_HOME</c> to the installation directory of atomic_ops.\n *\n *   If your system does not support GCC thread-local storage, set the\n *   variable <c>TLS</c> to TLS_POSIX value into the Makefile.common.\n *\n *   To compile TinySTM libraries, execute <c>make</c> in the main\n *   directory.  To compile test applications, execute <c>make test</c>.\n *\n * @section contact_sec Contact\n *\n *   - E-mail : tinystm@tinystm.org\n *   - Web    : http://tinystm.org\n */\n\n#ifndef _STM_H_\n# define _STM_H_\n\n# include <setjmp.h>\n# include <stdint.h>\n# include <stdio.h>\n# include <stdlib.h>\n\n/**\n * Version string\n */\n# define STM_VERSION                    \"1.0.6\"\n/**\n * Version number (times 100)\n */\n# define STM_VERSION_NB                 106\n\n/**\n * Calling convention\n */\n# ifdef __i386__\n/* The fastcall calling convention improves performance on old ia32\n * architecture that does not implement store forwarding.\n * regparm(3) does not improve significantly the performance. */\n#  define _CALLCONV                     __attribute__((fastcall))\n# else\n#  define _CALLCONV\n# endif /* __i386__ */\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\nstruct stm_tx;\n/**\n * Return the current transaction descriptor.\n * The library does not require to pass the current transaction as a\n * parameter to the functions (the current transaction is stored in a\n * thread-local variable).  One can, however, use the library with\n * explicit transaction parameters.  This is useful, for instance, for\n * performance on architectures that do not support TLS or for easier\n * compiler integration.\n */\nstruct stm_tx *stm_current_tx(void) _CALLCONV;\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\n/**\n * Size of a word (accessible atomically) on the target architecture.\n * The library supports 32-bit and 64-bit architectures.\n */\ntypedef uintptr_t stm_word_t;\n\n/**\n * Transaction attributes specified by the application.\n */\ntypedef union stm_tx_attr {\n  struct {\n  /**\n   * Application-specific identifier for the transaction.  Typically,\n   * each transactional construct (atomic block) should have a different\n   * identifier.  This identifier can be used by the infrastructure for\n   * improving performance, for instance by not scheduling together\n   * atomic blocks that have conflicted often in the past.\n   */\n  unsigned int id : 16;\n  /**\n   * Indicates whether the transaction is read-only.  This information\n   * is used as a hint.  If a read-only transaction performs a write, it\n   * is aborted and restarted in read-write mode.  In that case, the\n   * value of the read-only flag is changed to false.  If no attributes\n   * are specified when starting a transaction, it is assumed to be\n   * read-write.\n   */\n  unsigned int read_only : 1;\n  /**\n   * Indicates whether the transaction should use visible reads.  This\n   * information is used when the transaction starts or restarts.  If a\n   * transaction automatically switches to visible read mode (e.g.,\n   * after having repeatedly aborted with invisible reads), this flag is\n   * updated accordingly.  If no attributes are specified when starting\n   * a transaction, the default behavior is to use invisible reads.\n   */\n  unsigned int visible_reads : 1;\n  /**\n   * Indicates that the transaction should not retry execution using\n   * sigsetjmp() after abort.  If no attributes are specified when\n   * starting a transaction, the default behavior is to retry.\n   */\n  unsigned int no_retry : 1;\n  /**\n   * Indicates that the transaction cannot use the snapshot extension\n   * mechanism. (Working only with UNIT_TX)\n   */\n  unsigned int no_extend : 1;\n  /**\n   * Indicates that the transaction is irrevocable.\n   * 1 is simple irrevocable and 3 is serial irrevocable.\n   * (Working only with IRREVOCABLE_ENABLED)\n   * TODO Not yet implemented\n   */\n  /* unsigned int irrevocable : 2; */\n  };\n  /**\n   * All transaction attributes represented as one integer.\n   * For convenience, allow (stm_tx_attr_t)0 cast.\n   */\n  int32_t attrs;\n} stm_tx_attr_t;\n\n/**\n * Reason for aborting (returned by sigsetjmp() upon transaction\n * restart).\n */\nenum {\n  /**\n   * Indicates that the instrumented code path must be executed.\n   */\n  STM_PATH_INSTRUMENTED = 0x01,\n  /**\n   * Indicates that the uninstrumented code path must be executed\n   * (serial irrevocable mode).\n   */\n  STM_PATH_UNINSTRUMENTED = 0x02,\n  /**\n   * Abort due to explicit call from the programmer.\n   */\n  STM_ABORT_EXPLICIT = (1 << 5),\n  /**\n   * Abort and no retry due to explicit call from the programmer.\n   */\n  STM_ABORT_NO_RETRY = (1 << 5) | (0x01 << 8),\n  /**\n   * Implicit abort (high order bits indicate more detailed reason).\n   */\n  STM_ABORT_IMPLICIT = (1 << 6),\n  /**\n   * Abort upon reading a memory location being read by another\n   * transaction.\n   */\n  STM_ABORT_RR_CONFLICT = (1 << 6) | (0x01 << 8),\n  /**\n   * Abort upon writing a memory location being read by another\n   * transaction.\n   */\n  STM_ABORT_RW_CONFLICT = (1 << 6) | (0x02 << 8),\n  /**\n   * Abort upon reading a memory location being written by another\n   * transaction.\n   */\n  STM_ABORT_WR_CONFLICT = (1 << 6) | (0x03 << 8),\n  /**\n   * Abort upon writing a memory location being written by another\n   * transaction.\n   */\n  STM_ABORT_WW_CONFLICT = (1 << 6) | (0x04 << 8),\n  /**\n   * Abort upon read due to failed validation.\n   */\n  STM_ABORT_VAL_READ = (1 << 6) | (0x05 << 8),\n  /**\n   * Abort upon write due to failed validation.\n   */\n  STM_ABORT_VAL_WRITE = (1 << 6) | (0x06 << 8),\n  /**\n   * Abort upon commit due to failed validation.\n   */\n  STM_ABORT_VALIDATE = (1 << 6) | (0x07 << 8),\n  /**\n   * Abort upon deferring to an irrevocable transaction.\n   */\n  STM_ABORT_IRREVOCABLE = (1 << 6) | (0x09 << 8),\n  /**\n   * Abort due to being killed by another transaction.\n   */\n  STM_ABORT_KILLED = (1 << 6) | (0x0A << 8),\n  /**\n   * Abort due to receiving a signal.\n   */\n  STM_ABORT_SIGNAL = (1 << 6) | (0x0B << 8),\n  /**\n   * Abort due to reaching the write set size limit.\n   */\n  STM_ABORT_EXTEND_WS = (1 << 6) | (0x0C << 8),\n  /**\n   * Abort due to other reasons (internal to the protocol).\n   */\n  STM_ABORT_OTHER = (1 << 6) | (0x0F << 8)\n};\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/**\n * Initialize the STM library.  This function must be called once, from\n * the main thread, before any access to the other functions of the\n * library.\n */\nvoid stm_init(void) _CALLCONV;\n\n/**\n * Clean up the STM library.  This function must be called once, from\n * the main thread, after all transactional threads have completed.\n */\nvoid stm_exit(void) _CALLCONV;\n\n/**\n * Initialize a transactional thread.  This function must be called once\n * from each thread that performs transactional operations, before the\n * thread calls any other functions of the library.\n */\nstruct stm_tx *stm_init_thread(void) _CALLCONV;\n\n//@{\n/**\n * Clean up a transactional thread.  This function must be called once\n * from each thread that performs transactional operations, upon exit.\n */\nvoid stm_exit_thread(void) _CALLCONV;\nvoid stm_exit_thread_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Start a transaction.\n *\n * @param attr\n *   Specifies optional attributes associated to the transaction.\n *   Attributes are copied in transaction-local storage.  If null, the\n *   transaction uses default attributes.\n * @return\n *   Environment (stack context) to be used to jump back upon abort.  It\n *   is the responsibility of the application to call sigsetjmp()\n *   immediately after starting the transaction.  If the transaction is\n *   nested, the function returns NULL and one should not call\n *   sigsetjmp() as an abort will restart the top-level transaction\n *   (flat nesting).\n */\nsigjmp_buf *stm_start(stm_tx_attr_t attr) _CALLCONV;\nsigjmp_buf *stm_start_tx(struct stm_tx *tx, stm_tx_attr_t attr) _CALLCONV;\n//@}\n\n//@{\n/**\n * Try to commit a transaction.  If successful, the function returns 1.\n * Otherwise, execution continues at the point where sigsetjmp() has\n * been called after starting the outermost transaction (unless the\n * attributes indicate that the transaction should not retry).\n *\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_commit(void) _CALLCONV;\nint stm_commit_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Explicitly abort a transaction.  Execution continues at the point\n * where sigsetjmp() has been called after starting the outermost\n * transaction (unless the attributes indicate that the transaction\n * should not retry).\n *\n * @param abort_reason\n *   Reason for aborting the transaction.\n */\nvoid stm_abort(int abort_reason) _CALLCONV;\nvoid stm_abort_tx(struct stm_tx *tx, int abort_reason) _CALLCONV;\n//@}\n\n//@{\n/**\n * Transactional load.  Read the specified memory location in the\n * context of the current transaction and return its value.  Upon\n * conflict, the transaction may abort while reading the memory\n * location.  Note that the value returned is consistent with respect to\n * previous reads from the same transaction.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nstm_word_t stm_load(volatile stm_word_t *addr) _CALLCONV;\nstm_word_t stm_load_tx(struct stm_tx *tx, volatile stm_word_t *addr) _CALLCONV;\n//@}\n\n//@{\n/**\n * Transactional store.  Write a word-sized value to the specified\n * memory location in the context of the current transaction.  Upon\n * conflict, the transaction may abort while writing to the memory\n * location.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store(volatile stm_word_t *addr, stm_word_t value) _CALLCONV;\nvoid stm_store_tx(struct stm_tx *tx, volatile stm_word_t *addr, stm_word_t value) _CALLCONV;\n//@}\n\n//@{\n/**\n * Transactional store.  Write a value to the specified memory location\n * in the context of the current transaction.  The value may be smaller\n * than a word on the target architecture, in which case a mask is used\n * to indicate the bits of the words that must be updated.  Upon\n * conflict, the transaction may abort while writing to the memory\n * location.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n * @param mask\n *   Mask specifying the bits to be written.\n */\nvoid stm_store2(volatile stm_word_t *addr, stm_word_t value, stm_word_t mask) _CALLCONV;\nvoid stm_store2_tx(struct stm_tx *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask) _CALLCONV;\n//@}\n\n//@{\n/**\n * Check if the current transaction is still active.\n *\n * @return\n *   True (non-zero) if the transaction is active, false (zero) otherwise.\n */\nint stm_active(void) _CALLCONV;\nint stm_active_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Check if the current transaction has aborted.\n *\n * @return\n *   True (non-zero) if the transaction has aborted, false (zero) otherwise.\n */\nint stm_aborted(void) _CALLCONV;\nint stm_aborted_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Check if the current transaction is still active and in irrevocable\n * state.\n *\n * @return\n *   True (non-zero) if the transaction is active and irrevocable, false\n *   (zero) otherwise.\n */\nint stm_irrevocable(void) _CALLCONV;\nint stm_irrevocable_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Check if the current transaction has been killed.\n *\n * @return\n *   True (non-zero) if the transaction has been killed, false (zero) otherwise.\n */\nint stm_killed(void) _CALLCONV;\nint stm_killed_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Get the environment used by the current thread to jump back upon\n * abort.  This environment should be used when calling sigsetjmp()\n * before starting the transaction and passed as parameter to\n * stm_start().  If the current thread is already executing a\n * transaction, i.e., the new transaction will be nested, the function\n * returns NULL and one should not call sigsetjmp().\n *\n * @return\n *   The environment to use for saving the stack context, or NULL if the\n *   transaction is nested.\n */\nsigjmp_buf *stm_get_env(void) _CALLCONV;\nsigjmp_buf *stm_get_env_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Get attributes associated with the current transactions, if any.\n * These attributes were passed as parameters when starting the\n * transaction.\n *\n * @return Attributes associated with the current transaction, or NULL\n *   if no attributes were specified when starting the transaction.\n */\nstm_tx_attr_t stm_get_attributes(void) _CALLCONV;\nstm_tx_attr_t stm_get_attributes_tx(struct stm_tx *tx) _CALLCONV;\n//@}\n\n//@{\n/**\n * Get various statistics about the current thread/transaction.  See the\n * source code (stm.c) for a list of supported statistics.\n *\n * @param name\n *   Name of the statistics.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   statistics.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_stats(const char *name, void *val) _CALLCONV;\nint stm_get_stats_tx(struct stm_tx *tx, const char *name, void *val) _CALLCONV;\n//@}\n\n/**\n * Get various parameters of the STM library.  See the source code\n * (stm.c) for a list of supported parameters.\n *\n * @param name\n *   Name of the parameter.\n * @param val\n *   Pointer to the variable that should hold the value of the\n *   parameter.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_get_parameter(const char *name, void *val) _CALLCONV;\n\n/**\n * Set various parameters of the STM library.  See the source code\n * (stm.c) for a list of supported parameters.\n *\n * @param name\n *   Name of the parameter.\n * @param val\n *   Pointer to a variable that holds the new value of the parameter.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_set_parameter(const char *name, void *val) _CALLCONV;\n\n/**\n * Create a key to associate application-specific data to the current\n * thread/transaction.  This mechanism can be combined with callbacks to\n * write modules.\n *\n * @return\n *   The new key.\n */\nint stm_create_specific(void) _CALLCONV;\n\n//@{\n/**\n * Get application-specific data associated to the current\n * thread/transaction and a given key.\n *\n * @param key\n *   Key designating the data to read.\n * @return\n *   Data stored under the given key.\n */\nvoid *stm_get_specific(int key) _CALLCONV;\nvoid *stm_get_specific_tx(struct stm_tx *tx, int key) _CALLCONV;\n//@}\n\n//@{\n/**\n * Set application-specific data associated to the current\n * thread/transaction and a given key.\n *\n * @param key\n *   Key designating the data to read.\n * @param data\n *   Data to store under the given key.\n */\nvoid stm_set_specific(int key, void *data) _CALLCONV;\nvoid stm_set_specific_tx(struct stm_tx *tx, int key, void *data) _CALLCONV;\n//@}\n\n/**\n * Register application-specific callbacks that are triggered each time\n * particular events occur.\n *\n * @param on_thread_init\n *   Function called upon initialization of a transactional thread.\n * @param on_thread_exit\n *   Function called upon cleanup of a transactional thread.\n * @param on_start\n *   Function called upon start of a transaction.\n * @param on_precommit\n *   Function called before transaction try to commit.\n * @param on_commit\n *   Function called upon successful transaction commit.\n * @param on_abort\n *   Function called upon transaction abort.\n * @param arg\n *   Parameter to be passed to the callback functions.\n * @return\n *   1 if the callbacks have been successfully registered, 0 otherwise.\n */\nint stm_register(void (*on_thread_init)(void *arg),\n                 void (*on_thread_exit)(void *arg),\n                 void (*on_start)(void *arg),\n                 void (*on_precommit)(void *arg),\n                 void (*on_commit)(void *arg),\n                 void (*on_abort)(void *arg),\n                 void *arg) _CALLCONV;\n\n/**\n * Transaction-safe load.  Read the specified memory location outside of\n * the context of any transaction and return its value.  The operation\n * behaves as if executed in the context of a dedicated transaction\n * (i.e., it executes atomically and in isolation) that never aborts,\n * but may get delayed.\n *\n * @param addr Address of the memory location.\n\n * @param timestamp If non-null, the referenced variable is updated to\n *   hold the timestamp of the memory location being read.\n * @return\n *   Value read from the specified address.\n */\nstm_word_t stm_unit_load(volatile stm_word_t *addr, stm_word_t *timestamp) _CALLCONV;\n\n/**\n * Transaction-safe store.  Write a word-sized value to the specified\n * memory location outside of the context of any transaction.  The\n * operation behaves as if executed in the context of a dedicated\n * transaction (i.e., it executes atomically and in isolation) that\n * never aborts, but may get delayed.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n * @param timestamp If non-null and the timestamp in the referenced\n *   variable is smaller than that of the memory location being written,\n *   no data is actually written and the variable is updated to hold the\n *   more recent timestamp. If non-null and the timestamp in the\n *   referenced variable is not smaller than that of the memory location\n *   being written, the memory location is written and the variable is\n *   updated to hold the new timestamp.\n * @return\n *   1 if value has been written, 0 otherwise.\n */\nint stm_unit_store(volatile stm_word_t *addr, stm_word_t value, stm_word_t *timestamp) _CALLCONV;\n\n/**\n * Transaction-safe store.  Write a value to the specified memory\n * location outside of the context of any transaction.  The value may be\n * smaller than a word on the target architecture, in which case a mask\n * is used to indicate the bits of the words that must be updated.  The\n * operation behaves as if executed in the context of a dedicated\n * transaction (i.e., it executes atomically and in isolation) that\n * never aborts, but may get delayed.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n * @param mask\n *   Mask specifying the bits to be written.\n * @param timestamp If non-null and the timestamp in the referenced\n *   variable is smaller than that of the memory location being written,\n *   no data is actually written and the variable is updated to hold the\n *   more recent timestamp. If non-null and the timestamp in the\n *   referenced variable is not smaller than that of the memory location\n *   being written, the memory location is written and the variable is\n *   updated to hold the new timestamp.\n * @return\n *   1 if value has been written, 0 otherwise.\n */\nint stm_unit_store2(volatile stm_word_t *addr, stm_word_t value, stm_word_t mask, stm_word_t *timestamp) _CALLCONV;\n\n//@{\n/**\n * Enable or disable snapshot extensions for the current transaction,\n * and optionally set an upper bound for the snapshot.  This function is\n * useful for implementing efficient algorithms with unit loads and\n * stores while preserving compatibility with with regular transactions.\n *\n * @param enable\n *   True (non-zero) to enable snapshot extensions, false (zero) to\n *   disable them.\n * @param timestamp\n *   If non-null and the timestamp in the referenced variable is smaller\n *   than the current upper bound of the snapshot, update the upper\n *   bound to the value of the referenced variable.\n */\nvoid stm_set_extension(int enable, stm_word_t *timestamp) _CALLCONV;\nvoid stm_set_extension_tx(struct stm_tx *tx, int enable, stm_word_t *timestamp) _CALLCONV;\n//@}\n\n/**\n * Read the current value of the global clock (used for timestamps).\n * This function is useful when programming with unit loads and stores.\n *\n * @return\n *   Value of the global clock.\n */\nstm_word_t stm_get_clock(void) _CALLCONV;\n\n//@{\n/**\n * Enter irrevocable mode for the current transaction.  If successful,\n * the function returns 1.  Otherwise, it aborts and execution continues\n * at the point where sigsetjmp() has been called after starting the\n * outermost transaction (unless the attributes indicate that the\n * transaction should not retry).\n *\n * @param serial\n *   True (non-zero) for serial-irrevocable mode (no transaction can\n *   execute concurrently), false for parallel-irrevocable mode.\n * @return\n *   1 upon success, 0 otherwise.\n */\nint stm_set_irrevocable(int serial) _CALLCONV;\nint stm_set_irrevocable_tx(struct stm_tx *tx, int serial) _CALLCONV;\n//@}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _STM_H_ */\n"
  },
  {
    "path": "stms/tinystm/include/wrappers.h",
    "content": "/*\n * File:\n *   wrappers.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM wrapper functions for different data types.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/**\n * @file\n *   STM wrapper functions for different data types.  This library\n *   defines transactional loads/store functions for unsigned data types\n *   of various sizes and for basic C data types.\n * @author\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * @date\n *   2007-2014\n */\n\n#ifndef _WRAPPERS_H_\n# define _WRAPPERS_H_\n\n# include <stdint.h>\n\n# include \"stm.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/**\n * Transactional load of an unsigned 8-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint8_t stm_load_u8(volatile uint8_t *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned 16-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint16_t stm_load_u16(volatile uint16_t *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned 32-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint32_t stm_load_u32(volatile uint32_t *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned 64-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nuint64_t stm_load_u64(volatile uint64_t *addr) _CALLCONV;\n\n/**\n * Transactional load of a char value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nchar stm_load_char(volatile char *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned char value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned char stm_load_uchar(volatile unsigned char *addr) _CALLCONV;\n\n/**\n * Transactional load of a short value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nshort stm_load_short(volatile short *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned short value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned short stm_load_ushort(volatile unsigned short *addr) _CALLCONV;\n\n/**\n * Transactional load of an int value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nint stm_load_int(volatile int *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned int value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned int stm_load_uint(volatile unsigned int *addr) _CALLCONV;\n\n/**\n * Transactional load of a long value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nlong stm_load_long(volatile long *addr) _CALLCONV;\n\n/**\n * Transactional load of an unsigned long value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nunsigned long stm_load_ulong(volatile unsigned long *addr) _CALLCONV;\n\n/**\n * Transactional load of a float value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nfloat stm_load_float(volatile float *addr) _CALLCONV;\n\n/**\n * Transactional load of a double value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\ndouble stm_load_double(volatile double *addr) _CALLCONV;\n\n/**\n * Transactional load of a pointer value.\n *\n * @param addr\n *   Address of the memory location.\n * @return\n *   Value read from the specified address.\n */\nvoid *stm_load_ptr(volatile void **addr) _CALLCONV;\n\n/**\n * Transactional load of a memory region.  The address of the region\n * does not need to be word aligned and its size may be longer than a\n * word.  The values are copied into the provided buffer, which must be\n * allocated by the caller.\n *\n * @param addr\n *   Address of the memory location.\n * @param buf\n *   Buffer for storing the read bytes.\n * @param size\n *   Number of bytes to read.\n */\nvoid stm_load_bytes(volatile uint8_t *addr, uint8_t *buf, size_t size) _CALLCONV;\n\n/**\n * Transactional store of an unsigned 8-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_u8(volatile uint8_t *addr, uint8_t value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned 16-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_u16(volatile uint16_t *addr, uint16_t value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned 32-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_u32(volatile uint32_t *addr, uint32_t value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned 64-bit value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_u64(volatile uint64_t *addr, uint64_t value) _CALLCONV;\n\n/**\n * Transactional store of a char value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_char(volatile char *addr, char value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned char value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_uchar(volatile unsigned char *addr, unsigned char value) _CALLCONV;\n\n/**\n * Transactional store of a short value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_short(volatile short *addr, short value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned short value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_ushort(volatile unsigned short *addr, unsigned short value) _CALLCONV;\n\n/**\n * Transactional store of an int value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_int(volatile int *addr, int value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned int value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_uint(volatile unsigned int *addr, unsigned int value) _CALLCONV;\n\n/**\n * Transactional store of a long value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_long(volatile long *addr, long value) _CALLCONV;\n\n/**\n * Transactional store of an unsigned long value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_ulong(volatile unsigned long *addr, unsigned long value) _CALLCONV;\n\n/**\n * Transactional store of a float value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_float(volatile float *addr, float value) _CALLCONV;\n\n/**\n * Transactional store of a double value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_double(volatile double *addr, double value) _CALLCONV;\n\n/**\n * Transactional store of a pointer value.\n *\n * @param addr\n *   Address of the memory location.\n * @param value\n *   Value to be written.\n */\nvoid stm_store_ptr(volatile void **addr, void *value) _CALLCONV;\n\n/**\n * Transactional store of a memory region.  The address of the region\n * does not need to be word aligned and its size may be longer than a\n * word.  The values are copied from the provided buffer.\n *\n * @param addr\n *   Address of the memory location.\n * @param buf\n *   Buffer with the bytes to write.\n * @param size\n *   Number of bytes to write.\n */\nvoid stm_store_bytes(volatile uint8_t *addr, uint8_t *buf, size_t size) _CALLCONV;\n\n/**\n * Transactional write of a byte to a memory region.  The address of the\n * region does not need to be word aligned and its size may be longer\n * than a word.  The provided byte is repeatedly copied to the whole\n * memory region.\n *\n * @param addr\n *   Address of the memory location.\n * @param byte\n *   Byte to write.\n * @param count\n *   Number of bytes to write.\n */\nvoid stm_set_bytes(volatile uint8_t *addr, uint8_t byte, size_t count) _CALLCONV;\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _WRAPPERS_H_ */\n"
  },
  {
    "path": "stms/tinystm/lib/.gitignore",
    "content": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore\n"
  },
  {
    "path": "stms/tinystm/src/.gitignore",
    "content": "/mod_ab.o\n/mod_cb_mem.o\n/mod_log.o\n/mod_order.o\n/mod_print.o\n/mod_stats.o\n/stm.o\n/wrappers.o\n"
  },
  {
    "path": "stms/tinystm/src/atomic.h",
    "content": "/*\n * File:\n *   atomic.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Atomic operations.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _ATOMIC_H_\n# define _ATOMIC_H_\n\n# ifdef ATOMIC_BUILTIN\ntypedef volatile size_t atomic_t;\n#  ifdef __INTEL_COMPILER\n#   define ATOMIC_CB                     __memory_barrier()\n#  else /* ! __INTEL_COMPILER, assuming __GNUC__ */\n#   define ATOMIC_CB                     __asm__ __volatile__(\"\": : :\"memory\")\n#  endif /* ! __INTEL_COMPILER */\n#  ifndef UNSAFE\n#   warning \"This is experimental and shouldn't be used\"\n/*\n   Note: __sync_ is available for GCC 4.2+ and ICC 11.1+\n   But these definitions are not 100% safe:\n    * need 'a' to be volatile\n    * no fence for read/store proposed (only full fence)\n   C11 and C++11 also propose atomic operations.\n*/\n#   define ATOMIC_CAS_FULL(a, e, v)      (__sync_bool_compare_and_swap(a, e, v))\n#   define ATOMIC_FETCH_INC_FULL(a)      (__sync_fetch_and_add(a, 1))\n#   define ATOMIC_FETCH_DEC_FULL(a)      (__sync_fetch_and_add(a, -1))\n#   define ATOMIC_FETCH_ADD_FULL(a, v)   (__sync_fetch_and_add(a, v))\n#   define ATOMIC_LOAD_ACQ(a)            (*(a))\n#   define ATOMIC_LOAD(a)                (*(a))\n#   define ATOMIC_STORE_REL(a, v)        (*(a) = (v))\n#   define ATOMIC_STORE(a, v)            (*(a) = (v))\n#   define ATOMIC_MB_READ                /* Nothing */\n#   define ATOMIC_MB_WRITE               /* Nothing */\n#   define ATOMIC_MB_FULL                __sync_synchronize()\n#  else\n/* Use only for testing purposes (single thread benchmarks) */\n#   define ATOMIC_CAS_FULL(a, e, v)      (*(a) = (v), 1)\n#   define ATOMIC_FETCH_INC_FULL(a)      ((*(a))++)\n#   define ATOMIC_FETCH_DEC_FULL(a)      ((*(a))--)\n#   define ATOMIC_FETCH_ADD_FULL(a, v)   ((*(a)) += (v))\n#   define ATOMIC_LOAD_ACQ(a)            (*(a))\n#   define ATOMIC_LOAD(a)                (*(a))\n#   define ATOMIC_STORE_REL(a, v)        (*(a) = (v))\n#   define ATOMIC_STORE(a, v)            (*(a) = (v))\n#   define ATOMIC_MB_READ                /* Nothing */\n#   define ATOMIC_MB_WRITE               /* Nothing */\n#   define ATOMIC_MB_FULL                /* Nothing */\n#  endif /* UNSAFE */\n\n# else /* ! ATOMIC_BUILTIN */\n/* NOTE: enable fence instructions for i386 and amd64 but the mfence instructions seems costly. */\n/* # define AO_USE_PENTIUM4_INSTRS */\n#  include <atomic_ops.h>\ntypedef AO_t atomic_t;\n#  define ATOMIC_CB                     AO_compiler_barrier()\n#  define ATOMIC_CAS_FULL(a, e, v)      (AO_compare_and_swap_full((volatile AO_t *)(a), (AO_t)(e), (AO_t)(v)))\n#  define ATOMIC_FETCH_INC_FULL(a)      (AO_fetch_and_add1_full((volatile AO_t *)(a)))\n#  define ATOMIC_FETCH_DEC_FULL(a)      (AO_fetch_and_sub1_full((volatile AO_t *)(a)))\n#  define ATOMIC_FETCH_ADD_FULL(a, v)   (AO_fetch_and_add_full((volatile AO_t *)(a), (AO_t)(v)))\n#  ifdef SAFE\n#   define ATOMIC_LOAD_ACQ(a)           (AO_load_full((volatile AO_t *)(a)))\n#   define ATOMIC_LOAD(a)               (AO_load_full((volatile AO_t *)(a)))\n#   define ATOMIC_STORE_REL(a, v)       (AO_store_full((volatile AO_t *)(a), (AO_t)(v)))\n#   define ATOMIC_STORE(a, v)           (AO_store_full((volatile AO_t *)(a), (AO_t)(v)))\n#   define ATOMIC_MB_READ               AO_nop_full()\n#   define ATOMIC_MB_WRITE              AO_nop_full()\n#   define ATOMIC_MB_FULL               AO_nop_full()\n#  else /* ! SAFE */\n#   define ATOMIC_LOAD_ACQ(a)           (AO_load_acquire_read((volatile AO_t *)(a)))\n#   define ATOMIC_LOAD(a)               (*((volatile AO_t *)(a)))\n#   define ATOMIC_STORE_REL(a, v)       (AO_store_release((volatile AO_t *)(a), (AO_t)(v)))\n#   define ATOMIC_STORE(a, v)           (*((volatile AO_t *)(a)) = (AO_t)(v))\n#   define ATOMIC_MB_READ               AO_nop_read()\n#   define ATOMIC_MB_WRITE              AO_nop_write()\n#   define ATOMIC_MB_FULL               AO_nop_full()\n#  endif /* ! SAFE */\n# endif /* ! NO_AO */\n\n#endif /* _ATOMIC_H_ */\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/AUTHORS",
    "content": "Originally written by Hans Boehm, with some platform-dependent code\nimported from the Boehm-Demers-Weiser GC, where it was contributed\nby many others.\n\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/COPYING",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year  name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/README",
    "content": "This directory contains a stripped-down (support only gcc) version of libatomic_ops by Hans Boehm.\nThe official release is available from http://www.hpl.hp.com/research/linux/atomic_ops/.\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/aligned_atomic_load_store.h",
    "content": "/*\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * Definitions for architectures on which loads and stores of AO_t are\n * atomic fo all legal alignments.\n */\n\nAO_INLINE AO_t\nAO_load(const volatile AO_t *addr)\n{\n  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);\n  /* Cast away the volatile for architectures where             */\n  /* volatile adds barrier semantics.                           */\n  return *(AO_t *)addr;\n}\n\n#define AO_HAVE_load\n\nAO_INLINE void\nAO_store(volatile AO_t *addr, AO_t new_val)\n{\n  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);\n  (*(AO_t *)addr) = new_val;\n}\n\n#define AO_HAVE_store\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/all_acquire_release_volatile.h",
    "content": "/*\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE. \n */\n\n/*\n * Describes architectures on which volatile AO_t, unsigned char, unsigned\n * short, and unsigned int loads and stores have acquire/release semantics for\n * all normally legal alignments.\n */\n//#include \"acquire_release_volatile.h\"\n//#include \"char_acquire_release_volatile.h\"\n//#include \"short_acquire_release_volatile.h\"\n//#include \"int_acquire_release_volatile.h\"\n\n/*\n * This file adds definitions appropriate for environments in which an AO_t\n * volatile load has acquire semantics, and an AO_t volatile store has release\n * semantics.  This is arguably supposed to be true with the standard Itanium\n * software conventions.\n */\n\n/*\n * Empirically gcc/ia64 does some reordering of ordinary operations around volatiles\n * even when we think it shouldn't.  Gcc 3.3 and earlier could reorder a volatile store\n * with another store.  As of March 2005, gcc pre-4 reused previously computed\n * common subexpressions across a volatile load.\n * Hence we now add compiler barriers for gcc.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE AO_t\nAO_load_acquire(const volatile AO_t *p)\n{\n  AO_t result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_load_acquire\n\nAO_INLINE void\nAO_store_release(volatile AO_t *p, AO_t val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_store_release\n\n/*\n * This file adds definitions appropriate for environments in which an unsigned char\n * volatile load has acquire semantics, and an unsigned char volatile store has release\n * semantics.  This is true with the standard Itanium ABI.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE unsigned char\nAO_char_load_acquire(const volatile unsigned char *p)\n{\n  unsigned char result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_char_load_acquire\n\nAO_INLINE void\nAO_char_store_release(volatile unsigned char *p, unsigned char val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_char_store_release\n\n/*\n * This file adds definitions appropriate for environments in which an unsigned short\n * volatile load has acquire semantics, and an unsigned short volatile store has release\n * semantics.  This is true with the standard Itanium ABI.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE unsigned short\nAO_short_load_acquire(const volatile unsigned short *p)\n{\n  unsigned short result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_short_load_acquire\n\nAO_INLINE void\nAO_short_store_release(volatile unsigned short *p, unsigned short val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_short_store_release\n\n/*\n * This file adds definitions appropriate for environments in which an unsigned\n * int volatile load has acquire semantics, and an unsigned short volatile\n * store has release semantics.  This is true with the standard Itanium ABI.\n */\n#if !defined(AO_GCC_BARRIER)\n#  if defined(__GNUC__)\n#    define AO_GCC_BARRIER() AO_compiler_barrier()\n#  else\n#    define AO_GCC_BARRIER()\n#  endif\n#endif\n\nAO_INLINE unsigned int\nAO_int_load_acquire(const volatile unsigned int *p)\n{\n  unsigned int result = *p;\n  /* A normal volatile load generates an ld.acq         */\n  AO_GCC_BARRIER();\n  return result;\n}\n#define AO_HAVE_int_load_acquire\n\nAO_INLINE void\nAO_int_store_release(volatile unsigned int *p, unsigned int val)\n{\n  AO_GCC_BARRIER();\n  /* A normal volatile store generates an st.rel        */\n  *p = val;\n}\n#define AO_HAVE_int_store_release\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/ao_t_is_int.h",
    "content": "/*\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * Inclusion of this file signifies that AO_t is in fact int.  Hence\n * any AO_... operations can also server as AO_int_... operations.\n * We currently define only the more important ones here, and allow for\n * the normal generalization process to define the others.\n * We should probably add others in the future.\n */\n\n#if defined(AO_HAVE_compare_and_swap_full) && \\\n    !defined(AO_HAVE_int_compare_and_swap_full)\n#  define AO_int_compare_and_swap_full(addr, old, new_val) \\\n                AO_compare_and_swap_full((volatile AO_t *)(addr), \\\n                                        (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_full\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_int_compare_and_swap_acquire)\n#  define AO_int_compare_and_swap_acquire(addr, old, new_val) \\\n                AO_compare_and_swap_acquire((volatile AO_t *)(addr), \\\n                                            (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_acquire\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_release) && \\\n    !defined(AO_HAVE_int_compare_and_swap_release)\n#  define AO_int_compare_and_swap_release(addr, old, new_val) \\\n                AO_compare_and_swap_release((volatile AO_t *)(addr), \\\n                                         (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_release\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_write) && \\\n    !defined(AO_HAVE_int_compare_and_swap_write)\n#  define AO_int_compare_and_swap_write(addr, old, new_val) \\\n                AO_compare_and_swap_write((volatile AO_t *)(addr), \\\n                                          (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_write\n# endif\n\n#if defined(AO_HAVE_compare_and_swap_read) && \\\n    !defined(AO_HAVE_int_compare_and_swap_read)\n#  define AO_int_compare_and_swap_read(addr, old, new_val) \\\n                AO_compare_and_swap_read((volatile AO_t *)(addr), \\\n                                         (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap_read\n# endif\n\n#if defined(AO_HAVE_compare_and_swap) && \\\n    !defined(AO_HAVE_int_compare_and_swap)\n#  define AO_int_compare_and_swap(addr, old, new_val) \\\n                AO_compare_and_swap((volatile AO_t *)(addr), \\\n                                    (AO_t)(old), (AO_t)(new_val))\n#  define AO_HAVE_int_compare_and_swap\n# endif\n\n#if defined(AO_HAVE_load_acquire) && \\\n    !defined(AO_HAVE_int_load_acquire)\n#  define AO_int_load_acquire(addr) \\\n        (int)AO_load_acquire((const volatile AO_t *)(addr))\n#  define AO_HAVE_int_load_acquire\n# endif\n\n#if defined(AO_HAVE_store_release) && \\\n    !defined(AO_HAVE_int_store_release)\n#  define AO_int_store_release(addr, val) \\\n        AO_store_release((volatile AO_t *)(addr), (AO_t)(val))\n#  define AO_HAVE_int_store_release\n# endif\n\n#if defined(AO_HAVE_fetch_and_add_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add_full)\n#  define AO_int_fetch_and_add_full(addr, incr) \\\n        (int)AO_fetch_and_add_full((volatile AO_t *)(addr), (AO_t)(incr))\n#  define AO_HAVE_int_fetch_and_add_full\n# endif\n\n#if defined(AO_HAVE_fetch_and_add1_acquire) && \\\n    !defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1_acquire(addr) \\\n        (int)AO_fetch_and_add1_acquire((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_add1_acquire\n# endif\n\n#if defined(AO_HAVE_fetch_and_add1_release) && \\\n    !defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1_release(addr) \\\n        (int)AO_fetch_and_add1_release((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_add1_release\n# endif\n\n#if defined(AO_HAVE_fetch_and_sub1_acquire) && \\\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1_acquire(addr) \\\n        (int)AO_fetch_and_sub1_acquire((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_sub1_acquire\n# endif\n\n#if defined(AO_HAVE_fetch_and_sub1_release) && \\\n    !defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1_release(addr) \\\n        (int)AO_fetch_and_sub1_release((volatile AO_t *)(addr))\n#  define AO_HAVE_int_fetch_and_sub1_release\n# endif\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/atomic_ops.h",
    "content": "/*\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef ATOMIC_OPS_H\n\n#define ATOMIC_OPS_H\n\n#include <assert.h>\n#include <stddef.h>\n\n/* We define various atomic operations on memory in a           */\n/* machine-specific way.  Unfortunately, this is complicated    */\n/* by the fact that these may or may not be combined with       */\n/* various memory barriers.  Thus the actual operations we      */\n/* define have the form AO_<atomic-op>_<barrier>, for all       */\n/* plausible combinations of <atomic-op> and <barrier>.         */\n/* This of course results in a mild combinatorial explosion.    */\n/* To deal with it, we try to generate derived                  */\n/* definitions for as many of the combinations as we can, as    */\n/* automatically as possible.                                   */\n/*                                                              */\n/* Our assumption throughout is that the programmer will        */\n/* specify the least demanding operation and memory barrier     */\n/* that will guarantee correctness for the implementation.      */\n/* Our job is to find the least expensive way to implement it   */\n/* on the applicable hardware.  In many cases that will         */\n/* involve, for example, a stronger memory barrier, or a        */\n/* combination of hardware primitives.                          */\n/*                                                              */\n/* Conventions:                                                 */\n/* \"plain\" atomic operations are not guaranteed to include      */\n/* a barrier.  The suffix in the name specifies the barrier     */\n/* type.  Suffixes are:                                         */\n/* _release: Earlier operations may not be delayed past it.     */\n/* _acquire: Later operations may not move ahead of it.         */\n/* _read: Subsequent reads must follow this operation and       */\n/*        preceding reads.                                      */\n/* _write: Earlier writes precede both this operation and       */\n/*        later writes.                                         */\n/* _full: Ordered with respect to both earlier and later memops.*/\n/* _release_write: Ordered with respect to earlier writes.      */\n/* _acquire_read: Ordered with respect to later reads.          */\n/*                                                              */\n/* Currently we try to define the following atomic memory       */\n/* operations, in combination with the above barriers:          */\n/* AO_nop                                                       */\n/* AO_load                                                      */\n/* AO_store                                                     */\n/* AO_test_and_set (binary)                                     */\n/* AO_fetch_and_add                                             */\n/* AO_fetch_and_add1                                            */\n/* AO_fetch_and_sub1                                            */\n/* AO_or                                                        */\n/* AO_compare_and_swap                                          */\n/*                                                              */\n/* Note that atomicity guarantees are valid only if both        */\n/* readers and writers use AO_ operations to access the         */\n/* shared value, while ordering constraints are intended to     */\n/* apply all memory operations.  If a location can potentially  */\n/* be accessed simultaneously from multiple threads, and one of */\n/* those accesses may be a write access, then all such          */\n/* accesses to that location should be through AO_ primitives.  */\n/* However if AO_ operations enforce sufficient ordering to     */\n/* ensure that a location x cannot be accessed concurrently,    */\n/* or can only be read concurrently, then x can be accessed     */\n/* via ordinary references and assignments.                     */\n/*                                                              */\n/* Compare_and_exchange takes an address and an expected old    */\n/* value and a new value, and returns an int.  Nonzero          */\n/* indicates that it succeeded.                                 */\n/* Test_and_set takes an address, atomically replaces it by     */\n/* AO_TS_SET, and returns the prior value.                      */\n/* An AO_TS_t location can be reset with the                    */\n/* AO_CLEAR macro, which normally uses AO_store_release.        */\n/* AO_fetch_and_add takes an address and an AO_t increment      */\n/* value.  The AO_fetch_and_add1 and AO_fetch_and_sub1 variants */\n/* are provided, since they allow faster implementations on     */\n/* some hardware. AO_or atomically ors an AO_t value into a     */\n/* memory location, but does not provide access to the original.*/\n/*                                                              */\n/* We expect this list to grow slowly over time.                */\n/*                                                              */\n/* Note that AO_nop_full is a full memory barrier.              */\n/*                                                              */\n/* Note that if some data is initialized with                   */\n/*      data.x = ...; data.y = ...; ...                         */\n/*      AO_store_release_write(&data_is_initialized, 1)         */\n/* then data is guaranteed to be initialized after the test     */\n/*      if (AO_load_release_read(&data_is_initialized)) ...     */\n/* succeeds.  Furthermore, this should generate near-optimal    */\n/* code on all common platforms.                                */\n/*                                                              */\n/* All operations operate on unsigned AO_t, which               */\n/* is the natural word size, and usually unsigned long.         */\n/* It is possible to check whether a particular operation op    */\n/* is available on a particular platform by checking whether    */\n/* AO_HAVE_op is defined.  We make heavy use of these macros    */\n/* internally.                                                  */\n\n/* The rest of this file basically has three sections:          */\n/*                                                              */\n/* Some utility and default definitions.                        */\n/*                                                              */\n/* The architecture dependent section:                          */\n/* This defines atomic operations that have direct hardware     */\n/* support on a particular platform, mostly by including the    */\n/* appropriate compiler- and hardware-dependent file.           */\n/*                                                              */\n/* The synthesis section:                                       */\n/* This tries to define other atomic operations in terms of     */\n/* those that are explicitly available on the platform.         */\n/* This section is hardware independent.                        */\n/* We make no attempt to synthesize operations in ways that     */\n/* effectively introduce locks, except for the debugging/demo   */\n/* pthread-based implementation at the beginning.  A more       */\n/* realistic implementation that falls back to locks could be   */\n/* added as a higher layer.  But that would sacrifice           */\n/* usability from signal handlers.                              */\n/* The synthesis section is implemented almost entirely in      */\n/* atomic_ops_generalize.h.                                     */\n\n/* Some common defaults.  Overridden for some architectures.    */\n#define AO_t size_t\n\n/* The test_and_set primitive returns an AO_TS_VAL_t value.     */\n/* AO_TS_t is the type of an in-memory test-and-set location.   */\n\n#define AO_TS_INITIALIZER (AO_t)AO_TS_CLEAR\n\n/* Platform-dependent stuff:                                    */\n#if defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER) \\\n        || defined(__DMC__) || defined(__WATCOMC__)\n# define AO_INLINE static __inline\n#elif defined(__sun)\n# define AO_INLINE static inline\n#else\n# define AO_INLINE static\n#endif\n\n#if defined(__GNUC__) && !defined(__INTEL_COMPILER)\n# define AO_compiler_barrier() __asm__ __volatile__(\"\" : : : \"memory\")\n#elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \\\n        || defined(__WATCOMC__)\n# if defined(_AMD64_) || defined(_M_X64) || _MSC_VER >= 1400\n#   if defined(_WIN32_WCE)\n/* #     include <cmnintrin.h> */\n#   elif defined(_MSC_VER)\n#     include <intrin.h>\n#   endif\n#   pragma intrinsic(_ReadWriteBarrier)\n#   define AO_compiler_barrier() _ReadWriteBarrier()\n        /* We assume this does not generate a fence instruction.        */\n        /* The documentation is a bit unclear.                          */\n# else\n#   define AO_compiler_barrier() __asm { }\n        /* The preceding implementation may be preferable here too.     */\n        /* But the documentation warns about VC++ 2003 and earlier.     */\n# endif\n#elif defined(__INTEL_COMPILER)\n# define AO_compiler_barrier() __memory_barrier() /* Too strong? IA64-only? */\n#elif defined(_HPUX_SOURCE)\n# if defined(__ia64)\n#   include <machine/sys/inline.h>\n#   define AO_compiler_barrier() _Asm_sched_fence()\n# else\n    /* FIXME - We dont know how to do this.  This is a guess.   */\n    /* And probably a bad one.                                  */\n    static volatile int AO_barrier_dummy;\n#   define AO_compiler_barrier() AO_barrier_dummy = AO_barrier_dummy\n# endif\n#else\n  /* We conjecture that the following usually gives us the right        */\n  /* semantics or an error.                                             */\n# define AO_compiler_barrier() asm(\"\")\n#endif\n\n#if defined(AO_USE_PTHREAD_DEFS)\n# include \"atomic_ops/sysdeps/generic_pthread.h\"\n#endif /* AO_USE_PTHREAD_DEFS */\n\n#if defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS) \\\n    && !defined(__INTEL_COMPILER)\n# if defined(__i386__)\n    /* We don't define AO_USE_SYNC_CAS_BUILTIN for x86 here because     */\n    /* it might require specifying additional options (like -march)     */\n    /* or additional link libraries (if -march is not specified).       */\n#   include \"./x86.h\"\n# endif /* __i386__ */\n# if defined(__x86_64__)\n#   if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)\n      /* It is safe to use __sync CAS built-in on this architecture.    */\n#     define AO_USE_SYNC_CAS_BUILTIN\n#   endif\n#   include \"./x86_64.h\"\n# endif /* __x86_64__ */\n# if defined(__ia64__)\n#   include \"./ia64.h\"\n#   define AO_GENERALIZE_TWICE\n# endif /* __ia64__ */\n# if defined(__hppa__)\n#   include \"atomic_ops/sysdeps/gcc/hppa.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __hppa__ */\n# if defined(__alpha__)\n#   include \"atomic_ops/sysdeps/gcc/alpha.h\"\n#   define AO_GENERALIZE_TWICE\n# endif /* __alpha__ */\n# if defined(__s390__)\n#   include \"atomic_ops/sysdeps/gcc/s390.h\"\n# endif /* __s390__ */\n# if defined(__sparc__)\n#   include \"./sparc.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __sparc__ */\n# if defined(__m68k__)\n#   include \"atomic_ops/sysdeps/gcc/m68k.h\"\n# endif /* __m68k__ */\n# if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \\\n     || defined(__powerpc64__) || defined(__ppc64__)\n#   include \"./powerpc.h\"\n# endif /* __powerpc__ */\n# if defined(__arm__) && !defined(AO_USE_PTHREAD_DEFS)\n#   include \"atomic_ops/sysdeps/gcc/arm.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __arm__ */\n# if defined(__cris__) || defined(CRIS)\n#   include \"atomic_ops/sysdeps/gcc/cris.h\"\n# endif\n# if defined(__mips__)\n#   include \"atomic_ops/sysdeps/gcc/mips.h\"\n# endif /* __mips__ */\n# if defined(__sh__) || defined(SH4)\n#   include \"atomic_ops/sysdeps/gcc/sh.h\"\n#   define AO_CAN_EMUL_CAS\n# endif /* __sh__ */\n#endif /* __GNUC__ && !AO_USE_PTHREAD_DEFS */\n\n#if defined(__INTEL_COMPILER) && !defined(AO_USE_PTHREAD_DEFS)\n# if defined(__ia64__)\n#   include \"./ia64.h\"\n#   define AO_GENERALIZE_TWICE\n# endif\n# if defined(__GNUC__)\n    /* Intel Compiler in GCC compatible mode */\n#   if defined(__i386__)\n#     include \"./x86.h\"\n#   endif /* __i386__ */\n#   if defined(__x86_64__)\n#     if __INTEL_COMPILER > 1110\n#       define AO_USE_SYNC_CAS_BUILTIN\n#     endif\n#     include \"./x86_64.h\"\n#   endif /* __x86_64__ */\n# endif\n#endif\n\n#if defined(_HPUX_SOURCE) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)\n# if defined(__ia64)\n#   include \"atomic_ops/sysdeps/hpc/ia64.h\"\n#   define AO_GENERALIZE_TWICE\n# else\n#   include \"atomic_ops/sysdeps/hpc/hppa.h\"\n#   define AO_CAN_EMUL_CAS\n# endif\n#endif\n\n#if defined(__sun) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)\n  /* Note: use -DAO_USE_PTHREAD_DEFS if Sun CC does not handle inline asm. */\n# if defined(__i386)\n#   include \"atomic_ops/sysdeps/sunc/x86.h\"\n# endif /* __i386 */\n# if defined(__x86_64) || defined(__amd64)\n#   include \"atomic_ops/sysdeps/sunc/x86_64.h\"\n# endif /* __x86_64 */\n#endif\n\n#if !defined(__GNUC__) && (defined(sparc) || defined(__sparc)) \\\n    && !defined(AO_USE_PTHREAD_DEFS)\n#   include \"atomic_ops/sysdeps/sunc/sparc.h\"\n#   define AO_CAN_EMUL_CAS\n#endif\n\n#if defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \\\n        || (defined(__WATCOMC__) && defined(__NT__))\n# if defined(_AMD64_) || defined(_M_X64)\n#   include \"atomic_ops/sysdeps/msftc/x86_64.h\"\n# elif defined(_M_IX86) || defined(x86)\n#   include \"atomic_ops/sysdeps/msftc/x86.h\"\n# elif defined(_M_ARM) || defined(ARM) || defined(_ARM_)\n#   include \"atomic_ops/sysdeps/msftc/arm.h\"\n# endif\n#endif\n\n#if defined(AO_REQUIRE_CAS) && !defined(AO_HAVE_compare_and_swap) \\\n    && !defined(AO_HAVE_compare_and_swap_full) \\\n    && !defined(AO_HAVE_compare_and_swap_acquire)\n# if defined(AO_CAN_EMUL_CAS)\n#   include \"atomic_ops/sysdeps/emul_cas.h\"\n# else\n#  error Cannot implement AO_compare_and_swap_full on this architecture.\n# endif\n#endif  /* AO_REQUIRE_CAS && !AO_HAVE_compare_and_swap ... */\n\n/* The most common way to clear a test-and-set location         */\n/* at the end of a critical section.                            */\n#if AO_AO_TS_T && !defined(AO_CLEAR)\n# define AO_CLEAR(addr) AO_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)\n#endif\n#if AO_CHAR_TS_T && !defined(AO_CLEAR)\n# define AO_CLEAR(addr) AO_char_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)\n#endif\n\n/*\n * The generalization section.\n * Theoretically this should repeatedly include atomic_ops_generalize.h.\n * In fact, we observe that this converges after a small fixed number\n * of iterations, usually one.\n */\n#include \"./generalize.h\"\n#ifdef AO_GENERALIZE_TWICE\n# include \"./generalize.h\"\n#endif\n\n/* For compatibility with version 0.4 and earlier       */\n#define AO_TS_T AO_TS_t\n#define AO_T AO_t\n#define AO_TS_VAL AO_TS_VAL_t\n\n#endif /* ATOMIC_OPS_H */\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/generalize-small.h",
    "content": "/* char_load */\n#if defined(AO_HAVE_char_load_acquire) && !defined(AO_HAVE_char_load)\n#  define AO_char_load(addr) AO_char_load_acquire(addr)\n#  define AO_HAVE_char_load\n#endif\n\n#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_acquire)\n#  define AO_char_load_acquire(addr) AO_char_load_full(addr)\n#  define AO_HAVE_char_load_acquire\n#endif\n\n#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_read)\n#  define AO_char_load_read(addr) AO_char_load_full(addr)\n#  define AO_HAVE_char_load_read\n#endif\n\n#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_acquire)\n#  define AO_char_load_acquire_read(addr) AO_char_load_acquire(addr)\n#  define AO_HAVE_char_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_load_acquire)\n   AO_INLINE unsigned char\n   AO_char_load_acquire(const volatile unsigned char *addr)\n   {\n     unsigned char result = AO_char_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_char_load_acquire\n#endif\n\n#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_char_load_read)\n   AO_INLINE unsigned char\n   AO_char_load_read(const volatile unsigned char *addr)\n   {\n     unsigned char result = AO_char_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_char_load_read\n#endif\n\n#if defined(AO_HAVE_char_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_load_full)\n#  define AO_char_load_full(addr) (AO_nop_full(), AO_char_load_acquire(addr))\n#  define AO_HAVE_char_load_full\n#endif\n\n#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_read)\n#  define AO_char_load_acquire_read(addr) AO_char_load_read(addr)\n#  define AO_HAVE_char_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_char_load_acquire_read) && !defined(AO_HAVE_char_load)\n#  define AO_char_load(addr) AO_char_load_acquire_read(addr)\n#  define AO_HAVE_char_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_load_acquire_read)\n#    define AO_char_load_dd_acquire_read(addr) \\\n        AO_char_load_acquire_read(addr)\n#    define AO_HAVE_char_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_load)\n#    define AO_char_load_dd_acquire_read(addr) \\\n        AO_char_load(addr)\n#    define AO_HAVE_char_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* char_store */\n\n#if defined(AO_HAVE_char_store_release) && !defined(AO_HAVE_char_store)\n#  define AO_char_store(addr, val) AO_char_store_release(addr,val)\n#  define AO_HAVE_char_store\n#endif\n\n#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_release)\n#  define AO_char_store_release(addr,val) AO_char_store_full(addr,val)\n#  define AO_HAVE_char_store_release\n#endif\n\n#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_write)\n#  define AO_char_store_write(addr,val) AO_char_store_full(addr,val)\n#  define AO_HAVE_char_store_write\n#endif\n\n#if defined(AO_HAVE_char_store_release) && \\\n        !defined(AO_HAVE_char_store_release_write)\n#  define AO_char_store_release_write(addr, val) \\\n        AO_char_store_release(addr,val)\n#  define AO_HAVE_char_store_release_write\n#endif\n\n#if defined(AO_HAVE_char_store_write) && !defined(AO_HAVE_char_store)\n#  define AO_char_store(addr, val) AO_char_store_write(addr,val)\n#  define AO_HAVE_char_store\n#endif\n\n#if defined(AO_HAVE_char_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_store_release)\n#  define AO_char_store_release(addr,val) \\\n        (AO_nop_full(), AO_char_store(addr,val))\n#  define AO_HAVE_char_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_char_store) && \\\n     !defined(AO_HAVE_char_store_write)\n#  define AO_char_store_write(addr, val) \\\n        (AO_nop_write(), AO_char_store(addr,val))\n#  define AO_HAVE_char_store_write\n#endif\n\n#if defined(AO_HAVE_char_store_write) && \\\n     !defined(AO_HAVE_char_store_release_write)\n#  define AO_char_store_release_write(addr, val) AO_char_store_write(addr,val)\n#  define AO_HAVE_char_store_release_write\n#endif\n\n#if defined(AO_HAVE_char_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_store_full)\n#  define AO_char_store_full(addr, val) \\\n        (AO_char_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_char_store_full\n#endif\n\n\n/* char_fetch_and_add */\n#if defined(AO_HAVE_char_compare_and_swap_full) && \\\n    !defined(AO_HAVE_char_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_char_fetch_and_add_full(volatile unsigned char *addr,\n                               unsigned char incr)\n   {\n     unsigned char old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_char_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_char_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_char_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_char_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_char_fetch_and_add_acquire(volatile unsigned char *addr,\n                                  unsigned char incr)\n   {\n     unsigned char old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_char_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_char_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_char_compare_and_swap_release) && \\\n    !defined(AO_HAVE_char_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_char_fetch_and_add_release(volatile unsigned char *addr,\n                                  unsigned char incr)\n   {\n     unsigned char old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_char_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_char_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add_full)\n#  if !defined(AO_HAVE_char_fetch_and_add_release)\n#    define AO_char_fetch_and_add_release(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add_acquire)\n#    define AO_char_fetch_and_add_acquire(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add_write)\n#    define AO_char_fetch_and_add_write(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add_read)\n#    define AO_char_fetch_and_add_read(addr, val) \\\n         AO_char_fetch_and_add_full(addr, val)\n#    define AO_HAVE_char_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_char_fetch_and_add_full */\n\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_release)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_release(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_acquire)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_write)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_write(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add) && \\\n    defined(AO_HAVE_char_fetch_and_add_read)\n#  define AO_char_fetch_and_add(addr, val) \\\n        AO_char_fetch_and_add_read(addr, val)\n#  define AO_HAVE_char_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_fetch_and_add_full)\n#  define AO_char_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_char_fetch_and_add_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add_write)\n#  define AO_char_fetch_and_add_release_write(addr, val) \\\n        AO_char_fetch_and_add_write(addr, val)\n#  define AO_HAVE_char_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add_release)\n#  define AO_char_fetch_and_add_release_write(addr, val) \\\n        AO_char_fetch_and_add_release(addr, val)\n#  define AO_HAVE_char_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add_read)\n#  define AO_char_fetch_and_add_acquire_read(addr, val) \\\n        AO_char_fetch_and_add_read(addr, val)\n#  define AO_HAVE_char_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add_acquire)\n#  define AO_char_fetch_and_add_acquire_read(addr, val) \\\n        AO_char_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_char_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_fetch_and_add_acquire_read)\n#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_char_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_char_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_fetch_and_add)\n#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_char_fetch_and_add(addr, val)\n#    define AO_HAVE_char_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* char_fetch_and_add1 */\n\n#if defined(AO_HAVE_char_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_full)\n#  define AO_char_fetch_and_add1_full(addr) \\\n        AO_char_fetch_and_add_full(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_release)\n#  define AO_char_fetch_and_add1_release(addr) \\\n        AO_char_fetch_and_add_release(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_acquire)\n#  define AO_char_fetch_and_add1_acquire(addr) \\\n        AO_char_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_write)\n#  define AO_char_fetch_and_add1_write(addr) \\\n        AO_char_fetch_and_add_write(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_read)\n#  define AO_char_fetch_and_add1_read(addr) \\\n        AO_char_fetch_and_add_read(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_release_write)\n#  define AO_char_fetch_and_add1_release_write(addr) \\\n        AO_char_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1_acquire_read)\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\n        AO_char_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add) &&\\\n    !defined(AO_HAVE_char_fetch_and_add1)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add(addr,1)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add1_full)\n#  if !defined(AO_HAVE_char_fetch_and_add1_release)\n#    define AO_char_fetch_and_add1_release(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add1_acquire)\n#    define AO_char_fetch_and_add1_acquire(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add1_write)\n#    define AO_char_fetch_and_add1_write(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_add1_read)\n#    define AO_char_fetch_and_add1_read(addr) \\\n         AO_char_fetch_and_add1_full(addr)\n#    define AO_HAVE_char_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_char_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_release)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_release(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_acquire)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_write)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_write(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1) && \\\n    defined(AO_HAVE_char_fetch_and_add1_read)\n#  define AO_char_fetch_and_add1(addr) \\\n        AO_char_fetch_and_add1_read(addr)\n#  define AO_HAVE_char_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_fetch_and_add1_full)\n#  define AO_char_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_char_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_char_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add1_write)\n#  define AO_char_fetch_and_add1_release_write(addr) \\\n        AO_char_fetch_and_add1_write(addr)\n#  define AO_HAVE_char_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_add1_release)\n#  define AO_char_fetch_and_add1_release_write(addr) \\\n        AO_char_fetch_and_add1_release(addr)\n#  define AO_HAVE_char_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add1_read)\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\n        AO_char_fetch_and_add1_read(addr)\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_add1_acquire)\n#  define AO_char_fetch_and_add1_acquire_read(addr) \\\n        AO_char_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_fetch_and_add1_acquire_read)\n#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_fetch_and_add1)\n#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_add1(addr)\n#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* char_fetch_and_sub1 */\n\n#if defined(AO_HAVE_char_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_full)\n#  define AO_char_fetch_and_sub1_full(addr) \\\n        AO_char_fetch_and_add_full(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_release)\n#  define AO_char_fetch_and_sub1_release(addr) \\\n        AO_char_fetch_and_add_release(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#  define AO_char_fetch_and_sub1_acquire(addr) \\\n        AO_char_fetch_and_add_acquire(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_write)\n#  define AO_char_fetch_and_sub1_write(addr) \\\n        AO_char_fetch_and_add_write(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_read)\n#  define AO_char_fetch_and_sub1_read(addr) \\\n        AO_char_fetch_and_add_read(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_release_write)\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\n        AO_char_fetch_and_add_release_write(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1_acquire_read)\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\n        AO_char_fetch_and_add_acquire_read(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_char_fetch_and_add) &&\\\n    !defined(AO_HAVE_char_fetch_and_sub1)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_add(addr,(unsigned char)(-1))\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_char_fetch_and_sub1_release)\n#    define AO_char_fetch_and_sub1_release(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#    define AO_char_fetch_and_sub1_acquire(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_sub1_write)\n#    define AO_char_fetch_and_sub1_write(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_char_fetch_and_sub1_read)\n#    define AO_char_fetch_and_sub1_read(addr) \\\n         AO_char_fetch_and_sub1_full(addr)\n#    define AO_HAVE_char_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_char_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_release)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_release(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_write)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_write(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_read)\n#  define AO_char_fetch_and_sub1(addr) \\\n        AO_char_fetch_and_sub1_read(addr)\n#  define AO_HAVE_char_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_char_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_char_fetch_and_sub1_full)\n#  define AO_char_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_char_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_char_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_write)\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\n        AO_char_fetch_and_sub1_write(addr)\n#  define AO_HAVE_char_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_release)\n#  define AO_char_fetch_and_sub1_release_write(addr) \\\n        AO_char_fetch_and_sub1_release(addr)\n#  define AO_HAVE_char_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_read)\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\n        AO_char_fetch_and_sub1_read(addr)\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_char_fetch_and_sub1_acquire)\n#  define AO_char_fetch_and_sub1_acquire_read(addr) \\\n        AO_char_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_char_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_char_fetch_and_sub1_acquire_read)\n#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_char_fetch_and_sub1)\n#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_char_fetch_and_sub1(addr)\n#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n\n/* short_load */\n#if defined(AO_HAVE_short_load_acquire) && !defined(AO_HAVE_short_load)\n#  define AO_short_load(addr) AO_short_load_acquire(addr)\n#  define AO_HAVE_short_load\n#endif\n\n#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_acquire)\n#  define AO_short_load_acquire(addr) AO_short_load_full(addr)\n#  define AO_HAVE_short_load_acquire\n#endif\n\n#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_read)\n#  define AO_short_load_read(addr) AO_short_load_full(addr)\n#  define AO_HAVE_short_load_read\n#endif\n\n#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_acquire)\n#  define AO_short_load_acquire_read(addr) AO_short_load_acquire(addr)\n#  define AO_HAVE_short_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_load_acquire)\n   AO_INLINE unsigned short\n   AO_short_load_acquire(const volatile unsigned short *addr)\n   {\n     unsigned short result = AO_short_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_short_load_acquire\n#endif\n\n#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_short_load_read)\n   AO_INLINE unsigned short\n   AO_short_load_read(const volatile unsigned short *addr)\n   {\n     unsigned short result = AO_short_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_short_load_read\n#endif\n\n#if defined(AO_HAVE_short_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_load_full)\n#  define AO_short_load_full(addr) (AO_nop_full(), AO_short_load_acquire(addr))\n#  define AO_HAVE_short_load_full\n#endif\n\n#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_read)\n#  define AO_short_load_acquire_read(addr) AO_short_load_read(addr)\n#  define AO_HAVE_short_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_short_load_acquire_read) && !defined(AO_HAVE_short_load)\n#  define AO_short_load(addr) AO_short_load_acquire_read(addr)\n#  define AO_HAVE_short_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_load_acquire_read)\n#    define AO_short_load_dd_acquire_read(addr) \\\n        AO_short_load_acquire_read(addr)\n#    define AO_HAVE_short_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_load)\n#    define AO_short_load_dd_acquire_read(addr) \\\n        AO_short_load(addr)\n#    define AO_HAVE_short_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* short_store */\n\n#if defined(AO_HAVE_short_store_release) && !defined(AO_HAVE_short_store)\n#  define AO_short_store(addr, val) AO_short_store_release(addr,val)\n#  define AO_HAVE_short_store\n#endif\n\n#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_release)\n#  define AO_short_store_release(addr,val) AO_short_store_full(addr,val)\n#  define AO_HAVE_short_store_release\n#endif\n\n#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_write)\n#  define AO_short_store_write(addr,val) AO_short_store_full(addr,val)\n#  define AO_HAVE_short_store_write\n#endif\n\n#if defined(AO_HAVE_short_store_release) && \\\n        !defined(AO_HAVE_short_store_release_write)\n#  define AO_short_store_release_write(addr, val) \\\n        AO_short_store_release(addr,val)\n#  define AO_HAVE_short_store_release_write\n#endif\n\n#if defined(AO_HAVE_short_store_write) && !defined(AO_HAVE_short_store)\n#  define AO_short_store(addr, val) AO_short_store_write(addr,val)\n#  define AO_HAVE_short_store\n#endif\n\n#if defined(AO_HAVE_short_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_store_release)\n#  define AO_short_store_release(addr,val) \\\n        (AO_nop_full(), AO_short_store(addr,val))\n#  define AO_HAVE_short_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_short_store) && \\\n     !defined(AO_HAVE_short_store_write)\n#  define AO_short_store_write(addr, val) \\\n        (AO_nop_write(), AO_short_store(addr,val))\n#  define AO_HAVE_short_store_write\n#endif\n\n#if defined(AO_HAVE_short_store_write) && \\\n     !defined(AO_HAVE_short_store_release_write)\n#  define AO_short_store_release_write(addr, val) AO_short_store_write(addr,val)\n#  define AO_HAVE_short_store_release_write\n#endif\n\n#if defined(AO_HAVE_short_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_store_full)\n#  define AO_short_store_full(addr, val) \\\n        (AO_short_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_short_store_full\n#endif\n\n\n/* short_fetch_and_add */\n#if defined(AO_HAVE_short_compare_and_swap_full) && \\\n    !defined(AO_HAVE_short_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_short_fetch_and_add_full(volatile unsigned short *addr,\n                               unsigned short incr)\n   {\n     unsigned short old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_short_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_short_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_short_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_short_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_short_fetch_and_add_acquire(volatile unsigned short *addr,\n                                  unsigned short incr)\n   {\n     unsigned short old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_short_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_short_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_short_compare_and_swap_release) && \\\n    !defined(AO_HAVE_short_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_short_fetch_and_add_release(volatile unsigned short *addr,\n                                  unsigned short incr)\n   {\n     unsigned short old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_short_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_short_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add_full)\n#  if !defined(AO_HAVE_short_fetch_and_add_release)\n#    define AO_short_fetch_and_add_release(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add_acquire)\n#    define AO_short_fetch_and_add_acquire(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add_write)\n#    define AO_short_fetch_and_add_write(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add_read)\n#    define AO_short_fetch_and_add_read(addr, val) \\\n         AO_short_fetch_and_add_full(addr, val)\n#    define AO_HAVE_short_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_short_fetch_and_add_full */\n\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_release)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_release(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_acquire)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_write)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_write(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add) && \\\n    defined(AO_HAVE_short_fetch_and_add_read)\n#  define AO_short_fetch_and_add(addr, val) \\\n        AO_short_fetch_and_add_read(addr, val)\n#  define AO_HAVE_short_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_fetch_and_add_full)\n#  define AO_short_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_short_fetch_and_add_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add_write)\n#  define AO_short_fetch_and_add_release_write(addr, val) \\\n        AO_short_fetch_and_add_write(addr, val)\n#  define AO_HAVE_short_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add_release)\n#  define AO_short_fetch_and_add_release_write(addr, val) \\\n        AO_short_fetch_and_add_release(addr, val)\n#  define AO_HAVE_short_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add_read)\n#  define AO_short_fetch_and_add_acquire_read(addr, val) \\\n        AO_short_fetch_and_add_read(addr, val)\n#  define AO_HAVE_short_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add_acquire)\n#  define AO_short_fetch_and_add_acquire_read(addr, val) \\\n        AO_short_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_short_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_fetch_and_add_acquire_read)\n#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_short_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_short_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_fetch_and_add)\n#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_short_fetch_and_add(addr, val)\n#    define AO_HAVE_short_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* short_fetch_and_add1 */\n\n#if defined(AO_HAVE_short_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_full)\n#  define AO_short_fetch_and_add1_full(addr) \\\n        AO_short_fetch_and_add_full(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_release)\n#  define AO_short_fetch_and_add1_release(addr) \\\n        AO_short_fetch_and_add_release(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_acquire)\n#  define AO_short_fetch_and_add1_acquire(addr) \\\n        AO_short_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_write)\n#  define AO_short_fetch_and_add1_write(addr) \\\n        AO_short_fetch_and_add_write(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_read)\n#  define AO_short_fetch_and_add1_read(addr) \\\n        AO_short_fetch_and_add_read(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_release_write)\n#  define AO_short_fetch_and_add1_release_write(addr) \\\n        AO_short_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1_acquire_read)\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\n        AO_short_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add) &&\\\n    !defined(AO_HAVE_short_fetch_and_add1)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add(addr,1)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add1_full)\n#  if !defined(AO_HAVE_short_fetch_and_add1_release)\n#    define AO_short_fetch_and_add1_release(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add1_acquire)\n#    define AO_short_fetch_and_add1_acquire(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add1_write)\n#    define AO_short_fetch_and_add1_write(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_add1_read)\n#    define AO_short_fetch_and_add1_read(addr) \\\n         AO_short_fetch_and_add1_full(addr)\n#    define AO_HAVE_short_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_short_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_release)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_release(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_acquire)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_write)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_write(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1) && \\\n    defined(AO_HAVE_short_fetch_and_add1_read)\n#  define AO_short_fetch_and_add1(addr) \\\n        AO_short_fetch_and_add1_read(addr)\n#  define AO_HAVE_short_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_fetch_and_add1_full)\n#  define AO_short_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_short_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_short_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add1_write)\n#  define AO_short_fetch_and_add1_release_write(addr) \\\n        AO_short_fetch_and_add1_write(addr)\n#  define AO_HAVE_short_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_add1_release)\n#  define AO_short_fetch_and_add1_release_write(addr) \\\n        AO_short_fetch_and_add1_release(addr)\n#  define AO_HAVE_short_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add1_read)\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\n        AO_short_fetch_and_add1_read(addr)\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_add1_acquire)\n#  define AO_short_fetch_and_add1_acquire_read(addr) \\\n        AO_short_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_fetch_and_add1_acquire_read)\n#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_fetch_and_add1)\n#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_add1(addr)\n#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* short_fetch_and_sub1 */\n\n#if defined(AO_HAVE_short_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_full)\n#  define AO_short_fetch_and_sub1_full(addr) \\\n        AO_short_fetch_and_add_full(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_release)\n#  define AO_short_fetch_and_sub1_release(addr) \\\n        AO_short_fetch_and_add_release(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#  define AO_short_fetch_and_sub1_acquire(addr) \\\n        AO_short_fetch_and_add_acquire(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_write)\n#  define AO_short_fetch_and_sub1_write(addr) \\\n        AO_short_fetch_and_add_write(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_read)\n#  define AO_short_fetch_and_sub1_read(addr) \\\n        AO_short_fetch_and_add_read(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_release_write)\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\n        AO_short_fetch_and_add_release_write(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1_acquire_read)\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\n        AO_short_fetch_and_add_acquire_read(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_short_fetch_and_add) &&\\\n    !defined(AO_HAVE_short_fetch_and_sub1)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_add(addr,(unsigned short)(-1))\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_short_fetch_and_sub1_release)\n#    define AO_short_fetch_and_sub1_release(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#    define AO_short_fetch_and_sub1_acquire(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_sub1_write)\n#    define AO_short_fetch_and_sub1_write(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_short_fetch_and_sub1_read)\n#    define AO_short_fetch_and_sub1_read(addr) \\\n         AO_short_fetch_and_sub1_full(addr)\n#    define AO_HAVE_short_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_short_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_release)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_release(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_write)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_write(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_read)\n#  define AO_short_fetch_and_sub1(addr) \\\n        AO_short_fetch_and_sub1_read(addr)\n#  define AO_HAVE_short_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_short_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_short_fetch_and_sub1_full)\n#  define AO_short_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_short_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_short_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_write)\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\n        AO_short_fetch_and_sub1_write(addr)\n#  define AO_HAVE_short_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_release)\n#  define AO_short_fetch_and_sub1_release_write(addr) \\\n        AO_short_fetch_and_sub1_release(addr)\n#  define AO_HAVE_short_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_read)\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\n        AO_short_fetch_and_sub1_read(addr)\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_short_fetch_and_sub1_acquire)\n#  define AO_short_fetch_and_sub1_acquire_read(addr) \\\n        AO_short_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_short_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_short_fetch_and_sub1_acquire_read)\n#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_short_fetch_and_sub1)\n#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_short_fetch_and_sub1(addr)\n#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n\n/* int_load */\n#if defined(AO_HAVE_int_load_acquire) && !defined(AO_HAVE_int_load)\n#  define AO_int_load(addr) AO_int_load_acquire(addr)\n#  define AO_HAVE_int_load\n#endif\n\n#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_acquire)\n#  define AO_int_load_acquire(addr) AO_int_load_full(addr)\n#  define AO_HAVE_int_load_acquire\n#endif\n\n#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_read)\n#  define AO_int_load_read(addr) AO_int_load_full(addr)\n#  define AO_HAVE_int_load_read\n#endif\n\n#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_acquire)\n#  define AO_int_load_acquire_read(addr) AO_int_load_acquire(addr)\n#  define AO_HAVE_int_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_load_acquire)\n   AO_INLINE unsigned int\n   AO_int_load_acquire(const volatile unsigned int *addr)\n   {\n     unsigned int result = AO_int_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_int_load_acquire\n#endif\n\n#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_int_load_read)\n   AO_INLINE unsigned int\n   AO_int_load_read(const volatile unsigned int *addr)\n   {\n     unsigned int result = AO_int_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_int_load_read\n#endif\n\n#if defined(AO_HAVE_int_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_load_full)\n#  define AO_int_load_full(addr) (AO_nop_full(), AO_int_load_acquire(addr))\n#  define AO_HAVE_int_load_full\n#endif\n\n#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_read)\n#  define AO_int_load_acquire_read(addr) AO_int_load_read(addr)\n#  define AO_HAVE_int_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_int_load_acquire_read) && !defined(AO_HAVE_int_load)\n#  define AO_int_load(addr) AO_int_load_acquire_read(addr)\n#  define AO_HAVE_int_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_load_acquire_read)\n#    define AO_int_load_dd_acquire_read(addr) \\\n        AO_int_load_acquire_read(addr)\n#    define AO_HAVE_int_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_load)\n#    define AO_int_load_dd_acquire_read(addr) \\\n        AO_int_load(addr)\n#    define AO_HAVE_int_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* int_store */\n\n#if defined(AO_HAVE_int_store_release) && !defined(AO_HAVE_int_store)\n#  define AO_int_store(addr, val) AO_int_store_release(addr,val)\n#  define AO_HAVE_int_store\n#endif\n\n#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_release)\n#  define AO_int_store_release(addr,val) AO_int_store_full(addr,val)\n#  define AO_HAVE_int_store_release\n#endif\n\n#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_write)\n#  define AO_int_store_write(addr,val) AO_int_store_full(addr,val)\n#  define AO_HAVE_int_store_write\n#endif\n\n#if defined(AO_HAVE_int_store_release) && \\\n        !defined(AO_HAVE_int_store_release_write)\n#  define AO_int_store_release_write(addr, val) \\\n        AO_int_store_release(addr,val)\n#  define AO_HAVE_int_store_release_write\n#endif\n\n#if defined(AO_HAVE_int_store_write) && !defined(AO_HAVE_int_store)\n#  define AO_int_store(addr, val) AO_int_store_write(addr,val)\n#  define AO_HAVE_int_store\n#endif\n\n#if defined(AO_HAVE_int_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_store_release)\n#  define AO_int_store_release(addr,val) \\\n        (AO_nop_full(), AO_int_store(addr,val))\n#  define AO_HAVE_int_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_int_store) && \\\n     !defined(AO_HAVE_int_store_write)\n#  define AO_int_store_write(addr, val) \\\n        (AO_nop_write(), AO_int_store(addr,val))\n#  define AO_HAVE_int_store_write\n#endif\n\n#if defined(AO_HAVE_int_store_write) && \\\n     !defined(AO_HAVE_int_store_release_write)\n#  define AO_int_store_release_write(addr, val) AO_int_store_write(addr,val)\n#  define AO_HAVE_int_store_release_write\n#endif\n\n#if defined(AO_HAVE_int_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_store_full)\n#  define AO_int_store_full(addr, val) \\\n        (AO_int_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_int_store_full\n#endif\n\n\n/* int_fetch_and_add */\n#if defined(AO_HAVE_int_compare_and_swap_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_int_fetch_and_add_full(volatile unsigned int *addr,\n                               unsigned int incr)\n   {\n     unsigned int old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_int_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_int_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_int_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_int_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_int_fetch_and_add_acquire(volatile unsigned int *addr,\n                                  unsigned int incr)\n   {\n     unsigned int old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_int_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_int_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_int_compare_and_swap_release) && \\\n    !defined(AO_HAVE_int_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_int_fetch_and_add_release(volatile unsigned int *addr,\n                                  unsigned int incr)\n   {\n     unsigned int old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_int_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_int_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add_full)\n#  if !defined(AO_HAVE_int_fetch_and_add_release)\n#    define AO_int_fetch_and_add_release(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add_acquire)\n#    define AO_int_fetch_and_add_acquire(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add_write)\n#    define AO_int_fetch_and_add_write(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add_read)\n#    define AO_int_fetch_and_add_read(addr, val) \\\n         AO_int_fetch_and_add_full(addr, val)\n#    define AO_HAVE_int_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_int_fetch_and_add_full */\n\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_release)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_release(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_acquire)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_write)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_write(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add) && \\\n    defined(AO_HAVE_int_fetch_and_add_read)\n#  define AO_int_fetch_and_add(addr, val) \\\n        AO_int_fetch_and_add_read(addr, val)\n#  define AO_HAVE_int_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add_full)\n#  define AO_int_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_int_fetch_and_add_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add_write)\n#  define AO_int_fetch_and_add_release_write(addr, val) \\\n        AO_int_fetch_and_add_write(addr, val)\n#  define AO_HAVE_int_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add_release)\n#  define AO_int_fetch_and_add_release_write(addr, val) \\\n        AO_int_fetch_and_add_release(addr, val)\n#  define AO_HAVE_int_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add_read)\n#  define AO_int_fetch_and_add_acquire_read(addr, val) \\\n        AO_int_fetch_and_add_read(addr, val)\n#  define AO_HAVE_int_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add_acquire)\n#  define AO_int_fetch_and_add_acquire_read(addr, val) \\\n        AO_int_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_int_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_fetch_and_add_acquire_read)\n#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_int_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_int_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_fetch_and_add)\n#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_int_fetch_and_add(addr, val)\n#    define AO_HAVE_int_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* int_fetch_and_add1 */\n\n#if defined(AO_HAVE_int_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_full)\n#  define AO_int_fetch_and_add1_full(addr) \\\n        AO_int_fetch_and_add_full(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1_release(addr) \\\n        AO_int_fetch_and_add_release(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1_acquire(addr) \\\n        AO_int_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_write)\n#  define AO_int_fetch_and_add1_write(addr) \\\n        AO_int_fetch_and_add_write(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_read)\n#  define AO_int_fetch_and_add1_read(addr) \\\n        AO_int_fetch_and_add_read(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_release_write)\n#  define AO_int_fetch_and_add1_release_write(addr) \\\n        AO_int_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1_acquire_read)\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\n        AO_int_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add) &&\\\n    !defined(AO_HAVE_int_fetch_and_add1)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add(addr,1)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add1_full)\n#  if !defined(AO_HAVE_int_fetch_and_add1_release)\n#    define AO_int_fetch_and_add1_release(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add1_acquire)\n#    define AO_int_fetch_and_add1_acquire(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add1_write)\n#    define AO_int_fetch_and_add1_write(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_add1_read)\n#    define AO_int_fetch_and_add1_read(addr) \\\n         AO_int_fetch_and_add1_full(addr)\n#    define AO_HAVE_int_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_int_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_release(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_write)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_write(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1) && \\\n    defined(AO_HAVE_int_fetch_and_add1_read)\n#  define AO_int_fetch_and_add1(addr) \\\n        AO_int_fetch_and_add1_read(addr)\n#  define AO_HAVE_int_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_fetch_and_add1_full)\n#  define AO_int_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_int_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_int_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add1_write)\n#  define AO_int_fetch_and_add1_release_write(addr) \\\n        AO_int_fetch_and_add1_write(addr)\n#  define AO_HAVE_int_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_add1_release)\n#  define AO_int_fetch_and_add1_release_write(addr) \\\n        AO_int_fetch_and_add1_release(addr)\n#  define AO_HAVE_int_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add1_read)\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\n        AO_int_fetch_and_add1_read(addr)\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_add1_acquire)\n#  define AO_int_fetch_and_add1_acquire_read(addr) \\\n        AO_int_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_fetch_and_add1_acquire_read)\n#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_fetch_and_add1)\n#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_add1(addr)\n#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* int_fetch_and_sub1 */\n\n#if defined(AO_HAVE_int_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_full)\n#  define AO_int_fetch_and_sub1_full(addr) \\\n        AO_int_fetch_and_add_full(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1_release(addr) \\\n        AO_int_fetch_and_add_release(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1_acquire(addr) \\\n        AO_int_fetch_and_add_acquire(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_write)\n#  define AO_int_fetch_and_sub1_write(addr) \\\n        AO_int_fetch_and_add_write(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_read)\n#  define AO_int_fetch_and_sub1_read(addr) \\\n        AO_int_fetch_and_add_read(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_release_write)\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\n        AO_int_fetch_and_add_release_write(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1_acquire_read)\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\n        AO_int_fetch_and_add_acquire_read(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_int_fetch_and_add) &&\\\n    !defined(AO_HAVE_int_fetch_and_sub1)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_add(addr,(unsigned int)(-1))\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_int_fetch_and_sub1_release)\n#    define AO_int_fetch_and_sub1_release(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#    define AO_int_fetch_and_sub1_acquire(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_sub1_write)\n#    define AO_int_fetch_and_sub1_write(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_int_fetch_and_sub1_read)\n#    define AO_int_fetch_and_sub1_read(addr) \\\n         AO_int_fetch_and_sub1_full(addr)\n#    define AO_HAVE_int_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_int_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_release(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_write)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_write(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_read)\n#  define AO_int_fetch_and_sub1(addr) \\\n        AO_int_fetch_and_sub1_read(addr)\n#  define AO_HAVE_int_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_int_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_int_fetch_and_sub1_full)\n#  define AO_int_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_int_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_int_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_write)\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\n        AO_int_fetch_and_sub1_write(addr)\n#  define AO_HAVE_int_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_release)\n#  define AO_int_fetch_and_sub1_release_write(addr) \\\n        AO_int_fetch_and_sub1_release(addr)\n#  define AO_HAVE_int_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_read)\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\n        AO_int_fetch_and_sub1_read(addr)\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_int_fetch_and_sub1_acquire)\n#  define AO_int_fetch_and_sub1_acquire_read(addr) \\\n        AO_int_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_int_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_int_fetch_and_sub1_acquire_read)\n#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_int_fetch_and_sub1)\n#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_int_fetch_and_sub1(addr)\n#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/generalize.h",
    "content": "/*\n * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * Generalize atomic operations for atomic_ops.h.\n * Should not be included directly.\n *\n * We make no attempt to define useless operations, such as\n * AO_nop_acquire\n * AO_nop_release\n *\n * We have also so far neglected to define some others, which\n * do not appear likely to be useful, e.g. stores with acquire\n * or read barriers.\n *\n * This file is sometimes included twice by atomic_ops.h.\n * All definitions include explicit checks that we are not replacing\n * an earlier definition.  In general, more desirable expansions\n * appear earlier so that we are more likely to use them.\n *\n * We only make safe generalizations, except that by default we define\n * the ...dd_acquire_read operations to be equivalent to those without\n * a barrier.  On platforms for which this is unsafe, the platform-specific\n * file must define AO_NO_DD_ORDERING.\n */\n\n#ifndef ATOMIC_OPS_H\n# error Atomic_ops_generalize.h should not be included directly.\n#endif\n\n#if AO_CHAR_TS_T\n# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \\\n         AO_char_compare_and_swap_full(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \\\n         AO_char_compare_and_swap_acquire(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \\\n         AO_char_compare_and_swap_release(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP(a,o,n) \\\n         AO_char_compare_and_swap(a,o,n)\n#endif\n\n#if AO_AO_TS_T\n# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \\\n         AO_compare_and_swap_full(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \\\n         AO_compare_and_swap_acquire(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \\\n         AO_compare_and_swap_release(a,o,n)\n# define AO_TS_COMPARE_AND_SWAP(a,o,n) \\\n         AO_compare_and_swap(a,o,n)\n#endif\n\n/* Generate test_and_set_full, if necessary and possible.       */\n#if !defined(AO_HAVE_test_and_set) && \\\n    !defined(AO_HAVE_test_and_set_release) && \\\n    !defined(AO_HAVE_test_and_set_acquire) && \\\n    !defined(AO_HAVE_test_and_set_read) && \\\n    !defined(AO_HAVE_test_and_set_full)\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_full) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_full)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_full(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP_FULL(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set_full\n#  endif /* AO_HAVE_compare_and_swap_full */\n\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_acquire) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_acquire)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_acquire(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP_ACQUIRE(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set_acquire\n#  endif /* AO_HAVE_compare_and_swap_acquire */\n\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_release) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_release)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_release(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP_RELEASE(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set_release\n#  endif /* AO_HAVE_compare_and_swap_release */\n\n#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap) || \\\n      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set(volatile AO_TS_t *addr)\n     {\n       if (AO_TS_COMPARE_AND_SWAP(addr, AO_TS_CLEAR, AO_TS_SET))\n         return AO_TS_CLEAR;\n       else\n         return AO_TS_SET;\n     }\n#    define AO_HAVE_test_and_set\n#  endif /* AO_HAVE_compare_and_swap */\n\n#  if defined(AO_HAVE_test_and_set) && defined(AO_HAVE_nop_full) \\\n      && !defined(AO_HAVE_test_and_set_acquire)\n     AO_INLINE AO_TS_VAL_t\n     AO_test_and_set_acquire(volatile AO_TS_t *addr)\n     {\n       AO_TS_VAL_t result = AO_test_and_set(addr);\n       AO_nop_full();\n       return result;\n     }\n#    define AO_HAVE_test_and_set_acquire\n#  endif\n\n#endif /* No prior test and set */\n\n/* Nop */\n#if !defined(AO_HAVE_nop)\n   AO_INLINE void AO_nop(void) {}\n#  define AO_HAVE_nop\n#endif\n\n#if defined(AO_HAVE_test_and_set_full) && !defined(AO_HAVE_nop_full)\n   AO_INLINE void\n   AO_nop_full(void)\n   {\n     AO_TS_t dummy = AO_TS_INITIALIZER;\n     AO_test_and_set_full(&dummy);\n   }\n#  define AO_HAVE_nop_full\n#endif\n\n#if defined(AO_HAVE_nop_acquire)\n#  error AO_nop_acquire is useless: dont define.\n#endif\n#if defined(AO_HAVE_nop_release)\n#  error AO_nop_release is useless: dont define.\n#endif\n\n#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_read)\n#  define AO_nop_read() AO_nop_full()\n#  define AO_HAVE_nop_read\n#endif\n\n#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_write)\n#  define AO_nop_write() AO_nop_full()\n#  define AO_HAVE_nop_write\n#endif\n\n/* Load */\n#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_acquire)\n#  define AO_load_acquire(addr) AO_load_full(addr)\n#  define AO_HAVE_load_acquire\n#endif\n\n#if defined(AO_HAVE_load_acquire) && !defined(AO_HAVE_load)\n#  define AO_load(addr) AO_load_acquire(addr)\n#  define AO_HAVE_load\n#endif\n\n#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_read)\n#  define AO_load_read(addr) AO_load_full(addr)\n#  define AO_HAVE_load_read\n#endif\n\n#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_acquire)\n#  define AO_load_acquire_read(addr) AO_load_acquire(addr)\n#  define AO_HAVE_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_load_acquire)\n   AO_INLINE AO_t\n   AO_load_acquire(const volatile AO_t *addr)\n   {\n     AO_t result = AO_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_load_acquire\n#endif\n\n#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_read) && \\\n    !defined(AO_HAVE_load_read)\n   AO_INLINE AO_t\n   AO_load_read(const volatile AO_t *addr)\n   {\n     AO_t result = AO_load(addr);\n     /* Acquire barrier would be useless, since the load could be delayed  */\n     /* beyond it.                                                         */\n     AO_nop_read();\n     return result;\n   }\n#  define AO_HAVE_load_read\n#endif\n\n#if defined(AO_HAVE_load_acquire) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_load_full)\n#  define AO_load_full(addr) (AO_nop_full(), AO_load_acquire(addr))\n#  define AO_HAVE_load_full\n#endif\n\n#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_read)\n#  define AO_load_acquire_read(addr) AO_load_read(addr)\n#  define AO_HAVE_load_acquire_read\n#endif\n\n#if defined(AO_HAVE_load_acquire_read) && !defined(AO_HAVE_load)\n#  define AO_load(addr) AO_load_acquire_read(addr)\n#  define AO_HAVE_load\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_load_acquire_read)\n#    define AO_load_dd_acquire_read(addr) AO_load_acquire_read(addr)\n#    define AO_HAVE_load_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_load)\n#    define AO_load_dd_acquire_read(addr) AO_load(addr)\n#    define AO_HAVE_load_dd_acquire_read\n#  endif\n#endif\n\n\n/* Store */\n\n#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_release)\n#  define AO_store_release(addr,val) AO_store_full(addr,val)\n#  define AO_HAVE_store_release\n#endif\n\n#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store)\n#  define AO_store(addr, val) AO_store_release(addr,val)\n#  define AO_HAVE_store\n#endif\n\n#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_write)\n#  define AO_store_write(addr,val) AO_store_full(addr,val)\n#  define AO_HAVE_store_write\n#endif\n\n#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store_release_write)\n#  define AO_store_release_write(addr, val) AO_store_release(addr,val)\n#  define AO_HAVE_store_release_write\n#endif\n\n#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store)\n#  define AO_store(addr, val) AO_store_write(addr,val)\n#  define AO_HAVE_store\n#endif\n\n#if defined(AO_HAVE_store) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_store_release)\n#  define AO_store_release(addr,val) (AO_nop_full(), AO_store(addr,val))\n#  define AO_HAVE_store_release\n#endif\n\n#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_store) && \\\n     !defined(AO_HAVE_store_write)\n#  define AO_store_write(addr, val) (AO_nop_write(), AO_store(addr,val))\n#  define AO_HAVE_store_write\n#endif\n\n#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store_release_write)\n#  define AO_store_release_write(addr, val) AO_store_write(addr,val)\n#  define AO_HAVE_store_release_write\n#endif\n\n#if defined(AO_HAVE_store_release) && defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_store_full)\n#  define AO_store_full(addr, val) (AO_store_release(addr, val), AO_nop_full())\n#  define AO_HAVE_store_full\n#endif\n\n/* NEC LE-IT: Test and set */\n#if defined(AO_HAVE_test_and_set) && \\\n        defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_test_and_set_release)\n#       define AO_test_and_set_release(addr) \\\n        (AO_nop_full(), AO_test_and_set(addr))\n#  define AO_HAVE_test_and_set_release\n#endif\n\n#if defined(AO_HAVE_test_and_set) && \\\n        defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_test_and_set_acquire)\nAO_INLINE AO_TS_t\nAO_test_and_set_acquire(volatile AO_TS_t *addr)\n{\n        AO_TS_t res = AO_test_and_set(addr);\n        AO_nop_full();\n        return res;\n}\n#  define AO_HAVE_test_and_set_acquire\n#endif\n\n\n/* Fetch_and_add */\n/* We first try to implement fetch_and_add variants in terms    */\n/* of the corresponding compare_and_swap variants to minimize   */\n/* adding barriers.                                             */\n#if defined(AO_HAVE_compare_and_swap_full) && \\\n    !defined(AO_HAVE_fetch_and_add_full)\n   AO_INLINE AO_t\n   AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_full(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add_full\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_acquire) && \\\n    !defined(AO_HAVE_fetch_and_add_acquire)\n   AO_INLINE AO_t\n   AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_acquire(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add_acquire\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_release) && \\\n    !defined(AO_HAVE_fetch_and_add_release)\n   AO_INLINE AO_t\n   AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_release(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add_release\n#endif\n\n#if defined(AO_HAVE_compare_and_swap) && \\\n    !defined(AO_HAVE_fetch_and_add)\n   AO_INLINE AO_t\n   AO_fetch_and_add(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap(addr, old, old+incr));\n     return old;\n   }\n#  define AO_HAVE_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_fetch_and_add_full)\n#  if !defined(AO_HAVE_fetch_and_add_release)\n#    define AO_fetch_and_add_release(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_release\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add_acquire)\n#    define AO_fetch_and_add_acquire(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_acquire\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add_write)\n#    define AO_fetch_and_add_write(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_write\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add_read)\n#    define AO_fetch_and_add_read(addr, val) \\\n         AO_fetch_and_add_full(addr, val)\n#    define AO_HAVE_fetch_and_add_read\n#  endif\n#endif /* AO_HAVE_fetch_and_add_full */\n\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_release)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_release(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_acquire)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_write)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_write(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n#if !defined(AO_HAVE_fetch_and_add) && \\\n    defined(AO_HAVE_fetch_and_add_read)\n#  define AO_fetch_and_add(addr, val) \\\n        AO_fetch_and_add_read(addr, val)\n#  define AO_HAVE_fetch_and_add\n#endif\n\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_fetch_and_add_full)\n#  define AO_fetch_and_add_full(addr, val) \\\n        (AO_nop_full(), AO_fetch_and_add_acquire(addr, val))\n#  define AO_HAVE_fetch_and_add_full\n#endif\n\n#if !defined(AO_HAVE_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_fetch_and_add_write)\n#  define AO_fetch_and_add_release_write(addr, val) \\\n        AO_fetch_and_add_write(addr, val)\n#  define AO_HAVE_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add_release_write) && \\\n    defined(AO_HAVE_fetch_and_add_release)\n#  define AO_fetch_and_add_release_write(addr, val) \\\n        AO_fetch_and_add_release(addr, val)\n#  define AO_HAVE_fetch_and_add_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add_read)\n#  define AO_fetch_and_add_acquire_read(addr, val) \\\n        AO_fetch_and_add_read(addr, val)\n#  define AO_HAVE_fetch_and_add_acquire_read\n#endif\n#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add_acquire)\n#  define AO_fetch_and_add_acquire_read(addr, val) \\\n        AO_fetch_and_add_acquire(addr, val)\n#  define AO_HAVE_fetch_and_add_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_fetch_and_add_acquire_read)\n#    define AO_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_fetch_and_add_acquire_read(addr, val)\n#    define AO_HAVE_fetch_and_add_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_fetch_and_add)\n#    define AO_fetch_and_add_dd_acquire_read(addr, val) \\\n        AO_fetch_and_add(addr, val)\n#    define AO_HAVE_fetch_and_add_dd_acquire_read\n#  endif\n#endif\n\n/* Fetch_and_add1 */\n\n#if defined(AO_HAVE_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_fetch_and_add1_full)\n#  define AO_fetch_and_add1_full(addr) AO_fetch_and_add_full(addr,1)\n#  define AO_HAVE_fetch_and_add1_full\n#endif\n#if defined(AO_HAVE_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_fetch_and_add1_release)\n#  define AO_fetch_and_add1_release(addr) AO_fetch_and_add_release(addr,1)\n#  define AO_HAVE_fetch_and_add1_release\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_fetch_and_add1_acquire)\n#  define AO_fetch_and_add1_acquire(addr) AO_fetch_and_add_acquire(addr,1)\n#  define AO_HAVE_fetch_and_add1_acquire\n#endif\n#if defined(AO_HAVE_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_fetch_and_add1_write)\n#  define AO_fetch_and_add1_write(addr) AO_fetch_and_add_write(addr,1)\n#  define AO_HAVE_fetch_and_add1_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_fetch_and_add1_read)\n#  define AO_fetch_and_add1_read(addr) AO_fetch_and_add_read(addr,1)\n#  define AO_HAVE_fetch_and_add1_read\n#endif\n#if defined(AO_HAVE_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_fetch_and_add1_release_write)\n#  define AO_fetch_and_add1_release_write(addr) \\\n        AO_fetch_and_add_release_write(addr,1)\n#  define AO_HAVE_fetch_and_add1_release_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_fetch_and_add1_acquire_read)\n#  define AO_fetch_and_add1_acquire_read(addr) \\\n        AO_fetch_and_add_acquire_read(addr,1)\n#  define AO_HAVE_fetch_and_add1_acquire_read\n#endif\n#if defined(AO_HAVE_fetch_and_add) &&\\\n    !defined(AO_HAVE_fetch_and_add1)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add(addr,1)\n#  define AO_HAVE_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_fetch_and_add1_full)\n#  if !defined(AO_HAVE_fetch_and_add1_release)\n#    define AO_fetch_and_add1_release(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_release\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add1_acquire)\n#    define AO_fetch_and_add1_acquire(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_acquire\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add1_write)\n#    define AO_fetch_and_add1_write(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_write\n#  endif\n#  if !defined(AO_HAVE_fetch_and_add1_read)\n#    define AO_fetch_and_add1_read(addr) \\\n         AO_fetch_and_add1_full(addr)\n#    define AO_HAVE_fetch_and_add1_read\n#  endif\n#endif /* AO_HAVE_fetch_and_add1_full */\n\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_release)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_release(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_acquire)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_write)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_write(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n#if !defined(AO_HAVE_fetch_and_add1) && \\\n    defined(AO_HAVE_fetch_and_add1_read)\n#  define AO_fetch_and_add1(addr) \\\n        AO_fetch_and_add1_read(addr)\n#  define AO_HAVE_fetch_and_add1\n#endif\n\n#if defined(AO_HAVE_fetch_and_add1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_fetch_and_add1_full)\n#  define AO_fetch_and_add1_full(addr) \\\n        (AO_nop_full(), AO_fetch_and_add1_acquire(addr))\n#  define AO_HAVE_fetch_and_add1_full\n#endif\n\n#if !defined(AO_HAVE_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_fetch_and_add1_write)\n#  define AO_fetch_and_add1_release_write(addr) \\\n        AO_fetch_and_add1_write(addr)\n#  define AO_HAVE_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add1_release_write) && \\\n    defined(AO_HAVE_fetch_and_add1_release)\n#  define AO_fetch_and_add1_release_write(addr) \\\n        AO_fetch_and_add1_release(addr)\n#  define AO_HAVE_fetch_and_add1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add1_read)\n#  define AO_fetch_and_add1_acquire_read(addr) \\\n        AO_fetch_and_add1_read(addr)\n#  define AO_HAVE_fetch_and_add1_acquire_read\n#endif\n#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_add1_acquire)\n#  define AO_fetch_and_add1_acquire_read(addr) \\\n        AO_fetch_and_add1_acquire(addr)\n#  define AO_HAVE_fetch_and_add1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_fetch_and_add1_acquire_read)\n#    define AO_fetch_and_add1_dd_acquire_read(addr) \\\n        AO_fetch_and_add1_acquire_read(addr)\n#    define AO_HAVE_fetch_and_add1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_fetch_and_add1)\n#    define AO_fetch_and_add1_dd_acquire_read(addr) AO_fetch_and_add1(addr)\n#    define AO_HAVE_fetch_and_add1_dd_acquire_read\n#  endif\n#endif\n\n/* Fetch_and_sub1 */\n\n#if defined(AO_HAVE_fetch_and_add_full) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_full)\n#  define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_full\n#endif\n#if defined(AO_HAVE_fetch_and_add_release) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_release)\n#  define AO_fetch_and_sub1_release(addr) \\\n        AO_fetch_and_add_release(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_release\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_acquire)\n#  define AO_fetch_and_sub1_acquire(addr) \\\n        AO_fetch_and_add_acquire(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_acquire\n#endif\n#if defined(AO_HAVE_fetch_and_add_write) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_write)\n#  define AO_fetch_and_sub1_write(addr) \\\n        AO_fetch_and_add_write(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_read) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_read)\n#  define AO_fetch_and_sub1_read(addr) \\\n        AO_fetch_and_add_read(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_read\n#endif\n#if defined(AO_HAVE_fetch_and_add_release_write) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_release_write)\n#  define AO_fetch_and_sub1_release_write(addr) \\\n        AO_fetch_and_add_release_write(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_release_write\n#endif\n#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\\\n    !defined(AO_HAVE_fetch_and_sub1_acquire_read)\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\n        AO_fetch_and_add_acquire_read(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1_acquire_read\n#endif\n#if defined(AO_HAVE_fetch_and_add) &&\\\n    !defined(AO_HAVE_fetch_and_sub1)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_add(addr,(AO_t)(-1))\n#  define AO_HAVE_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_fetch_and_sub1_full)\n#  if !defined(AO_HAVE_fetch_and_sub1_release)\n#    define AO_fetch_and_sub1_release(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_release\n#  endif\n#  if !defined(AO_HAVE_fetch_and_sub1_acquire)\n#    define AO_fetch_and_sub1_acquire(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_acquire\n#  endif\n#  if !defined(AO_HAVE_fetch_and_sub1_write)\n#    define AO_fetch_and_sub1_write(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_write\n#  endif\n#  if !defined(AO_HAVE_fetch_and_sub1_read)\n#    define AO_fetch_and_sub1_read(addr) \\\n         AO_fetch_and_sub1_full(addr)\n#    define AO_HAVE_fetch_and_sub1_read\n#  endif\n#endif /* AO_HAVE_fetch_and_sub1_full */\n\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_release)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_release(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_acquire)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_write)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_write(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1) && \\\n    defined(AO_HAVE_fetch_and_sub1_read)\n#  define AO_fetch_and_sub1(addr) \\\n        AO_fetch_and_sub1_read(addr)\n#  define AO_HAVE_fetch_and_sub1\n#endif\n\n#if defined(AO_HAVE_fetch_and_sub1_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_fetch_and_sub1_full)\n#  define AO_fetch_and_sub1_full(addr) \\\n        (AO_nop_full(), AO_fetch_and_sub1_acquire(addr))\n#  define AO_HAVE_fetch_and_sub1_full\n#endif\n\n#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_fetch_and_sub1_write)\n#  define AO_fetch_and_sub1_release_write(addr) \\\n        AO_fetch_and_sub1_write(addr)\n#  define AO_HAVE_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \\\n    defined(AO_HAVE_fetch_and_sub1_release)\n#  define AO_fetch_and_sub1_release_write(addr) \\\n        AO_fetch_and_sub1_release(addr)\n#  define AO_HAVE_fetch_and_sub1_release_write\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_sub1_read)\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\n        AO_fetch_and_sub1_read(addr)\n#  define AO_HAVE_fetch_and_sub1_acquire_read\n#endif\n#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \\\n    defined(AO_HAVE_fetch_and_sub1_acquire)\n#  define AO_fetch_and_sub1_acquire_read(addr) \\\n        AO_fetch_and_sub1_acquire(addr)\n#  define AO_HAVE_fetch_and_sub1_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_fetch_and_sub1_acquire_read)\n#    define AO_fetch_and_sub1_dd_acquire_read(addr) \\\n        AO_fetch_and_sub1_acquire_read(addr)\n#    define AO_HAVE_fetch_and_sub1_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_fetch_and_sub1)\n#    define AO_fetch_and_sub1_dd_acquire_read(addr) AO_fetch_and_sub1(addr)\n#    define AO_HAVE_fetch_and_sub1_dd_acquire_read\n#  endif\n#endif\n\n/* Atomic or */\n#if defined(AO_HAVE_compare_and_swap_full) && \\\n    !defined(AO_HAVE_or_full)\n   AO_INLINE void\n   AO_or_full(volatile AO_t *addr, AO_t incr)\n   {\n     AO_t old;\n     do\n       {\n         old = *addr;\n       }\n     while (!AO_compare_and_swap_full(addr, old, (old | incr)));\n   }\n#  define AO_HAVE_or_full\n#endif\n\n#if defined(AO_HAVE_or_full)\n#  if !defined(AO_HAVE_or_release)\n#    define AO_or_release(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_release\n#  endif\n#  if !defined(AO_HAVE_or_acquire)\n#    define AO_or_acquire(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_acquire\n#  endif\n#  if !defined(AO_HAVE_or_write)\n#    define AO_or_write(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_write\n#  endif\n#  if !defined(AO_HAVE_or_read)\n#    define AO_or_read(addr, val) \\\n         AO_or_full(addr, val)\n#    define AO_HAVE_or_read\n#  endif\n#endif /* AO_HAVE_or_full */\n\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_release)\n#  define AO_or(addr, val) \\\n        AO_or_release(addr, val)\n#  define AO_HAVE_or\n#endif\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_acquire)\n#  define AO_or(addr, val) \\\n        AO_or_acquire(addr, val)\n#  define AO_HAVE_or\n#endif\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_write)\n#  define AO_or(addr, val) \\\n        AO_or_write(addr, val)\n#  define AO_HAVE_or\n#endif\n#if !defined(AO_HAVE_or) && \\\n    defined(AO_HAVE_or_read)\n#  define AO_or(addr, val) \\\n        AO_or_read(addr, val)\n#  define AO_HAVE_or\n#endif\n\n#if defined(AO_HAVE_or_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_or_full)\n#  define AO_or_full(addr, val) \\\n        (AO_nop_full(), AO_or_acquire(addr, val))\n#endif\n\n#if !defined(AO_HAVE_or_release_write) && \\\n    defined(AO_HAVE_or_write)\n#  define AO_or_release_write(addr, val) \\\n        AO_or_write(addr, val)\n#  define AO_HAVE_or_release_write\n#endif\n#if !defined(AO_HAVE_or_release_write) && \\\n    defined(AO_HAVE_or_release)\n#  define AO_or_release_write(addr, val) \\\n        AO_or_release(addr, val)\n#  define AO_HAVE_or_release_write\n#endif\n#if !defined(AO_HAVE_or_acquire_read) && \\\n    defined(AO_HAVE_or_read)\n#  define AO_or_acquire_read(addr, val) \\\n        AO_or_read(addr, val)\n#  define AO_HAVE_or_acquire_read\n#endif\n#if !defined(AO_HAVE_or_acquire_read) && \\\n    defined(AO_HAVE_or_acquire)\n#  define AO_or_acquire_read(addr, val) \\\n        AO_or_acquire(addr, val)\n#  define AO_HAVE_or_acquire_read\n#endif\n\n/* dd_aquire_read is meaningless.       */\n\n/* Test_and_set */\n\n#if defined(AO_HAVE_test_and_set_full)\n#  if !defined(AO_HAVE_test_and_set_release)\n#    define AO_test_and_set_release(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_release\n#  endif\n#  if !defined(AO_HAVE_test_and_set_acquire)\n#    define AO_test_and_set_acquire(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_acquire\n#  endif\n#  if !defined(AO_HAVE_test_and_set_write)\n#    define AO_test_and_set_write(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_write\n#  endif\n#  if !defined(AO_HAVE_test_and_set_read)\n#    define AO_test_and_set_read(addr) \\\n         AO_test_and_set_full(addr)\n#    define AO_HAVE_test_and_set_read\n#  endif\n#endif /* AO_HAVE_test_and_set_full */\n\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_release)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_release(addr)\n#  define AO_HAVE_test_and_set\n#endif\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_acquire)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_acquire(addr)\n#  define AO_HAVE_test_and_set\n#endif\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_write)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_write(addr)\n#  define AO_HAVE_test_and_set\n#endif\n#if !defined(AO_HAVE_test_and_set) && \\\n    defined(AO_HAVE_test_and_set_read)\n#  define AO_test_and_set(addr) \\\n        AO_test_and_set_read(addr)\n#  define AO_HAVE_test_and_set\n#endif\n\n#if defined(AO_HAVE_test_and_set_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_test_and_set_full)\n#  define AO_test_and_set_full(addr) \\\n        (AO_nop_full(), AO_test_and_set_acquire(addr))\n#  define AO_HAVE_test_and_set_full\n#endif\n\n#if !defined(AO_HAVE_test_and_set_release_write) && \\\n    defined(AO_HAVE_test_and_set_write)\n#  define AO_test_and_set_release_write(addr) \\\n        AO_test_and_set_write(addr)\n#  define AO_HAVE_test_and_set_release_write\n#endif\n#if !defined(AO_HAVE_test_and_set_release_write) && \\\n    defined(AO_HAVE_test_and_set_release)\n#  define AO_test_and_set_release_write(addr) \\\n        AO_test_and_set_release(addr)\n#  define AO_HAVE_test_and_set_release_write\n#endif\n#if !defined(AO_HAVE_test_and_set_acquire_read) && \\\n    defined(AO_HAVE_test_and_set_read)\n#  define AO_test_and_set_acquire_read(addr) \\\n        AO_test_and_set_read(addr)\n#  define AO_HAVE_test_and_set_acquire_read\n#endif\n#if !defined(AO_HAVE_test_and_set_acquire_read) && \\\n    defined(AO_HAVE_test_and_set_acquire)\n#  define AO_test_and_set_acquire_read(addr) \\\n        AO_test_and_set_acquire(addr)\n#  define AO_HAVE_test_and_set_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_test_and_set_acquire_read)\n#    define AO_test_and_set_dd_acquire_read(addr) \\\n        AO_test_and_set_acquire_read(addr)\n#    define AO_HAVE_test_and_set_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_test_and_set)\n#    define AO_test_and_set_dd_acquire_read(addr) AO_test_and_set(addr)\n#    define AO_HAVE_test_and_set_dd_acquire_read\n#  endif\n#endif\n\n/* Compare_and_swap */\n#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_acquire)\n   AO_INLINE int\n   AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val)\n   {\n     int result = AO_compare_and_swap(addr, old, new_val);\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_compare_and_swap_acquire\n#endif\n#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_release)\n#  define AO_compare_and_swap_release(addr, old, new_val) \\\n        (AO_nop_full(), AO_compare_and_swap(addr, old, new_val))\n#  define AO_HAVE_compare_and_swap_release\n#endif\n#if defined(AO_HAVE_compare_and_swap_full)\n#  if !defined(AO_HAVE_compare_and_swap_release)\n#    define AO_compare_and_swap_release(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_release\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_acquire)\n#    define AO_compare_and_swap_acquire(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_acquire\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_write)\n#    define AO_compare_and_swap_write(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_write\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_read)\n#    define AO_compare_and_swap_read(addr, old, new_val) \\\n         AO_compare_and_swap_full(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_read\n#  endif\n#endif /* AO_HAVE_compare_and_swap_full */\n\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_release)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_release(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_acquire)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_acquire(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_write)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_write(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n#if !defined(AO_HAVE_compare_and_swap) && \\\n    defined(AO_HAVE_compare_and_swap_read)\n#  define AO_compare_and_swap(addr, old, new_val) \\\n        AO_compare_and_swap_read(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_compare_and_swap_full)\n#  define AO_compare_and_swap_full(addr, old, new_val) \\\n        (AO_nop_full(), AO_compare_and_swap_acquire(addr, old, new_val))\n#  define AO_HAVE_compare_and_swap_full\n#endif\n\n#if !defined(AO_HAVE_compare_and_swap_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_write)\n#  define AO_compare_and_swap_release_write(addr, old, new_val) \\\n        AO_compare_and_swap_write(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_release)\n#  define AO_compare_and_swap_release_write(addr, old, new_val) \\\n        AO_compare_and_swap_release(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_read)\n#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap_read(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_acquire_read\n#endif\n#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_acquire)\n#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap_acquire(addr, old, new_val)\n#  define AO_HAVE_compare_and_swap_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_compare_and_swap_acquire_read)\n#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap_acquire_read(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_compare_and_swap)\n#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \\\n        AO_compare_and_swap(addr, old, new_val)\n#    define AO_HAVE_compare_and_swap_dd_acquire_read\n#  endif\n#endif\n\n#include \"generalize-small.h\"\n\n/* Compare_double_and_swap_double */\n#if defined(AO_HAVE_compare_double_and_swap_double) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_double_and_swap_double_acquire)\n   AO_INLINE int\n   AO_compare_double_and_swap_double_acquire(volatile AO_double_t *addr,\n                                             AO_t o1, AO_t o2,\n                                             AO_t n1, AO_t n2)\n   {\n     int result = AO_compare_double_and_swap_double(addr, o1, o2, n1, n2);\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_compare_double_and_swap_double_acquire\n#endif\n#if defined(AO_HAVE_compare_double_and_swap_double) \\\n    && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_double_and_swap_double_release)\n#  define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \\\n        (AO_nop_full(), AO_compare_double_and_swap_double(addr, o1, o2, n1, n2))\n#  define AO_HAVE_compare_double_and_swap_double_release\n#endif\n#if defined(AO_HAVE_compare_double_and_swap_double_full)\n#  if !defined(AO_HAVE_compare_double_and_swap_double_release)\n#    define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_release\n#  endif\n#  if !defined(AO_HAVE_compare_double_and_swap_double_acquire)\n#    define AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_acquire\n#  endif\n#  if !defined(AO_HAVE_compare_double_and_swap_double_write)\n#    define AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_write\n#  endif\n#  if !defined(AO_HAVE_compare_double_and_swap_double_read)\n#    define AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2) \\\n         AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_read\n#  endif\n#endif /* AO_HAVE_compare_double_and_swap_double_full */\n\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_release)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_acquire)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_write)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_read)\n#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double\n#endif\n\n#if defined(AO_HAVE_compare_double_and_swap_double_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_compare_double_and_swap_double_full)\n#  define AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2) \\\n        (AO_nop_full(), AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2))\n#  define AO_HAVE_compare_double_and_swap_double_full\n#endif\n\n#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_write)\n#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_release)\n#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_read)\n#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_acquire_read\n#endif\n#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_double_and_swap_double_acquire)\n#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)\n#  define AO_HAVE_compare_double_and_swap_double_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_compare_double_and_swap_double_acquire_read)\n#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_compare_double_and_swap_double)\n#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \\\n        AO_compare_double_and_swap_double(addr, o1, o2, n1, n2)\n#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read\n#  endif\n#endif\n\n/* Compare_and_swap_double */\n#if defined(AO_HAVE_compare_and_swap_double) && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_double_acquire)\n   AO_INLINE int\n   AO_compare_and_swap_double_acquire(volatile AO_double_t *addr,\n                                             AO_t o1,\n                                             AO_t n1, AO_t n2)\n   {\n     int result = AO_compare_and_swap_double(addr, o1, n1, n2);\n     AO_nop_full();\n     return result;\n   }\n#  define AO_HAVE_compare_and_swap_double_acquire\n#endif\n#if defined(AO_HAVE_compare_and_swap_double) \\\n    && defined(AO_HAVE_nop_full)\\\n    && !defined(AO_HAVE_compare_and_swap_double_release)\n#  define AO_compare_and_swap_double_release(addr, o1, n1, n2) \\\n        (AO_nop_full(), AO_compare_and_swap_double(addr, o1, n1, n2))\n#  define AO_HAVE_compare_and_swap_double_release\n#endif\n#if defined(AO_HAVE_compare_and_swap_double_full)\n#  if !defined(AO_HAVE_compare_and_swap_double_release)\n#    define AO_compare_and_swap_double_release(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_release\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_double_acquire)\n#    define AO_compare_and_swap_double_acquire(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_acquire\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_double_write)\n#    define AO_compare_and_swap_double_write(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_write\n#  endif\n#  if !defined(AO_HAVE_compare_and_swap_double_read)\n#    define AO_compare_and_swap_double_read(addr, o1, n1, n2) \\\n         AO_compare_and_swap_double_full(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_read\n#  endif\n#endif /* AO_HAVE_compare_and_swap_double_full */\n\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_release)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_release(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_acquire)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_acquire(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_write)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_write(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double) && \\\n    defined(AO_HAVE_compare_and_swap_double_read)\n#  define AO_compare_and_swap_double(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_read(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double\n#endif\n\n#if defined(AO_HAVE_compare_and_swap_double_acquire) &&\\\n    defined(AO_HAVE_nop_full) && \\\n    !defined(AO_HAVE_compare_and_swap_double_full)\n#  define AO_compare_and_swap_double_full(addr, o1, n1, n2) \\\n        (AO_nop_full(), AO_compare_and_swap_double_acquire(addr, o1, n1, n2))\n#  define AO_HAVE_compare_and_swap_double_full\n#endif\n\n#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_double_write)\n#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_write(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \\\n    defined(AO_HAVE_compare_and_swap_double_release)\n#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_release(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_release_write\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_double_read)\n#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_read(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_acquire_read\n#endif\n#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \\\n    defined(AO_HAVE_compare_and_swap_double_acquire)\n#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_acquire(addr, o1, n1, n2)\n#  define AO_HAVE_compare_and_swap_double_acquire_read\n#endif\n\n#ifdef AO_NO_DD_ORDERING\n#  if defined(AO_HAVE_compare_and_swap_double_acquire_read)\n#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_dd_acquire_read\n#  endif\n#else\n#  if defined(AO_HAVE_compare_and_swap_double)\n#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \\\n        AO_compare_and_swap_double(addr, o1, n1, n2)\n#    define AO_HAVE_compare_and_swap_double_dd_acquire_read\n#  endif\n#endif\n\n/* NEC LE-IT: Convenience functions for AO_double compare and swap which */\n/* types and reads easier in code                                        */\n#if defined(AO_HAVE_compare_double_and_swap_double_release) && \\\n    !defined(AO_HAVE_double_compare_and_swap_release)\nAO_INLINE int\nAO_double_compare_and_swap_release(volatile AO_double_t *addr,\n                                   AO_double_t old_val, AO_double_t new_val)\n{\n        return AO_compare_double_and_swap_double_release(addr,\n                                                         old_val.AO_val1, old_val.AO_val2,\n                                                         new_val.AO_val1, new_val.AO_val2);\n}\n#define AO_HAVE_double_compare_and_swap_release\n#endif\n\n#if defined(AO_HAVE_compare_double_and_swap_double_acquire) && \\\n    !defined(AO_HAVE_double_compare_and_swap_acquire)\nAO_INLINE int\nAO_double_compare_and_swap_acquire(volatile AO_double_t *addr,\n                                   AO_double_t old_val, AO_double_t new_val)\n{\n        return AO_compare_double_and_swap_double_acquire(addr,\n                                                         old_val.AO_val1, old_val.AO_val2,\n                                                         new_val.AO_val1, new_val.AO_val2);\n}\n#define AO_HAVE_double_compare_and_swap_acquire\n#endif\n\n#if defined(AO_HAVE_compare_double_and_swap_double_full) && \\\n    !defined(AO_HAVE_double_compare_and_swap_full)\nAO_INLINE int\nAO_double_compare_and_swap_full(volatile AO_double_t *addr,\n                                         AO_double_t old_val, AO_double_t new_val)\n{\n        return AO_compare_double_and_swap_double_full(addr,\n                                                      old_val.AO_val1, old_val.AO_val2,\n                                                      new_val.AO_val1, new_val.AO_val2);\n}\n#define AO_HAVE_double_compare_and_swap_full\n#endif\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/ia64.h",
    "content": "/*\n * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include \"./aligned_atomic_load_store.h\"\n\n#include \"./all_acquire_release_volatile.h\"\n\n#include \"./test_and_set_t_is_char.h\"\n\n#ifdef _ILP32\n  /* 32-bit HP/UX code. */\n  /* This requires pointer \"swizzling\".  Pointers need to be expanded   */\n  /* to 64 bits using the addp4 instruction before use.  This makes it  */\n  /* hard to share code, but we try anyway.                             */\n# define AO_LEN \"4\"\n  /* We assume that addr always appears in argument position 1 in asm   */\n  /* code.  If it is clobbered due to swizzling, we also need it in     */\n  /* second position.  Any later arguments are referenced symbolically, */\n  /* so that we don't have to worry about their position.  This requires*/\n  /* gcc 3.1, but you shouldn't be using anything older than that on    */\n  /* IA64 anyway.                                                       */\n  /* The AO_MASK macro is a workaround for the fact that HP/UX gcc      */\n  /* appears to otherwise store 64-bit pointers in ar.ccv, i.e. it      */\n  /* doesn't appear to clear high bits in a pointer value we pass into  */\n  /* assembly code, even if it is supposedly of type AO_t.              */\n# define AO_IN_ADDR \"1\"(addr)\n# define AO_OUT_ADDR , \"=r\"(addr)\n# define AO_SWIZZLE \"addp4 %1=0,%1;;\\n\"\n# define AO_MASK(ptr) __asm__(\"zxt4 %1=%1\": \"=r\"(ptr) : \"0\"(ptr));\n#else\n# define AO_LEN \"8\"\n# define AO_IN_ADDR \"r\"(addr)\n# define AO_OUT_ADDR\n# define AO_SWIZZLE\n# define AO_MASK(ptr)\n#endif\n\nAO_INLINE void\nAO_nop_full(void)\n{\n  __asm__ __volatile__(\"mf\" : : : \"memory\");\n}\n#define AO_HAVE_nop_full\n\nAO_INLINE AO_t\nAO_fetch_and_add1_acquire (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".acq %0=[%1],1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n#define AO_HAVE_fetch_and_add1_acquire\n\nAO_INLINE AO_t\nAO_fetch_and_add1_release (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".rel %0=[%1],1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add1_release\n\nAO_INLINE AO_t\nAO_fetch_and_sub1_acquire (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".acq %0=[%1],-1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_sub1_acquire\n\nAO_INLINE AO_t\nAO_fetch_and_sub1_release (volatile AO_t *addr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (AO_SWIZZLE\n                        \"fetchadd\" AO_LEN \".rel %0=[%1],-1\":\n                        \"=r\" (result) AO_OUT_ADDR: AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_sub1_release\n\n#ifndef _ILP32\n\nAO_INLINE unsigned int\nAO_int_fetch_and_add1_acquire (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.acq %0=[%1],1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n#define AO_HAVE_int_fetch_and_add1_acquire\n\nAO_INLINE unsigned int\nAO_int_fetch_and_add1_release (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.rel %0=[%1],1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_add1_release\n\nAO_INLINE unsigned int\nAO_int_fetch_and_sub1_acquire (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.acq %0=[%1],-1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_sub1_acquire\n\nAO_INLINE unsigned int\nAO_int_fetch_and_sub1_release (volatile unsigned int *addr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"fetchadd4.rel %0=[%1],-1\":\n                        \"=r\" (result): AO_IN_ADDR :\"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_sub1_release\n\n#endif /* !_ILP32 */\n\nAO_INLINE int\nAO_compare_and_swap_acquire(volatile AO_t *addr,\n                             AO_t old, AO_t new_val)\n{\n  AO_t oldval;\n  AO_MASK(old);\n  __asm__ __volatile__(AO_SWIZZLE\n                       \"mov ar.ccv=%[old] ;; cmpxchg\" AO_LEN\n                       \".acq %0=[%1],%[new_val],ar.ccv\"\n                       : \"=r\"(oldval) AO_OUT_ADDR\n                       : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"(old)\n                       : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_compare_and_swap_acquire\n\nAO_INLINE int\nAO_compare_and_swap_release(volatile AO_t *addr,\n                             AO_t old, AO_t new_val)\n{\n  AO_t oldval;\n  AO_MASK(old);\n  __asm__ __volatile__(AO_SWIZZLE\n                       \"mov ar.ccv=%[old] ;; cmpxchg\" AO_LEN\n                       \".rel %0=[%1],%[new_val],ar.ccv\"\n                       : \"=r\"(oldval) AO_OUT_ADDR\n                       : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"(old)\n                       : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_compare_and_swap_release\n\nAO_INLINE int\nAO_char_compare_and_swap_acquire(volatile unsigned char *addr,\n                                 unsigned char old, unsigned char new_val)\n{\n  unsigned char oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n               \"mov ar.ccv=%[old] ;; cmpxchg1.acq %0=[%1],%[new_val],ar.ccv\"\n               : \"=r\"(oldval) AO_OUT_ADDR\n               : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n               : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_char_compare_and_swap_acquire\n\nAO_INLINE int\nAO_char_compare_and_swap_release(volatile unsigned char *addr,\n                                 unsigned char old, unsigned char new_val)\n{\n  unsigned char oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n                \"mov ar.ccv=%[old] ;; cmpxchg1.rel %0=[%1],%[new_val],ar.ccv\"\n                : \"=r\"(oldval) AO_OUT_ADDR\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n                : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_char_compare_and_swap_release\n\nAO_INLINE int\nAO_short_compare_and_swap_acquire(volatile unsigned short *addr,\n                                  unsigned short old, unsigned short new_val)\n{\n  unsigned short oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n                \"mov ar.ccv=%[old] ;; cmpxchg2.acq %0=[%1],%[new_val],ar.ccv\"\n                : \"=r\"(oldval) AO_OUT_ADDR\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n                : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_short_compare_and_swap_acquire\n\nAO_INLINE int\nAO_short_compare_and_swap_release(volatile unsigned short *addr,\n                                  unsigned short old, unsigned short new_val)\n{\n  unsigned short oldval;\n  __asm__ __volatile__(AO_SWIZZLE\n                \"mov ar.ccv=%[old] ;; cmpxchg2.rel %0=[%1],%[new_val],ar.ccv\"\n                : \"=r\"(oldval) AO_OUT_ADDR\n                : AO_IN_ADDR, [new_val]\"r\"(new_val), [old]\"r\"((AO_t)old)\n                : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_short_compare_and_swap_release\n\n#ifndef _ILP32\n\nAO_INLINE int\nAO_int_compare_and_swap_acquire(volatile unsigned int *addr,\n                                unsigned int old, unsigned int new_val)\n{\n  unsigned int oldval;\n  __asm__ __volatile__(\"mov ar.ccv=%3 ;; cmpxchg4.acq %0=[%1],%2,ar.ccv\"\n                       : \"=r\"(oldval)\n                       : AO_IN_ADDR, \"r\"(new_val), \"r\"((AO_t)old) : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_int_compare_and_swap_acquire\n\nAO_INLINE int\nAO_int_compare_and_swap_release(volatile unsigned int *addr,\n                                unsigned int old, unsigned int new_val)\n{\n  unsigned int oldval;\n  __asm__ __volatile__(\"mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%1],%2,ar.ccv\"\n                       : \"=r\"(oldval)\n                       : AO_IN_ADDR, \"r\"(new_val), \"r\"((AO_t)old) : \"memory\");\n  return (oldval == old);\n}\n\n#define AO_HAVE_int_compare_and_swap_release\n\n#endif /* !_ILP32 */\n\n/* FIXME: Add compare_and_swap_double as soon as there is widely        */\n/* available hardware that implements it.                               */\n\n/* FIXME: Add compare_double_and_swap_double for the _ILP32 case.       */\n\n#ifdef _ILP32\n# include \"./ao_t_is_int.h\"\n#endif\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/ordered_except_wr.h",
    "content": "/*\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * These are common definitions for architectures that provide processor\n * ordered memory operations except that a later read may pass an\n * earlier write.  Real x86 implementations seem to be in this category,\n * except apparently for some IDT WinChips, which we ignore.\n */\n\n#include \"read_ordered.h\"\n\nAO_INLINE void\nAO_nop_write(void)\n{\n  AO_compiler_barrier();\n  /* sfence according to Intel docs.  Pentium 3 and up. */\n  /* Unnecessary for cached accesses?                   */\n}\n\n#define AO_HAVE_NOP_WRITE\n\n#if defined(AO_HAVE_store)\n\nAO_INLINE void\nAO_store_write(volatile AO_t *addr, AO_t val)\n{\n  AO_compiler_barrier();\n  AO_store(addr, val);\n}\n# define AO_HAVE_store_write\n\n# define AO_store_release(addr, val) AO_store_write(addr, val)\n# define AO_HAVE_store_release\n\n#endif /* AO_HAVE_store */\n\n#if defined(AO_HAVE_char_store)\n\nAO_INLINE void\nAO_char_store_write(volatile unsigned char *addr, unsigned char val)\n{\n  AO_compiler_barrier();\n  AO_char_store(addr, val);\n}\n# define AO_HAVE_char_store_write\n\n# define AO_char_store_release(addr, val) AO_char_store_write(addr, val)\n# define AO_HAVE_char_store_release\n\n#endif /* AO_HAVE_char_store */\n\n#if defined(AO_HAVE_short_store)\n\nAO_INLINE void\nAO_short_store_write(volatile unsigned short *addr, unsigned short val)\n{\n  AO_compiler_barrier();\n  AO_short_store(addr, val);\n}\n# define AO_HAVE_short_store_write\n\n# define AO_short_store_release(addr, val) AO_short_store_write(addr, val)\n# define AO_HAVE_short_store_release\n\n#endif /* AO_HAVE_short_store */\n\n#if defined(AO_HAVE_int_store)\n\nAO_INLINE void\nAO_int_store_write(volatile unsigned int *addr, unsigned int val)\n{\n  AO_compiler_barrier();\n  AO_int_store(addr, val);\n}\n# define AO_HAVE_int_store_write\n\n# define AO_int_store_release(addr, val) AO_int_store_write(addr, val)\n# define AO_HAVE_int_store_release\n\n#endif /* AO_HAVE_int_store */\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/powerpc.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n */\n\n/* Memory model documented at http://www-106.ibm.com/developerworks/    */\n/* eserver/articles/archguide.html and (clearer)                        */\n/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */\n/* There appears to be no implicit ordering between any kind of         */\n/* independent memory references.                                       */\n/* Architecture enforces some ordering based on control dependence.     */\n/* I don't know if that could help.                                     */\n/* Data-dependent loads are always ordered.                             */\n/* Based on the above references, eieio is intended for use on          */\n/* uncached memory, which we don't support.  It does not order loads    */\n/* from cached memory.                                                  */\n/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to   */\n/* track some of this down and correcting my misunderstandings. -HB     */\n/* Earl Chew subsequently contributed further fixes & additions.        */\n\n#include \"./aligned_atomic_load_store.h\"\n\n#include \"./test_and_set_t_is_ao_t.h\"\n        /* There seems to be no byte equivalent of lwarx, so this       */\n        /* may really be what we want, at least in the 32-bit case.     */\n\nAO_INLINE void\nAO_nop_full(void)\n{\n  __asm__ __volatile__(\"sync\" : : : \"memory\");\n}\n\n#define AO_HAVE_nop_full\n\n/* lwsync apparently works for everything but a StoreLoad barrier.      */\nAO_INLINE void\nAO_lwsync(void)\n{\n#ifdef __NO_LWSYNC__\n  __asm__ __volatile__(\"sync\" : : : \"memory\");\n#else\n  __asm__ __volatile__(\"lwsync\" : : : \"memory\");\n#endif\n}\n\n#define AO_nop_write() AO_lwsync()\n#define AO_HAVE_nop_write\n\n#define AO_nop_read() AO_lwsync()\n#define AO_HAVE_nop_read\n\n/* We explicitly specify load_acquire, since it is important, and can   */\n/* be implemented relatively cheaply.  It could be implemented          */\n/* with an ordinary load followed by a lwsync.  But the general wisdom  */\n/* seems to be that a data dependent branch followed by an isync is     */\n/* cheaper.  And the documentation is fairly explicit that this also    */\n/* has acquire semantics.                                               */\n/* ppc64 uses ld not lwz */\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\nAO_INLINE AO_t\nAO_load_acquire(const volatile AO_t *addr)\n{\n  AO_t result;\n\n   __asm__ __volatile__ (\n    \"ld%U1%X1 %0,%1\\n\"\n    \"cmpw %0,%0\\n\"\n    \"bne- 1f\\n\"\n    \"1: isync\\n\"\n    : \"=r\" (result)\n    : \"m\"(*addr) : \"memory\", \"cr0\");\n  return result;\n}\n#else\nAO_INLINE AO_t\nAO_load_acquire(const volatile AO_t *addr)\n{\n  AO_t result;\n\n  /* FIXME: We should get gcc to allocate one of the condition  */\n  /* registers.  I always got \"impossible constraint\" when I    */\n  /* tried the \"y\" constraint.                                  */\n  __asm__ __volatile__ (\n    \"lwz%U1%X1 %0,%1\\n\"\n    \"cmpw %0,%0\\n\"\n    \"bne- 1f\\n\"\n    \"1: isync\\n\"\n    : \"=r\" (result)\n    : \"m\"(*addr) : \"memory\", \"cc\");\n  return result;\n}\n#endif\n#define AO_HAVE_load_acquire\n\n/* We explicitly specify store_release, since it relies         */\n/* on the fact that lwsync is also a LoadStore barrier.         */\nAO_INLINE void\nAO_store_release(volatile AO_t *addr, AO_t value)\n{\n  AO_lwsync();\n  *addr = value;\n}\n\n#define AO_HAVE_load_acquire\n\n/* This is similar to the code in the garbage collector.  Deleting      */\n/* this and having it synthesized from compare_and_swap would probably  */\n/* only cost us a load immediate instruction.                           */\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n/* Completely untested.  And we should be using smaller objects anyway. */\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set(volatile AO_TS_t *addr) {\n  unsigned long oldval;\n  unsigned long temp = 1; /* locked value */\n\n  __asm__ __volatile__(\n               \"1:ldarx %0,0,%1\\n\"   /* load and reserve               */\n               \"cmpdi %0, 0\\n\"       /* if load is                     */\n               \"bne 2f\\n\"            /*   non-zero, return already set */\n               \"stdcx. %2,0,%1\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"2:\\n\"                /* oldval is zero if we set       */\n              : \"=&r\"(oldval)\n              : \"r\"(addr), \"r\"(temp)\n              : \"memory\", \"cr0\");\n\n  return (AO_TS_VAL_t)oldval;\n}\n\n#else\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set(volatile AO_TS_t *addr) {\n  int oldval;\n  int temp = 1; /* locked value */\n\n  __asm__ __volatile__(\n               \"1:lwarx %0,0,%1\\n\"   /* load and reserve               */\n               \"cmpwi %0, 0\\n\"       /* if load is                     */\n               \"bne 2f\\n\"            /*   non-zero, return already set */\n               \"stwcx. %2,0,%1\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"2:\\n\"                /* oldval is zero if we set       */\n              : \"=&r\"(oldval)\n              : \"r\"(addr), \"r\"(temp)\n              : \"memory\", \"cr0\");\n\n  return (AO_TS_VAL_t)oldval;\n}\n\n#endif\n\n#define AO_HAVE_test_and_set\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_acquire(volatile AO_TS_t *addr) {\n  AO_TS_VAL_t result = AO_test_and_set(addr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_test_and_set_acquire\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_release(volatile AO_TS_t *addr) {\n  AO_lwsync();\n  return AO_test_and_set(addr);\n}\n\n#define AO_HAVE_test_and_set_release\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr) {\n  AO_TS_VAL_t result;\n  AO_lwsync();\n  result = AO_test_and_set(addr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_test_and_set_full\n\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n/* FIXME: Completely untested.  */\nAO_INLINE int\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_t oldval;\n  int result = 0;\n\n  __asm__ __volatile__(\n               \"1:ldarx %0,0,%2\\n\"   /* load and reserve              */\n               \"cmpd %0, %4\\n\"      /* if load is not equal to  */\n               \"bne 2f\\n\"            /*   old, fail                     */\n               \"stdcx. %3,0,%2\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"li %1,1\\n\"           /* result = 1;                     */\n               \"2:\\n\"\n              : \"=&r\"(oldval), \"=&r\"(result)\n              : \"r\"(addr), \"r\"(new_val), \"r\"(old), \"1\"(result)\n              : \"memory\", \"cr0\");\n\n  return result;\n}\n\n#else\n\nAO_INLINE int\nAO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_t oldval;\n  int result = 0;\n\n  __asm__ __volatile__(\n               \"1:lwarx %0,0,%2\\n\"   /* load and reserve              */\n               \"cmpw %0, %4\\n\"      /* if load is not equal to  */\n               \"bne 2f\\n\"            /*   old, fail                     */\n               \"stwcx. %3,0,%2\\n\"    /* else store conditional         */\n               \"bne- 1b\\n\"           /* retry if lost reservation      */\n               \"li %1,1\\n\"           /* result = 1;                     */\n               \"2:\\n\"\n              : \"=&r\"(oldval), \"=&r\"(result)\n              : \"r\"(addr), \"r\"(new_val), \"r\"(old), \"1\"(result)\n              : \"memory\", \"cr0\");\n\n  return result;\n}\n#endif\n\n#define AO_HAVE_compare_and_swap\n\nAO_INLINE int\nAO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  int result = AO_compare_and_swap(addr, old, new_val);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_compare_and_swap_acquire\n\nAO_INLINE int\nAO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_lwsync();\n  return AO_compare_and_swap(addr, old, new_val);\n}\n\n#define AO_HAVE_compare_and_swap_release\n\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  AO_t result;\n  AO_lwsync();\n  result = AO_compare_and_swap(addr, old, new_val);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_compare_and_swap_full\n\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n/* FIXME: Completely untested.                                          */\n\nAO_INLINE AO_t\nAO_fetch_and_add(volatile AO_t *addr, AO_t incr) {\n  AO_t oldval;\n  AO_t newval;\n\n  __asm__ __volatile__(\n               \"1:ldarx %0,0,%2\\n\"   /* load and reserve                */\n               \"add %1,%0,%3\\n\"      /* increment                       */\n               \"stdcx. %1,0,%2\\n\"    /* store conditional               */\n               \"bne- 1b\\n\"           /* retry if lost reservation       */\n              : \"=&r\"(oldval), \"=&r\"(newval)\n               : \"r\"(addr), \"r\"(incr)\n              : \"memory\", \"cr0\");\n\n  return oldval;\n}\n\n#define AO_HAVE_fetch_and_add\n\n#else\n\nAO_INLINE AO_t\nAO_fetch_and_add(volatile AO_t *addr, AO_t incr) {\n  AO_t oldval;\n  AO_t newval;\n\n  __asm__ __volatile__(\n               \"1:lwarx %0,0,%2\\n\"   /* load and reserve                */\n               \"add %1,%0,%3\\n\"      /* increment                       */\n               \"stwcx. %1,0,%2\\n\"    /* store conditional               */\n               \"bne- 1b\\n\"           /* retry if lost reservation       */\n              : \"=&r\"(oldval), \"=&r\"(newval)\n               : \"r\"(addr), \"r\"(incr)\n              : \"memory\", \"cr0\");\n\n  return oldval;\n}\n\n#define AO_HAVE_fetch_and_add\n\n#endif\n\nAO_INLINE AO_t\nAO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr) {\n  AO_t result = AO_fetch_and_add(addr, incr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_acquire\n\nAO_INLINE AO_t\nAO_fetch_and_add_release(volatile AO_t *addr, AO_t incr) {\n  AO_lwsync();\n  return AO_fetch_and_add(addr, incr);\n}\n\n#define AO_HAVE_fetch_and_add_release\n\nAO_INLINE AO_t\nAO_fetch_and_add_full(volatile AO_t *addr, AO_t incr) {\n  AO_t result;\n  AO_lwsync();\n  result = AO_fetch_and_add(addr, incr);\n  AO_lwsync();\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_full\n\n#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)\n#else\n# include \"./ao_t_is_int.h\"\n#endif\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/read_ordered.h",
    "content": "/*\n * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * These are common definitions for architectures that provide processor\n * ordered memory operations except that a later read may pass an\n * earlier write.  Real x86 implementations seem to be in this category,\n * except apparently for some IDT WinChips, which we ignore.\n */\n\nAO_INLINE void\nAO_nop_read(void)\n{\n  AO_compiler_barrier();\n}\n\n#define AO_HAVE_NOP_READ\n\n#ifdef AO_HAVE_load\n\nAO_INLINE AO_t\nAO_load_read(const volatile AO_t *addr)\n{\n  AO_t result = AO_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_load_read\n\n#define AO_load_acquire(addr) AO_load_read(addr)\n#define AO_HAVE_load_acquire\n\n#endif /* AO_HAVE_load */\n\n#ifdef AO_HAVE_char_load\n\nAO_INLINE AO_t\nAO_char_load_read(const volatile unsigned char *addr)\n{\n  AO_t result = AO_char_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_char_load_read\n\n#define AO_char_load_acquire(addr) AO_char_load_read(addr)\n#define AO_HAVE_char_load_acquire\n\n#endif /* AO_HAVE_char_load */\n\n#ifdef AO_HAVE_short_load\n\nAO_INLINE AO_t\nAO_short_load_read(const volatile unsigned short *addr)\n{\n  AO_t result = AO_short_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_short_load_read\n\n#define AO_short_load_acquire(addr) AO_short_load_read(addr)\n#define AO_HAVE_short_load_acquire\n\n#endif /* AO_HAVE_short_load */\n\n#ifdef AO_HAVE_int_load\n\nAO_INLINE AO_t\nAO_int_load_read(const volatile unsigned int *addr)\n{\n  AO_t result = AO_int_load(addr);\n  AO_compiler_barrier();\n  return result;\n}\n#define AO_HAVE_int_load_read\n\n#define AO_int_load_acquire(addr) AO_int_load_read(addr)\n#define AO_HAVE_int_load_acquire\n\n#endif /* AO_HAVE_int_load */\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/sparc.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n */\n\n/* FIXME.  Very incomplete.  No support for sparc64.    */\n/* Non-ancient SPARCs provide compare-and-swap (casa).  */\n/* We should make that available.                       */\n\n#include \"./aligned_atomic_load_store.h\"\n\n/* Real SPARC code uses TSO:                            */\n#include \"./ordered_except_wr.h\"\n\n/* Test_and_set location is just a byte.                */\n#include \"./test_and_set_t_is_char.h\"\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr) {\n   AO_TS_VAL_t oldval;\n\n   __asm__ __volatile__(\"ldstub %1,%0\"\n                        : \"=r\"(oldval), \"=m\"(*addr)\n                        : \"m\"(*addr) : \"memory\");\n   return oldval;\n}\n\n#define AO_HAVE_test_and_set_full\n\n#ifndef AO_NO_SPARC_V9\n/* Returns nonzero if the comparison succeeded. */\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {\n  char ret;\n  __asm__ __volatile__ (\"membar #StoreLoad | #LoadLoad\\n\\t\"\n#                       if defined(__arch64__)\n                          \"casx [%2],%0,%1\\n\\t\"\n#                       else\n                          \"cas [%2],%0,%1\\n\\t\" /* 32-bit version */\n#                       endif\n                        \"membar #StoreLoad | #StoreStore\\n\\t\"\n                        \"cmp %0,%1\\n\\t\"\n                        \"be,a 0f\\n\\t\"\n                        \"mov 1,%0\\n\\t\"/* one insn after branch always executed */\n                        \"clr %0\\n\\t\"\n                        \"0:\\n\\t\"\n                        : \"=r\" (ret), \"+r\" (new_val)\n                        : \"r\" (addr), \"0\" (old)\n                        : \"memory\", \"cc\");\n  return (int)ret;\n}\n\n#define AO_HAVE_compare_and_swap_full\n#endif /* AO_NO_SPARC_V9 */\n\n/* FIXME: This needs to be extended for SPARC v8 and v9.        */\n/* SPARC V8 also has swap.  V9 has CAS.                         */\n/* There are barriers like membar #LoadStore.                   */\n/* CASA (32-bit) and CASXA(64-bit) instructions were            */\n/* added in V9.                                                 */\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/standard_ao_double_t.h",
    "content": "/* NEC LE-IT: For 64Bit OS we extend the double type to hold two int64's\n*\n*  x86-64: __m128 serves as placeholder which also requires the compiler\n*          to align     it on 16 byte boundary (as required by cmpxchg16.\n* Similar things could be done for PowerPC 64bit using a VMX data type...       */\n\n#if (defined(__x86_64__) && defined(__GNUC__)) || defined(_WIN64)\n# include <xmmintrin.h>\n  typedef __m128 double_ptr_storage;\n#elif defined(_WIN32) && !defined(__GNUC__)\n  typedef unsigned __int64 double_ptr_storage;\n#else\n  typedef unsigned long long double_ptr_storage;\n#endif\n\n# define AO_HAVE_DOUBLE_PTR_STORAGE\n\ntypedef union {\n    double_ptr_storage AO_whole;\n    struct {AO_t AO_v1; AO_t AO_v2;} AO_parts;\n} AO_double_t;\n\n#define AO_HAVE_double_t\n#define AO_val1 AO_parts.AO_v1\n#define AO_val2 AO_parts.AO_v2\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/test_and_set_t_is_ao_t.h",
    "content": "/*\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * These are common definitions for architectures on which test_and_set\n * operates on pointer-sized quantities, the \"clear\" value contains\n * all zeroes, and the \"set\" value contains only one lowest bit set.\n * This can be used if test_and_set is synthesized from compare_and_swap.\n */\ntypedef enum {AO_TS_clear = 0, AO_TS_set = 1} AO_TS_val;\n#define AO_TS_VAL_t AO_TS_val\n#define AO_TS_CLEAR AO_TS_clear\n#define AO_TS_SET AO_TS_set\n\n#define AO_TS_t AO_t\n\n#define AO_AO_TS_T 1\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/test_and_set_t_is_char.h",
    "content": "/*\n * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE. \n */ \n\n/*\n * These are common definitions for architectures on which test_and_set\n * operates on byte sized quantities, the \"clear\" value contains\n * all zeroes, and the \"set\" value contains all ones.\n */\n\n#define AO_TS_t unsigned char\ntypedef enum {AO_BYTE_TS_clear = 0, AO_BYTE_TS_set = 0xff} AO_BYTE_TS_val;\n#define AO_TS_VAL_t AO_BYTE_TS_val\n#define AO_TS_CLEAR AO_BYTE_TS_clear\n#define AO_TS_SET AO_BYTE_TS_set\n\n#define AO_CHAR_TS_T 1\n\n\n\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/x86.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n * Some of the machine specific code was borrowed from our GC distribution.\n */\n\n/* The following really assume we have a 486 or better.  Unfortunately  */\n/* gcc doesn't define a suitable feature test macro based on command    */\n/* line options.                                                        */\n/* We should perhaps test dynamically.                                  */\n\n#include \"./aligned_atomic_load_store.h\"\n\n/* Real X86 implementations, except for some old WinChips, appear       */\n/* to enforce ordering between memory operations, EXCEPT that a later   */\n/* read can pass earlier writes, presumably due to the visible          */\n/* presence of store buffers.                                           */\n/* We ignore both the WinChips, and the fact that the official specs    */\n/* seem to be much weaker (and arguably too weak to be usable).         */\n\n#include \"./ordered_except_wr.h\"\n\n#include \"./test_and_set_t_is_char.h\"\n\n#include \"./standard_ao_double_t.h\"\n\n#if defined(AO_USE_PENTIUM4_INSTRS)\nAO_INLINE void\nAO_nop_full(void)\n{\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\n}\n\n#define AO_HAVE_nop_full\n\n#else\n\n/* We could use the cpuid instruction.  But that seems to be slower     */\n/* than the default implementation based on test_and_set_full.  Thus    */\n/* we omit that bit of misinformation here.                             */\n\n#endif\n\n/* As far as we can tell, the lfence and sfence instructions are not    */\n/* currently needed or useful for cached memory accesses.               */\n\n/* Really only works for 486 and later */\nAO_INLINE AO_t\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_full\n\nAO_INLINE unsigned char\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\n{\n  unsigned char result;\n\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_char_fetch_and_add_full\n\nAO_INLINE unsigned short\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\n{\n  unsigned short result;\n\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_short_fetch_and_add_full\n\n/* Really only works for 486 and later */\nAO_INLINE void\nAO_or_full (volatile AO_t *p, AO_t incr)\n{\n  __asm__ __volatile__ (\"lock; orl %1, %0\" :\n                        \"=m\" (*p) : \"r\" (incr), \"m\" (*p) : \"memory\");\n}\n\n#define AO_HAVE_or_full\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr)\n{\n  unsigned char oldval;\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\n  __asm__ __volatile__(\"xchgb %0, %1\"\n                : \"=q\"(oldval), \"=m\"(*addr)\n                : \"0\"((unsigned char)0xff), \"m\"(*addr) : \"memory\");\n  return (AO_TS_VAL_t)oldval;\n}\n\n#define AO_HAVE_test_and_set_full\n\n/* Returns nonzero if the comparison succeeded. */\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\n{\n# ifdef AO_USE_SYNC_CAS_BUILTIN\n    return (int)__sync_bool_compare_and_swap(addr, old, new_val);\n# else\n    char result;\n    __asm__ __volatile__(\"lock; cmpxchgl %3, %0; setz %1\"\n                         : \"=m\" (*addr), \"=a\" (result)\n                         : \"m\" (*addr), \"r\" (new_val), \"a\" (old) : \"memory\");\n    return (int)result;\n# endif\n}\n\n#define AO_HAVE_compare_and_swap_full\n\n/* Returns nonzero if the comparison succeeded. */\n/* Really requires at least a Pentium.          */\nAO_INLINE int\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\n                                       AO_t old_val1, AO_t old_val2,\n                                       AO_t new_val1, AO_t new_val2)\n{\n  char result;\n#if __PIC__\n  /* If PIC is turned on, we can't use %ebx as it is reserved for the\n     GOT pointer.  We can save and restore %ebx because GCC won't be\n     using it for anything else (such as any of the m operands) */\n  __asm__ __volatile__(\"pushl %%ebx;\"   /* save ebx used for PIC GOT ptr */\n                       \"movl %6,%%ebx;\" /* move new_val2 to %ebx */\n                       \"lock; cmpxchg8b %0; setz %1;\"\n                       \"pop %%ebx;\"     /* restore %ebx */\n                       : \"=m\"(*addr), \"=a\"(result)\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\n                         \"c\" (new_val2), \"m\" (new_val1) : \"memory\");\n#else\n  /* We can't just do the same thing in non-PIC mode, because GCC\n   * might be using %ebx as the memory operand.  We could have ifdef'd\n   * in a clobber, but there's no point doing the push/pop if we don't\n   * have to. */\n  __asm__ __volatile__(\"lock; cmpxchg8b %0; setz %1;\"\n                       : \"=m\"(*addr), \"=a\"(result)\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\n#endif\n  return (int) result;\n}\n\n#define AO_HAVE_compare_double_and_swap_double_full\n\n#include \"./ao_t_is_int.h\"\n"
  },
  {
    "path": "stms/tinystm/src/atomic_ops/x86_64.h",
    "content": "/*\n * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.\n * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.\n * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.\n *\n *\n * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\n * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n *\n * Permission is hereby granted to use or copy this program\n * for any purpose,  provided the above notices are retained on all copies.\n * Permission to modify the code and to distribute modified code is granted,\n * provided the above notices are retained, and a notice that the code was\n * modified is included with the above copyright notice.\n *\n * Some of the machine specific code was borrowed from our GC distribution.\n */\n\n#include \"./aligned_atomic_load_store.h\"\n\n/* Real X86 implementations appear                                      */\n/* to enforce ordering between memory operations, EXCEPT that a later   */\n/* read can pass earlier writes, presumably due to the visible          */\n/* presence of store buffers.                                           */\n/* We ignore the fact that the official specs                           */\n/* seem to be much weaker (and arguably too weak to be usable).         */\n\n#include \"./ordered_except_wr.h\"\n\n#include \"./test_and_set_t_is_char.h\"\n\n#include \"./standard_ao_double_t.h\"\n\nAO_INLINE void\nAO_nop_full(void)\n{\n  /* Note: \"mfence\" (SSE2) is supported on all x86_64/amd64 chips.      */\n  __asm__ __volatile__(\"mfence\" : : : \"memory\");\n}\n\n#define AO_HAVE_nop_full\n\n/* As far as we can tell, the lfence and sfence instructions are not    */\n/* currently needed or useful for cached memory accesses.               */\n\nAO_INLINE AO_t\nAO_fetch_and_add_full (volatile AO_t *p, AO_t incr)\n{\n  AO_t result;\n\n  __asm__ __volatile__ (\"lock; xaddq %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_fetch_and_add_full\n\nAO_INLINE unsigned char\nAO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)\n{\n  unsigned char result;\n\n  __asm__ __volatile__ (\"lock; xaddb %0, %1\" :\n                        \"=q\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_char_fetch_and_add_full\n\nAO_INLINE unsigned short\nAO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)\n{\n  unsigned short result;\n\n  __asm__ __volatile__ (\"lock; xaddw %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_short_fetch_and_add_full\n\nAO_INLINE unsigned int\nAO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)\n{\n  unsigned int result;\n\n  __asm__ __volatile__ (\"lock; xaddl %0, %1\" :\n                        \"=r\" (result), \"=m\" (*p) : \"0\" (incr), \"m\" (*p)\n                        : \"memory\");\n  return result;\n}\n\n#define AO_HAVE_int_fetch_and_add_full\n\nAO_INLINE void\nAO_or_full (volatile AO_t *p, AO_t incr)\n{\n  __asm__ __volatile__ (\"lock; orq %1, %0\" :\n                        \"=m\" (*p) : \"r\" (incr), \"m\" (*p) : \"memory\");\n}\n\n#define AO_HAVE_or_full\n\nAO_INLINE AO_TS_VAL_t\nAO_test_and_set_full(volatile AO_TS_t *addr)\n{\n  unsigned char oldval;\n  /* Note: the \"xchg\" instruction does not need a \"lock\" prefix */\n  __asm__ __volatile__(\"xchgb %0, %1\"\n                : \"=q\"(oldval), \"=m\"(*addr)\n                : \"0\"((unsigned char)0xff), \"m\"(*addr) : \"memory\");\n  return (AO_TS_VAL_t)oldval;\n}\n\n#define AO_HAVE_test_and_set_full\n\n/* Returns nonzero if the comparison succeeded. */\nAO_INLINE int\nAO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)\n{\n# ifdef AO_USE_SYNC_CAS_BUILTIN\n    return (int)__sync_bool_compare_and_swap(addr, old, new_val);\n# else\n    char result;\n    __asm__ __volatile__(\"lock; cmpxchgq %3, %0; setz %1\"\n                         : \"=m\" (*addr), \"=a\" (result)\n                         : \"m\" (*addr), \"r\" (new_val), \"a\" (old) : \"memory\");\n    return (int) result;\n# endif\n}\n\n#define AO_HAVE_compare_and_swap_full\n\n#ifdef AO_CMPXCHG16B_AVAILABLE\n/* NEC LE-IT: older AMD Opterons are missing this instruction.\n * On these machines SIGILL will be thrown.\n * Define AO_WEAK_DOUBLE_CAS_EMULATION to have an emulated\n * (lock based) version available */\n/* HB: Changed this to not define either by default.  There are\n * enough machines and tool chains around on which cmpxchg16b\n * doesn't work.  And the emulation is unsafe by our usual rules.\n * Hoewever both are clearly useful in certain cases.\n */\nAO_INLINE int\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\n                                       AO_t old_val1, AO_t old_val2,\n                                       AO_t new_val1, AO_t new_val2)\n{\n  char result;\n  __asm__ __volatile__(\"lock; cmpxchg16b %0; setz %1\"\n                       : \"=m\"(*addr), \"=a\"(result)\n                       : \"m\"(*addr), \"d\" (old_val2), \"a\" (old_val1),\n                         \"c\" (new_val2), \"b\" (new_val1) : \"memory\");\n  return (int) result;\n}\n#define AO_HAVE_compare_double_and_swap_double_full\n#else\n/* this one provides spinlock based emulation of CAS implemented in     */\n/* atomic_ops.c.  We probably do not want to do this here, since it is  */\n/* not atomic with respect to other kinds of updates of *addr.  On the  */\n/* other hand, this may be a useful facility on occasion.               */\n#ifdef AO_WEAK_DOUBLE_CAS_EMULATION\nint AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,\n                                                AO_t old_val1, AO_t old_val2,\n                                                AO_t new_val1, AO_t new_val2);\n\nAO_INLINE int\nAO_compare_double_and_swap_double_full(volatile AO_double_t *addr,\n                                       AO_t old_val1, AO_t old_val2,\n                                       AO_t new_val1, AO_t new_val2)\n{\n        return AO_compare_double_and_swap_double_emulation(addr,\n                                                           old_val1, old_val2,\n                                                           new_val1, new_val2);\n}\n#define AO_HAVE_compare_double_and_swap_double_full\n#endif /* AO_WEAK_DOUBLE_CAS_EMULATION */\n#endif /* AO_CMPXCHG16B_AVAILABLE */\n"
  },
  {
    "path": "stms/tinystm/src/gc.c",
    "content": "/*\n * File:\n *   gc.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Epoch-based garbage collector.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdint.h>\n\n#include <pthread.h>\n\n#include \"tls.h\"\n#include \"gc.h\"\n\n#include \"atomic.h\"\n#include \"stm.h\"\n\n/* TODO: could be made much more efficient by allocating large chunks. */\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n\n#define MAX_GC_THREADS                  1024\n#define EPOCH_MAX                       (~(gc_word_t)0)\n\n#ifndef NO_PERIODIC_CLEANUP\n# ifndef CLEANUP_FREQUENCY\n#  define CLEANUP_FREQUENCY             1\n# endif /* ! CLEANUP_FREQUENCY */\n#endif /* ! NO_PERIODIC_CLEANUP */\n\n#ifdef DEBUG\n/* Note: stdio is thread-safe */\n# define IO_FLUSH                       fflush(NULL)\n# define PRINT_DEBUG(...)               printf(__VA_ARGS__); fflush(NULL)\n#else /* ! DEBUG */\n# define IO_FLUSH\n# define PRINT_DEBUG(...)\n#endif /* ! DEBUG */\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\nenum {                                  /* Descriptor status */\n  GC_NULL = 0,\n  GC_BUSY = 1,\n  GC_FREE_EMPTY = 2,\n  GC_FREE_FULL = 3\n};\n\ntypedef struct gc_block {               /* Block of allocated memory */\n  void *addr;                           /* Address of memory */\n  struct gc_block *next;                /* Next block */\n} gc_block_t;\n\ntypedef struct gc_region {              /* A list of allocated memory blocks */\n  struct gc_block *blocks;              /* Memory blocks */\n  gc_word_t ts;                         /* Deallocation timestamp */\n  struct gc_region *next;               /* Next region */\n} gc_region_t;\n\ntypedef struct gc_thread {              /* Descriptor of an active thread */\n  union {                               /* For padding... */\n    struct {\n      gc_word_t used;                   /* Is this entry used? */\n      gc_word_t ts;                     /* Start timestamp */\n      gc_region_t *head;                /* First memory region(s) assigned to thread */\n      gc_region_t *tail;                /* Last memory region(s) assigned to thread */\n#ifndef NO_PERIODIC_CLEANUP\n      unsigned int frees;               /* How many blocks have been freed? */\n#endif /* ! NO_PERIODIC_CLEANUP */\n    };\n    char padding[CACHELINE_SIZE];       /* Padding (should be at least a cache line) */\n  };\n} gc_thread_t;\n\nstatic struct {                         /* Descriptors of active threads */\n  volatile gc_thread_t *slots;          /* Array of thread slots */\n  volatile gc_word_t nb_active;         /* Number of used thread slots */\n} gc_threads;\n\nstatic gc_word_t (*gc_current_epoch)(void); /* Read the value of the current epoch */\n\n/* ################################################################### *\n * STATIC\n * ################################################################### */\n\n/*\n * Returns the index of the CURRENT thread.\n */\nstatic inline int gc_get_idx(void)\n{\n  return tls_get_gc();\n}\n\n/*\n * Compute a lower bound on the minimum start time of all active transactions.\n */\nstatic inline gc_word_t gc_compute_min(gc_word_t now)\n{\n  int i;\n  gc_word_t min, ts;\n  stm_word_t used;\n\n  PRINT_DEBUG(\"==> gc_compute_min(%d)\\n\", gc_get_idx());\n\n  min = now;\n  for (i = 0; i < MAX_GC_THREADS; ) {\n    used = (gc_word_t)ATOMIC_LOAD(&gc_threads.slots[i].used);\n    if (used == GC_BUSY) {\n      /* Used entry */\n      ts = (gc_word_t)ATOMIC_LOAD(&gc_threads.slots[i].ts);\n      if (ts == EPOCH_MAX) {\n        /* Wait until thread has set a safe lower bound */\n        continue;\n      }\n      if (ts < min)\n        min = ts;\n    } else if (used == GC_NULL) {\n      /* No more threads */\n      break;\n    }\n    /* Move to next entry only if entry is not used or it has a safe lower bound */\n    i++;\n  }\n\n  PRINT_DEBUG(\"==> gc_compute_min(%d,m=%lu)\\n\", gc_get_idx(), (unsigned long)min);\n\n  return min;\n}\n\n/*\n * Free block list.\n */\nstatic inline void gc_clean_blocks(gc_block_t *mb)\n{\n  gc_block_t *next_mb;\n\n  while (mb != NULL) {\n    PRINT_DEBUG(\"==> free(%d,a=%p)\\n\", gc_get_idx(), mb->addr);\n    xfree(mb->addr);\n    next_mb = mb->next;\n    xfree(mb);\n    mb = next_mb;\n  }\n}\n\n/*\n * Free region list.\n */\nstatic inline void gc_clean_regions(gc_region_t *mr)\n{\n  gc_region_t *next_mr;\n\n  while (mr != NULL) {\n    gc_clean_blocks(mr->blocks);\n    next_mr = mr->next;\n    xfree(mr);\n    mr = next_mr;\n  }\n}\n\n/*\n * Garbage-collect old data associated with a thread.\n */\nvoid gc_cleanup_thread(int idx, gc_word_t min)\n{\n  gc_region_t *mr;\n\n  PRINT_DEBUG(\"==> gc_cleanup_thread(%d,m=%lu)\\n\", idx, (unsigned long)min);\n\n  if (gc_threads.slots[idx].head == NULL) {\n    /* Nothing to clean up */\n    return;\n  }\n\n  while (min > gc_threads.slots[idx].head->ts) {\n    gc_clean_blocks(gc_threads.slots[idx].head->blocks);\n    mr = gc_threads.slots[idx].head->next;\n    xfree(gc_threads.slots[idx].head);\n    gc_threads.slots[idx].head = mr;\n    if(mr == NULL) {\n      /* All memory regions deleted */\n      gc_threads.slots[idx].tail = NULL;\n      break;\n    }\n  }\n}\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/*\n * Initialize GC library (to be called from main thread).\n */\nvoid gc_init(gc_word_t (*epoch)(void))\n{\n  int i;\n\n  PRINT_DEBUG(\"==> gc_init()\\n\");\n\n  gc_current_epoch = epoch;\n  gc_threads.slots = (gc_thread_t *)xmalloc(MAX_GC_THREADS * sizeof(gc_thread_t));\n  for (i = 0; i < MAX_GC_THREADS; i++) {\n    gc_threads.slots[i].used = GC_NULL;\n    gc_threads.slots[i].ts = EPOCH_MAX;\n    gc_threads.slots[i].head = gc_threads.slots[i].tail = NULL;\n#ifndef NO_PERIODIC_CLEANUP\n    gc_threads.slots[i].frees = 0;\n#endif /* ! NO_PERIODIC_CLEANUP */\n  }\n  gc_threads.nb_active = 0;\n}\n\n/*\n * Clean up GC library (to be called from main thread).\n */\nvoid gc_exit(void)\n{\n  int i;\n\n  PRINT_DEBUG(\"==> gc_exit()\\n\");\n\n  /* Make sure that all threads have been stopped */\n  if (ATOMIC_LOAD(&gc_threads.nb_active) != 0) {\n    fprintf(stderr, \"Error: some threads have not been cleaned up\\n\");\n    exit(1);\n  }\n  /* Clean up memory */\n  for (i = 0; i < MAX_GC_THREADS; i++)\n    gc_clean_regions(gc_threads.slots[i].head);\n\n  xfree((void *)gc_threads.slots);\n}\n\n/*\n * Initialize thread-specific GC resources (to be called once by each thread).\n */\nvoid gc_init_thread(void)\n{\n  int i, idx;\n  gc_word_t used;\n\n  PRINT_DEBUG(\"==> gc_init_thread()\\n\");\n\n  if (ATOMIC_FETCH_INC_FULL(&gc_threads.nb_active) >= MAX_GC_THREADS) {\n    fprintf(stderr, \"Error: too many concurrent threads created\\n\");\n    exit(1);\n  }\n  /* Find entry in threads array */\n  i = 0;\n  /* TODO: not wait-free */\n  while (1) {\n    used = (gc_word_t)ATOMIC_LOAD(&gc_threads.slots[i].used);\n    if (used != GC_BUSY) {\n      if (ATOMIC_CAS_FULL(&gc_threads.slots[i].used, used, GC_BUSY) != 0) {\n        idx = i;\n        /* Set safe lower bound */\n        ATOMIC_STORE(&gc_threads.slots[idx].ts, gc_current_epoch());\n        break;\n      }\n      /* CAS failed: another thread must have acquired slot */\n      assert (gc_threads.slots[i].used != GC_NULL);\n    }\n    if (++i >= MAX_GC_THREADS)\n      i = 0;\n  }\n  tls_set_gc(idx);\n\n  PRINT_DEBUG(\"==> gc_init_thread(i=%d)\\n\", idx);\n}\n\n/*\n * Clean up thread-specific GC resources (to be called once by each thread).\n */\nvoid gc_exit_thread(void)\n{\n  int idx = gc_get_idx();\n  /* NOTA: if gc_exit_thread is not called when it finishes, others threads will not free chunks. */\n\n  PRINT_DEBUG(\"==> gc_exit_thread(%d)\\n\", idx);\n\n  /* No more lower bound for this thread */\n  ATOMIC_STORE(&gc_threads.slots[idx].ts, EPOCH_MAX);\n  /* Release slot */\n  ATOMIC_STORE(&gc_threads.slots[idx].used, gc_threads.slots[idx].head == NULL ? GC_FREE_EMPTY : GC_FREE_FULL);\n  ATOMIC_FETCH_DEC_FULL(&gc_threads.nb_active);\n  /* Leave memory for next thread to cleanup */\n}\n\n/*\n * Set new epoch (to be called by each thread, typically when starting\n * new transactions to indicate their start timestamp).\n */\nvoid gc_set_epoch(gc_word_t epoch)\n{\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_set_epoch(%d,%lu)\\n\", idx, (unsigned long)epoch);\n\n  if (epoch >= EPOCH_MAX) {\n    fprintf(stderr, \"Exceeded maximum epoch number: 0x%lx\\n\", (unsigned long)epoch);\n    /* Do nothing (will prevent data from being garbage collected) */\n    return;\n  }\n\n  /* Do not need a barrier as we only compute lower bounds */\n  ATOMIC_STORE(&gc_threads.slots[idx].ts, epoch);\n}\n\n/*\n * Free memory (the thread must indicate the current timestamp).\n */\nvoid gc_free(void *addr, gc_word_t epoch)\n{\n  gc_region_t *mr;\n  gc_block_t *mb;\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_free(%d,%lu)\\n\", idx, (unsigned long)epoch);\n\n  /* Function must be called with non-decreasing epoch numbers for any given thread! */\n  if (gc_threads.slots[idx].head == NULL || gc_threads.slots[idx].tail->ts < epoch) {\n    /* Allocate a new region */\n    mr = (gc_region_t *)xmalloc(sizeof(gc_region_t));\n    mr->ts = epoch;\n    mr->blocks = NULL;\n    mr->next = NULL;\n    if (gc_threads.slots[idx].head == NULL) {\n      gc_threads.slots[idx].head = gc_threads.slots[idx].tail = mr;\n    } else {\n      gc_threads.slots[idx].tail->next = mr;\n      gc_threads.slots[idx].tail = mr;\n    }\n  } else {\n    /* Add to current region */\n    assert(gc_threads.slots[idx].tail->ts == epoch);\n    mr = gc_threads.slots[idx].tail;\n  }\n\n  /* Allocate block */\n  mb = (gc_block_t *)xmalloc(sizeof(gc_block_t));\n  mb->addr = addr;\n  mb->next = mr->blocks;\n  mr->blocks = mb;\n\n#ifndef NO_PERIODIC_CLEANUP\n  gc_threads.slots[idx].frees++;\n  if (gc_threads.slots[idx].frees % CLEANUP_FREQUENCY == 0)\n    gc_cleanup();\n#endif /* ! NO_PERIODIC_CLEANUP */\n}\n\n/*\n * Garbage-collect old data associated with the current thread (should\n * be called periodically).\n */\nvoid gc_cleanup(void)\n{\n  gc_word_t min;\n  int idx = gc_get_idx();\n\n  PRINT_DEBUG(\"==> gc_cleanup(%d)\\n\", idx);\n\n  if (gc_threads.slots[idx].head == NULL) {\n    /* Nothing to clean up */\n    return;\n  }\n\n  min = gc_compute_min(gc_current_epoch());\n\n  gc_cleanup_thread(idx, min);\n}\n\n/*\n * Garbage-collect old data associated with all threads (should be\n * called periodically).\n */\nvoid gc_cleanup_all(void)\n{\n  int i;\n  gc_word_t min = EPOCH_MAX;\n\n  PRINT_DEBUG(\"==> gc_cleanup_all()\\n\");\n\n  for (i = 0; i < MAX_GC_THREADS; i++) {\n    if ((gc_word_t)ATOMIC_LOAD(&gc_threads.slots[i].used) == GC_NULL)\n      break;\n    if ((gc_word_t)ATOMIC_LOAD(&gc_threads.slots[i].used) == GC_FREE_FULL) {\n      if (ATOMIC_CAS_FULL(&gc_threads.slots[i].used, GC_FREE_FULL, GC_BUSY) != 0) {\n        if (min == EPOCH_MAX)\n          min = gc_compute_min(gc_current_epoch());\n        gc_cleanup_thread(i, min);\n        ATOMIC_STORE(&gc_threads.slots[i].used, gc_threads.slots[i].head == NULL ? GC_FREE_EMPTY : GC_FREE_FULL);\n      }\n    }\n  }\n}\n\n/*\n * Reset all epochs for all threads (must be called with all threads\n * stopped and out of transactions, e.g., upon roll-over).\n */\nvoid gc_reset(void)\n{\n  int i;\n\n  PRINT_DEBUG(\"==> gc_reset()\\n\");\n\n  for (i = 0; i < MAX_GC_THREADS; i++) {\n    if (gc_threads.slots[i].used == GC_NULL)\n      break;\n    gc_clean_regions(gc_threads.slots[i].head);\n    gc_threads.slots[i].ts = EPOCH_MAX;\n    gc_threads.slots[i].head = gc_threads.slots[i].tail = NULL;\n#ifndef NO_PERIODIC_CLEANUP\n    gc_threads.slots[i].frees = 0;\n#endif /* ! NO_PERIODIC_CLEANUP */\n  }\n}\n"
  },
  {
    "path": "stms/tinystm/src/gc.h",
    "content": "/*\n * File:\n *   gc.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Epoch-based garbage collector.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _GC_H_\n# define _GC_H_\n\n# include <stdlib.h>\n# include <stdint.h>\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\ntypedef uintptr_t gc_word_t;\n\nvoid gc_init(gc_word_t (*epoch)(void));\nvoid gc_exit(void);\n\nvoid gc_init_thread(void);\nvoid gc_exit_thread(void);\n\nvoid gc_set_epoch(gc_word_t epoch);\n\nvoid gc_free(void *addr, gc_word_t epoch);\n\nvoid gc_cleanup(void);\n\nvoid gc_cleanup_all(void);\n\nvoid gc_reset(void);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif /* _GC_H_ */\n"
  },
  {
    "path": "stms/tinystm/src/mod_ab.c",
    "content": "/*\n * File:\n *   mod_ab.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for gathering statistics about atomic blocks.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <math.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/time.h>\n\n#include <pthread.h>\n\n#include \"mod_ab.h\"\n\n#include \"atomic.h\"\n#include \"stm.h\"\n#include \"utils.h\"\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\n#define NB_ATOMIC_BLOCKS                64\n#define BUFFER_SIZE                     1024\n#define RESERVOIR_SIZE                  \"RESERVOIR_SIZE\"\n#define RESERVOIR_SIZE_DEFAULT          1000\n#define SAMPLING_PERIOD_DEFAULT         1024\n\ntypedef struct smart_counter {          /* Smart counter */\n  unsigned long samples;                /* Number of samples */\n  double mean;                          /* Mean */\n  double variance;                      /* Variance */\n  double min;                           /* Minimum */\n  double max;                           /* Maximum */\n  double *reservoir;                    /* Vitter's reservoir */\n  int sorted;                           /* Is the reservoir sorted? */\n} smart_counter_t;\n\ntypedef struct ab_stats {               /* Atomic block statistics */\n  int id;                               /* Atomic block identifier */\n  struct ab_stats *next;                /* Next atomic block */\n  smart_counter_t stats;                /* Length statistics */\n} ab_stats_t;\n\ntypedef struct samples_buffer {         /* Buffer to hold samples */\n  struct {\n    int id;                             /* Atomic block identifier */\n    unsigned long length;               /* Transaction length */\n  } buffer[BUFFER_SIZE];                /* Buffer */\n  unsigned int nb;                      /* Number of samples */\n  unsigned int total;                   /* Total number of valid samples seen by thread so far */\n  uint64_t start;                       /* Start time of the current transaction */\n  unsigned short seed[3];               /* Thread-local PNRG's seed */\n} samples_buffer_t;\n\nstatic int mod_ab_key;\nstatic int mod_ab_initialized = 0;\nstatic int sampling_period;             /* Inverse sampling frequency */\nstatic unsigned int reservoir_size;     /* Size of Vitter's reservoir */\nstatic int (*check_fn)(void);           /* Function to check sample validity */\n\nstatic unsigned int seed;               /* Global PNRG's seed */\n\nstatic pthread_mutex_t ab_mutex;        /* Mutex to update global statistics */\n\nstatic ab_stats_t *ab_list[NB_ATOMIC_BLOCKS];\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/*\n * Round double to int.\n */\nstatic int sc_round(double d)\n{\n  return (int)(d + 0.5);\n}\n\n/*\n * Compare doubles.\n */\nstatic int compare_doubles(const void *a, const void *b)\n{\n  const double *da = (const double *)a;\n  const double *db = (const double *)b;\n  return (*da < *db ? -1 : (*da > *db ? 1 : 0));\n}\n\n/*\n * Initialize smart counter.\n */\nstatic void sc_init(smart_counter_t *c)\n{\n  c->samples = 0;\n  c->mean = c->variance = c->min = c->max = 0;\n  c->sorted = 1;\n  c->reservoir = (double *)xmalloc(reservoir_size * sizeof(double));\n}\n\n/*\n * Add sample in smart counter.\n */\nstatic void sc_add_sample(smart_counter_t *c, double n, unsigned short *seed)\n{\n  double prev, prob;\n\n  /* Update mean, variance, min, max */\n  prev = c->mean;\n  if (c->samples == 0)\n    c->min = c->max = n;\n  else if (n < c->min)\n    c->min = n;\n  else if (n > c->max)\n    c->max = n;\n  c->mean = c->mean + (n - c->mean) / (double)(c->samples + 1);\n  c->variance = c->variance + (n - prev) * (n - c->mean);\n\n  /* Add sample to reservoir */\n  if (c->samples < reservoir_size) {\n    c->reservoir[c->samples] = n;\n    c->sorted = 0;\n  } else {\n    prob = reservoir_size / (double)(c->samples + 1);\n    if (erand48(seed) <= prob) {\n      /* Replace random element */\n      c->reservoir[nrand48(seed) % reservoir_size] = n;\n    }\n    c->sorted = 0;\n  }\n\n  c->samples++;\n}\n\n/*\n * Get number of samples of smart counter.\n */\nstatic unsigned long sc_samples(smart_counter_t *c)\n{\n  return c->samples;\n}\n\n/*\n * Get mean of smart counter.\n */\nstatic double sc_mean(smart_counter_t *c)\n{\n  return c->mean;\n}\n\n/*\n * Get variance of smart counter.\n */\nstatic double sc_variance(smart_counter_t *c)\n{\n  if(c->samples <= 1)\n    return 0.0;\n  return c->variance / (c->samples - 1);\n}\n\n/*\n * Get min of smart counter.\n */\nstatic double sc_min(smart_counter_t *c)\n{\n  return c->min;\n}\n\n/*\n * Get max of smart counter.\n */\nstatic double sc_max(smart_counter_t *c)\n{\n  return c->max;\n}\n\n/*\n * Get specific percentile.\n */\nstatic double sc_percentile(smart_counter_t *c, int percentile)\n{\n  int length, i;\n\n  length = c->samples < reservoir_size ? c->samples : reservoir_size;\n  i = sc_round(length * percentile / 100.0);\n\n  if (i <= 0)\n    return c->min;\n  if (i >= length)\n    return c->max;\n\n  /* Sort array (if not yet sorted) */\n  if (!c->sorted) {\n    qsort(c->reservoir, length, sizeof(double), compare_doubles);\n    c->sorted = 1;\n  }\n\n  return c->reservoir[i];\n}\n\n/*\n * Returns a time measurement (clock ticks for x86).\n */\nstatic inline uint64_t get_time(void) {\n#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)\n  uint32_t lo, hi;\n  /* Note across cores the counter is not fully synchronized.\n   * The serializing instruction is rdtscp. */\n  __asm__ __volatile__ (\"rdtsc\" : \"=a\" (lo), \"=d\" (hi));\n  /* __asm__ __volatile__(\"rdtscp\" : \"=a\"(lo), \"=d\"(hi) :: \"ecx\" ); */\n  return (((uint64_t)hi) << 32) | (((uint64_t)lo) & 0xffffffff);\n#else\n  struct timeval tv;\n  gettimeofday(&tv, NULL);\n  return (uint64_t)(tv.tv_sec * 1000000 + tv.tv_usec);\n#endif\n}\n\n/*\n * Add samples to global stats.\n */\nstatic void sc_add_samples(samples_buffer_t *samples)\n{\n  int i, id, bucket;\n  ab_stats_t *ab;\n\n  pthread_mutex_lock(&ab_mutex);\n  for (i = 0; i < samples->nb; i++) {\n    id = samples->buffer[i].id;\n    /* Find bucket */\n    bucket = abs(id) % NB_ATOMIC_BLOCKS;\n    /* Search for entry in bucket */\n    ab = ab_list[bucket];\n    while (ab != NULL && ab->id != id)\n      ab = ab->next;\n    if (ab == NULL) {\n      /* No entry yet: create one */\n      ab = (ab_stats_t *)xmalloc(sizeof(ab_stats_t));\n      ab->id = id;\n      ab->next = ab_list[bucket];\n      sc_init(&ab->stats);\n      ab_list[bucket] = ab;\n    }\n    sc_add_sample(&ab->stats, (double)samples->buffer[i].length, samples->seed);\n  }\n  samples->nb = 0;\n  pthread_mutex_unlock(&ab_mutex);\n}\n\n/*\n * Clean up module.\n */\nstatic void cleanup(void)\n{\n  int i;\n  ab_stats_t *ab, *n;\n\n  pthread_mutex_lock(&ab_mutex);\n  for (i = 0; i < NB_ATOMIC_BLOCKS; i++) {\n    ab = ab_list[i];\n    while (ab != NULL) {\n      n = ab->next;\n      xfree(ab->stats.reservoir);\n      xfree(ab);\n      ab = n;\n    }\n  }\n  pthread_mutex_unlock(&ab_mutex);\n\n  pthread_mutex_destroy(&ab_mutex);\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void mod_ab_on_thread_init(void *arg)\n{\n  samples_buffer_t *samples;\n\n  samples = (samples_buffer_t *)xmalloc(sizeof(samples_buffer_t));\n  samples->nb = 0;\n  samples->total = 0;\n  /* Initialize thread-local seed in mutual exclution */\n  pthread_mutex_lock(&ab_mutex);\n  samples->seed[0] = (unsigned short)rand_r(&seed);\n  samples->seed[1] = (unsigned short)rand_r(&seed);\n  samples->seed[2] = (unsigned short)rand_r(&seed);\n  pthread_mutex_unlock(&ab_mutex);\n  stm_set_specific(mod_ab_key, samples);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void mod_ab_on_thread_exit(void *arg)\n{\n  samples_buffer_t *samples;\n\n  samples = (samples_buffer_t *)stm_get_specific(mod_ab_key);\n  assert(samples != NULL);\n\n  sc_add_samples(samples);\n\n  xfree(samples);\n}\n\n/*\n * Called upon transaction start.\n */\nstatic void mod_ab_on_start(void *arg)\n{\n  samples_buffer_t *samples;\n\n  samples = (samples_buffer_t *)stm_get_specific(mod_ab_key);\n  assert(samples != NULL);\n\n  samples->start = get_time();\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void mod_ab_on_commit(void *arg)\n{\n  samples_buffer_t *samples;\n  stm_tx_attr_t attrs;\n  unsigned long length;\n\n  samples = (samples_buffer_t *)stm_get_specific(mod_ab_key);\n  assert(samples != NULL);\n\n  if (check_fn == NULL || check_fn()) {\n    length = get_time() - samples->start;\n    samples->total++;\n    /* Should be keep this sample? */\n    if ((samples->total % sampling_period) == 0) {\n      attrs = stm_get_attributes();\n      samples->buffer[samples->nb].id = attrs.id;\n      samples->buffer[samples->nb].length = length;\n      /* Is buffer full? */\n      if (++samples->nb == BUFFER_SIZE) {\n        /* Accumulate in global stats (and empty buffer) */\n        sc_add_samples(samples);\n      }\n    }\n  }\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void mod_ab_on_abort(void *arg)\n{\n  samples_buffer_t *samples;\n\n  samples = (samples_buffer_t *)stm_get_specific(mod_ab_key);\n  assert(samples != NULL);\n\n  samples->start = get_time();\n}\n\n/*\n * Return statistics about atomic block.\n */\nint stm_get_ab_stats(int id, stm_ab_stats_t *stats)\n{\n  int bucket, result;\n  ab_stats_t *ab;\n\n  result = 0;\n  pthread_mutex_lock(&ab_mutex);\n  /* Find bucket */\n  bucket = abs(id) % NB_ATOMIC_BLOCKS;\n  /* Search for entry in bucket */\n  ab = ab_list[bucket];\n  while (ab != NULL && ab->id != id)\n    ab = ab->next;\n  if (ab != NULL) {\n    stats->samples = sc_samples(&ab->stats);\n    stats->mean = sc_mean(&ab->stats);\n    stats->variance = sc_variance(&ab->stats);\n    stats->min = sc_min(&ab->stats);\n    stats->max = sc_max(&ab->stats);\n    stats->percentile_50 = sc_percentile(&ab->stats, 50);\n    stats->percentile_90 = sc_percentile(&ab->stats, 90);\n    stats->percentile_95 = sc_percentile(&ab->stats, 95);\n    /* At this point, the reservoir is sorted */\n    stats->reservoir = ab->stats.reservoir;\n    stats->reservoir_size = ab->stats.samples < reservoir_size ? ab->stats.samples : reservoir_size;\n    result = 1;\n  }\n  pthread_mutex_unlock(&ab_mutex);\n\n  return result;\n}\n\n/*\n * Initialize module.\n */\nvoid mod_ab_init(int freq, int (*check)(void))\n{\n  int i;\n  char *s;\n\n  if (mod_ab_initialized)\n    return;\n\n  /* Use random seed (we are in main thread) */\n  seed = (unsigned int)rand();\n\n  sampling_period = (freq <= 0 ? SAMPLING_PERIOD_DEFAULT : freq);\n  s = getenv(RESERVOIR_SIZE);\n  if (s != NULL)\n    reservoir_size = (unsigned int)strtol(s, NULL, 10);\n  else\n    reservoir_size = RESERVOIR_SIZE_DEFAULT;\n  check_fn = check;\n\n  if (!stm_register(mod_ab_on_thread_init, mod_ab_on_thread_exit, mod_ab_on_start, NULL, mod_ab_on_commit, mod_ab_on_abort, NULL)) {\n    fprintf(stderr, \"Cannot register callbacks\\n\");\n    exit(1);\n  }\n  mod_ab_key = stm_create_specific();\n  if (mod_ab_key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  if (pthread_mutex_init(&ab_mutex, NULL) != 0) {\n    fprintf(stderr, \"Error creating mutex\\n\");\n    exit(1);\n  }\n  for (i = 0; i < NB_ATOMIC_BLOCKS; i++)\n    ab_list[i] = NULL;\n  atexit(cleanup);\n  mod_ab_initialized = 1;\n}\n"
  },
  {
    "path": "stms/tinystm/src/mod_cb_mem.c",
    "content": "/*\n * File:\n *   mod_cb_mem.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for user callback and for dynamic memory management.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"mod_cb.h\"\n#include \"mod_mem.h\"\n\n/* TODO use stm_internal.h for faster accesses */\n#include \"stm.h\"\n#include \"utils.h\"\n#include \"gc.h\"\n\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n#define DEFAULT_CB_SIZE                 16\n\ntypedef struct mod_cb_entry {           /* Callback entry */\n  void (*f)(void *);                    /* Function */\n  void *arg;                            /* Argument to be passed to function */\n} mod_cb_entry_t;\n\ntypedef struct mod_cb_info {\n  unsigned short commit_size;           /* Array size for commit callbacks */\n  unsigned short commit_nb;             /* Number of commit callbacks */\n  mod_cb_entry_t *commit;               /* Commit callback entries */\n  unsigned short abort_size;            /* Array size for abort callbacks */\n  unsigned short abort_nb;              /* Number of abort callbacks */\n  mod_cb_entry_t *abort;                /* Abort callback entries */\n} mod_cb_info_t;\n\n/* TODO: to avoid false sharing, this should be in a dedicated cacheline.\n * Unfortunately this will cost one cache line for each module. Probably\n * mod_cb_mem could be included always in mainline stm since allocation is\n * common in transaction (?). */\nstatic union {\n  struct {\n    int key;\n    unsigned int use_gc;\n  };\n  char padding[CACHELINE_SIZE];\n} ALIGNED mod_cb = {{.key = -1}};\n\n/* ################################################################### *\n * CALLBACKS FUNCTIONS\n * ################################################################### */\n\nstatic INLINE void\nmod_cb_add_on_abort(mod_cb_info_t *icb, void (*f)(void *arg), void *arg)\n{\n  if (unlikely(icb->abort_nb >= icb->abort_size)) {\n    icb->abort_size *= 2;\n    icb->abort = xrealloc(icb->abort, sizeof(mod_cb_entry_t) * icb->abort_size);\n  }\n  icb->abort[icb->abort_nb].f = f;\n  icb->abort[icb->abort_nb].arg = arg;\n  icb->abort_nb++;\n}\n\nstatic INLINE void\nmod_cb_add_on_commit(mod_cb_info_t *icb, void (*f)(void *arg), void *arg)\n{\n  if (unlikely(icb->commit_nb >= icb->commit_size)) {\n    icb->commit_size *= 2;\n    icb->commit = xrealloc(icb->commit, sizeof(mod_cb_entry_t) * icb->commit_size);\n  }\n  icb->commit[icb->commit_nb].f = f;\n  icb->commit[icb->commit_nb].arg = arg;\n  icb->commit_nb++;\n}\n\n/*\n * Register abort callback for the CURRENT transaction.\n */\nint stm_on_abort(void (*on_abort)(void *arg), void *arg)\n{\n  mod_cb_info_t *icb;\n\n  assert(mod_cb.key >= 0);\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  mod_cb_add_on_abort(icb, on_abort, arg);\n\n  return 1;\n}\n\n/*\n * Register commit callback for the CURRENT transaction.\n */\nint stm_on_commit(void (*on_commit)(void *arg), void *arg)\n{\n  mod_cb_info_t *icb;\n\n  assert(mod_cb.key >= 0);\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  mod_cb_add_on_commit(icb, on_commit, arg);\n\n  return 1;\n}\n\n/* ################################################################### *\n * MEMORY ALLOCATION FUNCTIONS\n * ################################################################### */\nstatic INLINE void *\nint_stm_malloc(struct stm_tx *tx, size_t size)\n{\n  /* Memory will be freed upon abort */\n  mod_cb_info_t *icb;\n  void *addr;\n\n  assert(mod_cb.key >= 0);\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  /* Round up size */\n  if (sizeof(stm_word_t) == 4) {\n    size = (size + 3) & ~(size_t)0x03;\n  } else {\n    size = (size + 7) & ~(size_t)0x07;\n  }\n\n  addr = xmalloc(size);\n\n  mod_cb_add_on_abort(icb, free, addr);\n\n  return addr;\n}\n\n/*\n * Called by the CURRENT thread to allocate memory within a transaction.\n */\nvoid *stm_malloc(size_t size)\n{\n  struct stm_tx *tx = stm_current_tx();\n  return int_stm_malloc(tx, size);\n}\n\nvoid *stm_malloc_tx(struct stm_tx *tx, size_t size)\n{\n  return int_stm_malloc(tx, size);\n}\n\nstatic inline\nvoid *int_stm_calloc(struct stm_tx *tx, size_t nm, size_t size)\n{\n  /* Memory will be freed upon abort */\n  mod_cb_info_t *icb;\n  void *addr;\n\n  assert(mod_cb.key >= 0);\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  /* Round up size */\n  if (sizeof(stm_word_t) == 4) {\n    size = (size + 3) & ~(size_t)0x03;\n  } else {\n    size = (size + 7) & ~(size_t)0x07;\n  }\n\n  addr = xcalloc(nm, size);\n\n  mod_cb_add_on_abort(icb, free, addr);\n\n  return addr;\n}\n\n/*\n * Called by the CURRENT thread to allocate initialized memory within a transaction.\n */\nvoid *stm_calloc(size_t nm, size_t size)\n{\n  struct stm_tx *tx = stm_current_tx();\n  return int_stm_calloc(tx, nm, size);\n}\n\nvoid *stm_calloc_tx(struct stm_tx *tx, size_t nm, size_t size)\n{\n  return int_stm_calloc(tx, nm, size);\n}\n\n#ifdef EPOCH_GC\nstatic void\nepoch_free(void *addr)\n{\n  if (mod_cb.use_gc) {\n    /* TODO use tx->end could be also used */\n    stm_word_t t = stm_get_clock();\n    gc_free(addr, t);\n  } else {\n    xfree(addr);\n  }\n}\n#endif /* EPOCH_GC */\n\nstatic inline\nvoid int_stm_free2(struct stm_tx *tx, void *addr, size_t idx, size_t size)\n{\n  /* Memory disposal is delayed until commit */\n  mod_cb_info_t *icb;\n\n  assert(mod_cb.key >= 0);\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  /* TODO: if block allocated in same transaction => no need to overwrite */\n  if (size > 0) {\n    stm_word_t *a;\n    /* Overwrite to prevent inconsistent reads */\n    if (sizeof(stm_word_t) == 4) {\n      idx = (idx + 3) >> 2;\n      size = (size + 3) >> 2;\n    } else {\n      idx = (idx + 7) >> 3;\n      size = (size + 7) >> 3;\n    }\n    a = (stm_word_t *)addr + idx;\n    while (size-- > 0) {\n      /* Acquire lock and update version number */\n      stm_store2_tx(tx, a++, 0, 0);\n    }\n  }\n  /* Schedule for removal */\n#ifdef EPOCH_GC\n  mod_cb_add_on_commit(icb, epoch_free, addr);\n#else /* ! EPOCH_GC */\n  mod_cb_add_on_commit(icb, free, addr);\n#endif /* ! EPOCH_GC */\n}\n\n/*\n * Called by the CURRENT thread to free memory within a transaction.\n */\nvoid stm_free2(void *addr, size_t idx, size_t size)\n{\n  struct stm_tx *tx = stm_current_tx();\n  int_stm_free2(tx, addr, idx, size);\n}\n\nvoid stm_free2_tx(struct stm_tx *tx, void *addr, size_t idx, size_t size)\n{\n  int_stm_free2(tx, addr, idx, size);\n}\n\n/*\n * Called by the CURRENT thread to free memory within a transaction.\n */\nvoid stm_free(void *addr, size_t size)\n{\n  struct stm_tx *tx = stm_current_tx();\n  int_stm_free2(tx, addr, 0, size);\n}\n\nvoid stm_free_tx(struct stm_tx *tx, void *addr, size_t size)\n{\n  int_stm_free2(tx, addr, 0, size);\n}\n\n\n/*\n * Called upon transaction commit.\n */\nstatic void mod_cb_on_commit(void *arg)\n{\n  mod_cb_info_t *icb;\n\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  /* Call commit callback */\n  while (icb->commit_nb > 0) {\n    icb->commit_nb--;\n    icb->commit[icb->commit_nb].f(icb->commit[icb->commit_nb].arg);\n  }\n  /* Reset abort callback */\n  icb->abort_nb = 0;\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void mod_cb_on_abort(void *arg)\n{\n  mod_cb_info_t *icb;\n\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  /* Call abort callback */\n  while (icb->abort_nb > 0) {\n    icb->abort_nb--;\n    icb->abort[icb->abort_nb].f(icb->abort[icb->abort_nb].arg);\n  }\n  /* Reset commit callback */\n  icb->commit_nb = 0;\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void mod_cb_on_thread_init(void *arg)\n{\n  mod_cb_info_t *icb;\n\n  icb = (mod_cb_info_t *)xmalloc(sizeof(mod_cb_info_t));\n  icb->commit_nb = icb->abort_nb = 0;\n  icb->commit_size = icb->abort_size = DEFAULT_CB_SIZE;\n  icb->commit = xmalloc(sizeof(mod_cb_entry_t) * icb->commit_size);\n  icb->abort = xmalloc(sizeof(mod_cb_entry_t) * icb->abort_size);\n\n  stm_set_specific(mod_cb.key, icb);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void mod_cb_on_thread_exit(void *arg)\n{\n  mod_cb_info_t *icb;\n\n  icb = (mod_cb_info_t *)stm_get_specific(mod_cb.key);\n  assert(icb != NULL);\n\n  xfree(icb->abort);\n  xfree(icb->commit);\n  xfree(icb);\n}\n\nstatic INLINE void\nmod_cb_mem_init(void)\n{\n  /* Module is already initialized? */\n  if (mod_cb.key >= 0)\n    return;\n\n  if (!stm_register(mod_cb_on_thread_init, mod_cb_on_thread_exit, NULL, NULL, mod_cb_on_commit, mod_cb_on_abort, NULL)) {\n    fprintf(stderr, \"Cannot register callbacks\\n\");\n    exit(1);\n  }\n  mod_cb.key = stm_create_specific();\n  if (mod_cb.key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n}\n\n/*\n * Initialize module.\n */\nvoid mod_cb_init(void)\n{\n  mod_cb_mem_init();\n}\n\nvoid mod_mem_init(int use_gc)\n{\n  mod_cb_mem_init();\n#ifdef EPOCH_GC\n  mod_cb.use_gc = use_gc;\n#endif /* EPOCH_GC */\n}\n\n"
  },
  {
    "path": "stms/tinystm/src/mod_log.c",
    "content": "/*\n * File:\n *   mod_log.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for logging memory accesses.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"mod_log.h\"\n\n#include \"stm.h\"\n#include \"utils.h\"\n\n#ifndef LW_SET_SIZE\n# define LW_SET_SIZE                    1024\n#endif /* ! LW_SET_SIZE */\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\nenum {\n  TYPE_WORD,\n  TYPE_U8,\n  TYPE_U16,\n  TYPE_U32,\n  TYPE_U64,\n  TYPE_CHAR,\n  TYPE_UCHAR,\n  TYPE_SHORT,\n  TYPE_USHORT,\n  TYPE_INT,\n  TYPE_UINT,\n  TYPE_LONG,\n  TYPE_ULONG,\n  TYPE_FLOAT,\n  TYPE_DOUBLE,\n  TYPE_PTR,\n  TYPE_BYTES\n};\n\ntypedef struct mod_log_w_entry {        /* Write set entry */\n  int type;                             /* Data type */\n  union {                               /* Address written and old value */\n    struct { stm_word_t *a; stm_word_t v; } w;\n    struct { uint8_t *a; char v; } u8;\n    struct { uint16_t *a; char v; } u16;\n    struct { uint32_t *a; char v; } u32;\n    struct { uint64_t *a; char v; } u64;\n    struct { char *a; char v; } c;\n    struct { unsigned char *a; unsigned char v; } uc;\n    struct { short *a; short v; } s;\n    struct { unsigned short *a; unsigned short v; } us;\n    struct { int *a; int v; } i;\n    struct { unsigned int *a; unsigned int v; } ui;\n    struct { long *a; long v; } l;\n    struct { unsigned long *a; unsigned long v; } ul;\n    struct { float *a; float v; } f;\n    struct { double *a; double v; } d;\n    struct { void **a; void *v; } p;\n    struct { uint8_t *a; uint8_t *v; size_t s; } b;\n  } data;\n} mod_log_w_entry_t;\n\ntypedef struct mod_log_w_set {          /* Write set */\n  mod_log_w_entry_t *entries;           /* Array of entries */\n  int nb_entries;                       /* Number of entries */\n  int size;                             /* Size of array */\n  int allocated;                        /* Memory blocks allocated */\n} mod_log_w_set_t;\n\nstatic int mod_log_key;\nstatic int mod_log_initialized = 0;\n\n/* ################################################################### *\n * STATIC\n * ################################################################### */\n\n/*\n * Called by the CURRENT thread to obtain log entry.\n */\nstatic inline mod_log_w_entry_t *get_entry(void)\n{\n  mod_log_w_set_t *ws;\n\n  if (!mod_log_initialized) {\n    fprintf(stderr, \"Module mod_log not initialized\\n\");\n    exit(1);\n  }\n\n  /* Store in undo log */\n  ws = (mod_log_w_set_t *)stm_get_specific(mod_log_key);\n  assert(ws != NULL);\n\n  if (ws->nb_entries == ws->size) {\n    /* Extend read set */\n    ws->size = (ws->size < LW_SET_SIZE ? LW_SET_SIZE : ws->size * 2);\n    ws->entries = (mod_log_w_entry_t *)xrealloc(ws->entries, ws->size * sizeof(mod_log_w_entry_t));\n  }\n\n  return &ws->entries[ws->nb_entries++];\n}\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\nvoid stm_log(stm_word_t *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_WORD;\n  w->data.w.a = addr;\n  w->data.w.v = *addr;\n}\n\nvoid stm_log_u8(uint8_t *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_U8;\n  w->data.u8.a = addr;\n  w->data.u8.v = *addr;\n}\n\nvoid stm_log_u16(uint16_t *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_U16;\n  w->data.u16.a = addr;\n  w->data.u16.v = *addr;\n}\n\nvoid stm_log_u32(uint32_t *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_U32;\n  w->data.u32.a = addr;\n  w->data.u32.v = *addr;\n}\n\nvoid stm_log_u64(uint64_t *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_U64;\n  w->data.u64.a = addr;\n  w->data.u64.v = *addr;\n}\n\nvoid stm_log_char(char *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_CHAR;\n  w->data.c.a = addr;\n  w->data.c.v = *addr;\n}\n\nvoid stm_log_uchar(unsigned char *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_UCHAR;\n  w->data.uc.a = addr;\n  w->data.uc.v = *addr;\n}\n\nvoid stm_log_short(short *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_SHORT;\n  w->data.s.a = addr;\n  w->data.s.v = *addr;\n}\n\nvoid stm_log_ushort(unsigned short *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_USHORT;\n  w->data.us.a = addr;\n  w->data.us.v = *addr;\n}\n\nvoid stm_log_int(int *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_INT;\n  w->data.i.a = addr;\n  w->data.i.v = *addr;\n}\n\nvoid stm_log_uint(unsigned int *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_UINT;\n  w->data.ui.a = addr;\n  w->data.ui.v = *addr;\n}\n\nvoid stm_log_long(long *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_LONG;\n  w->data.l.a = addr;\n  w->data.l.v = *addr;\n}\n\nvoid stm_log_ulong(unsigned long *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_ULONG;\n  w->data.ul.a = addr;\n  w->data.ul.v = *addr;\n}\n\nvoid stm_log_float(float *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_FLOAT;\n  w->data.f.a = addr;\n  w->data.f.v = *addr;\n}\n\nvoid stm_log_double(double *addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_DOUBLE;\n  w->data.d.a = addr;\n  w->data.d.v = *addr;\n}\n\nvoid stm_log_ptr(void **addr)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_PTR;\n  w->data.p.a = addr;\n  w->data.p.v = *addr;\n}\n\nvoid stm_log_bytes(uint8_t *addr, size_t size)\n{\n  mod_log_w_entry_t *w = get_entry();\n\n  w->type = TYPE_BYTES;\n  w->data.b.a = addr;\n  w->data.b.v = (uint8_t *)xmalloc(size);\n  w->data.b.s = size;\n  memcpy(w->data.b.v, addr, size);\n\n  /* Remember we have allocated memory */\n  ((mod_log_w_set_t *)stm_get_specific(mod_log_key))->allocated++;\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void mod_log_on_thread_init(void *arg)\n{\n  mod_log_w_set_t *ws;\n\n  ws = (mod_log_w_set_t *)xmalloc(sizeof(mod_log_w_set_t));\n  ws->entries = NULL;\n  ws->nb_entries = ws->size = ws->allocated = 0;\n\n  stm_set_specific(mod_log_key, ws);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void mod_log_on_thread_exit(void *arg)\n{\n  mod_log_w_set_t *ws;\n\n  ws = (mod_log_w_set_t *)stm_get_specific(mod_log_key);\n  assert(ws != NULL);\n\n  xfree(ws->entries);\n  xfree(ws);\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void mod_log_on_commit(void *arg)\n{\n  mod_log_w_set_t *ws;\n  mod_log_w_entry_t *w;\n\n  ws = (mod_log_w_set_t *)stm_get_specific(mod_log_key);\n  assert(ws != NULL);\n\n  /* Free memory */\n  if (ws->allocated > 0) {\n    w = ws->entries;\n    do {\n      assert(w < &ws->entries[ws->nb_entries]);\n      if (w->type == TYPE_BYTES) {\n        xfree(w->data.b.v);\n        ws->allocated--;\n      }\n      w++;\n    } while (ws->allocated > 0);\n  }\n  /* Erase undo log */\n  ws->nb_entries = 0;\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void mod_log_on_abort(void *arg)\n{\n  mod_log_w_set_t *ws;\n  mod_log_w_entry_t *w;\n\n  ws = (mod_log_w_set_t *)stm_get_specific(mod_log_key);\n  assert(ws != NULL);\n\n  if (ws->nb_entries > 0) {\n    /* Apply undo log in reverse order */\n    w = &ws->entries[ws->nb_entries - 1];\n    do {\n      switch (w->type) {\n       case TYPE_WORD:\n         *w->data.w.a = w->data.w.v;\n         break;\n       case TYPE_U8:\n         *w->data.u8.a = w->data.u8.v;\n         break;\n       case TYPE_U16:\n         *w->data.u16.a = w->data.u16.v;\n         break;\n       case TYPE_U32:\n         *w->data.u32.a = w->data.u32.v;\n         break;\n       case TYPE_U64:\n         *w->data.u64.a = w->data.u64.v;\n         break;\n       case TYPE_CHAR:\n         *w->data.c.a = w->data.c.v;\n         break;\n       case TYPE_UCHAR:\n         *w->data.uc.a = w->data.uc.v;\n         break;\n       case TYPE_SHORT:\n         *w->data.s.a = w->data.s.v;\n         break;\n       case TYPE_USHORT:\n         *w->data.us.a = w->data.us.v;\n         break;\n       case TYPE_INT:\n         *w->data.i.a = w->data.i.v;\n         break;\n       case TYPE_UINT:\n         *w->data.ui.a = w->data.ui.v;\n         break;\n       case TYPE_LONG:\n         *w->data.l.a = w->data.l.v;\n         break;\n       case TYPE_ULONG:\n         *w->data.ul.a = w->data.ul.v;\n         break;\n       case TYPE_FLOAT:\n         *w->data.f.a = w->data.f.v;\n         break;\n       case TYPE_DOUBLE:\n         *w->data.d.a = w->data.d.v;\n         break;\n       case TYPE_PTR:\n         *w->data.p.a = w->data.p.v;\n         break;\n       case TYPE_BYTES:\n         memcpy(w->data.b.a, w->data.b.v, w->data.b.s);\n         xfree(w->data.b.v);\n         ws->allocated--;\n         break;\n       default:\n         fprintf(stderr, \"Unexpected entry in undo log\\n\");\n         abort();\n         exit(1);\n      }\n    } while (--w >= ws->entries);\n    /* Erase undo log */\n    ws->nb_entries = 0;\n  }\n  assert(ws->allocated == 0);\n}\n\n/*\n * Initialize module.\n */\nvoid mod_log_init(void)\n{\n  if (mod_log_initialized)\n    return;\n\n  if (!stm_register(mod_log_on_thread_init, mod_log_on_thread_exit, NULL, NULL, mod_log_on_commit, mod_log_on_abort, NULL)) {\n    fprintf(stderr, \"Cannot register callbacks\\n\");\n    exit(1);\n  }\n  mod_log_key = stm_create_specific();\n  if (mod_log_key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  mod_log_initialized = 1;\n}\n"
  },
  {
    "path": "stms/tinystm/src/mod_order.c",
    "content": "/*\n * File:\n *   mod_order.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module to force transactions to commit in order.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <pthread.h>\n#include <stm.h>\n#include \"atomic.h\"\n#include \"utils.h\"\n#include \"mod_order.h\"\n\n#define KILL_SELF                      0x00\n#define KILL_OTHER                     0x01\n\n/* XXX Maybe these two could be in the same cacheline. */\nALIGNED static stm_word_t mod_order_ts_next = 0;\nALIGNED static stm_word_t mod_order_ts_commit = 0;\nstatic int mod_order_key;\nstatic int mod_order_initialized = 0;\n\nstatic void mod_order_on_start(void *arg)\n{\n  stm_word_t ts;\n  /* Get a timestamp for commit */\n  ts = ATOMIC_FETCH_INC_FULL(&mod_order_ts_next);\n  stm_set_specific(mod_order_key, (void *)ts);\n}\n\nstatic void mod_order_on_precommit(void *arg)\n{\n  stm_word_t my_ts, current_ts;\n  my_ts = (stm_word_t)stm_get_specific(mod_order_key);\n  /* Wait its turn... */\n  do {\n    current_ts = ATOMIC_LOAD(&mod_order_ts_commit);\n    /* Check that we are not killed to keep the liveness, the transaction will\n     * abort before to commit. Note that if the kill feature is not present, the\n     * transaction must abort if it is not its turn to guarantee progress. */\n    if (stm_killed())\n      return;\n  } while (current_ts != my_ts);\n}\n\nstatic void mod_order_on_commit(void *arg)\n{\n  /* Release next transaction to commit */\n  ATOMIC_FETCH_INC_FULL(&mod_order_ts_commit);\n}\n\nstatic int mod_order_cm(struct stm_tx *tx, struct stm_tx *other_tx, int conflict)\n{\n  stm_word_t my_order = (stm_word_t)stm_get_specific_tx(tx, mod_order_key);\n  stm_word_t other_order = (stm_word_t)stm_get_specific_tx(other_tx, mod_order_key);\n\n  if (my_order < other_order)\n    return KILL_OTHER;\n\n  return KILL_SELF;\n}\n\n/*\n * Initialize module.\n */\nvoid mod_order_init(void)\n{\n  if (mod_order_initialized)\n    return;\n#if CM == CM_MODULAR\n  if (!stm_register(NULL, NULL, mod_order_on_start, mod_order_on_precommit, mod_order_on_commit, NULL, NULL)) {\n    fprintf(stderr, \"Could not set callbacks for module 'mod_order'. Exiting.\\n\");\n    goto err;\n  }\n  if (stm_set_parameter(\"cm_function\", mod_order_cm) == 0) {\n    fprintf(stderr, \"Could not set contention manager for module 'mod_order'. Exiting.\\n\");\n    goto err;\n  }\n  mod_order_key = stm_create_specific();\n  if (mod_order_key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    goto err;\n  }\n  mod_order_initialized = 1;\n  return;\n err:\n#else /* CM != CM_MODULAR */\n  fprintf(stderr, \"The 'mod_order' module requires CM_MODULAR.\\n\");\n#endif /* CM != CM_MODULAR */\n  exit(1);\n}\n"
  },
  {
    "path": "stms/tinystm/src/mod_print.c",
    "content": "/*\n * File:\n *   mod_print.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module to test callbacks.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include \"mod_print.h\"\n\n#include \"stm.h\"\n\n/*\n * Called upon thread creation.\n */\nstatic void mod_print_on_thread_init(void *arg)\n{\n  printf(\"==> on_thread_init()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void mod_print_on_thread_exit(void *arg)\n{\n  printf(\"==> on_thread_exit()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon transaction start.\n */\nstatic void mod_print_on_start(void *arg)\n{\n  printf(\"==> on_start()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called before transaction try to commit.\n */\nstatic void mod_print_on_precommit(void *arg)\n{\n  printf(\"==> on_precommit()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void mod_print_on_commit(void *arg)\n{\n  printf(\"==> on_commit()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void mod_print_on_abort(void *arg)\n{\n  printf(\"==> on_abort()\\n\");\n  fflush(NULL);\n}\n\n/*\n * Initialize module.\n */\nvoid mod_print_init(void)\n{\n  if (!stm_register(mod_print_on_thread_init, mod_print_on_thread_exit, mod_print_on_start, mod_print_on_precommit, mod_print_on_commit, mod_print_on_abort, NULL)) {\n    fprintf(stderr, \"Cannot register callbacks\\n\");\n    exit(1);\n  }\n}\n"
  },
  {
    "path": "stms/tinystm/src/mod_stats.c",
    "content": "/*\n * File:\n *   mod_stats.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Module for gathering global statistics about transactions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <limits.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"mod_stats.h\"\n\n#include \"atomic.h\"\n#include \"stm.h\"\n#include \"utils.h\"\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\ntypedef struct mod_stats_data {         /* Transaction statistics */\n  unsigned long commits;                /* Total number of commits (cumulative) */\n  unsigned long retries;                /* Number of consecutive aborts of current transaction (retries) */\n  unsigned long retries_min;            /* Minimum number of consecutive aborts */\n  unsigned long retries_max;            /* Maximum number of consecutive aborts */\n  unsigned long retries_acc;            /* Total number of aborts (cumulative) */\n  unsigned long retries_cnt;            /* Number of samples for cumulative aborts */\n} mod_stats_data_t;\n\nstatic int mod_stats_key;\nstatic int mod_stats_initialized = 0;\n\nstatic mod_stats_data_t mod_stats_global = { 0, 0, ULONG_MAX, 0, 0, 0 };\n\n/* ################################################################### *\n * FUNCTIONS\n * ################################################################### */\n\n/*\n * Return aggregate statistics about transactions.\n */\nint stm_get_global_stats(const char *name, void *val)\n{\n  if (!mod_stats_initialized) {\n    fprintf(stderr, \"Module mod_stats not initialized\\n\");\n    exit(1);\n  }\n\n  if (strcmp(\"global_nb_commits\", name) == 0) {\n    *(unsigned long *)val = mod_stats_global.commits;\n    return 1;\n  }\n  if (strcmp(\"global_nb_aborts\", name) == 0) {\n    *(unsigned long *)val = mod_stats_global.retries_acc;\n    return 1;\n  }\n  if (strcmp(\"global_max_retries\", name) == 0) {\n    *(unsigned long *)val = mod_stats_global.retries_max;\n    return 1;\n  }\n\n  return 0;\n}\n\n/*\n * Return statistics about current thread.\n */\nint stm_get_local_stats(const char *name, void *val)\n{\n  mod_stats_data_t *stats;\n\n  if (!mod_stats_initialized) {\n    fprintf(stderr, \"Module mod_stats not initialized\\n\");\n    exit(1);\n  }\n\n  stats = (mod_stats_data_t *)stm_get_specific(mod_stats_key);\n  assert(stats != NULL);\n\n  if (strcmp(\"nb_commits\", name) == 0) {\n    *(unsigned long *)val = stats->commits;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts\", name) == 0) {\n    *(unsigned long *)val = stats->retries_acc;\n    return 1;\n  }\n  if (strcmp(\"nb_retries_avg\", name) == 0) {\n    *(double *)val = (double)stats->retries_acc / stats->retries_cnt;\n    return 1;\n  }\n  if (strcmp(\"nb_retries_min\", name) == 0) {\n    *(unsigned long *)val = stats->retries_min;\n    return 1;\n  }\n  if (strcmp(\"nb_retries_max\", name) == 0) {\n    *(unsigned long *)val = stats->retries_max;\n    return 1;\n  }\n\n  return 0;\n}\n\n/*\n * Called upon thread creation.\n */\nstatic void mod_stats_on_thread_init(void *arg)\n{\n  mod_stats_data_t *stats;\n\n  stats = (mod_stats_data_t *)xmalloc(sizeof(mod_stats_data_t));\n  stats->commits = 0;\n  stats->retries = 0;\n  stats->retries_acc = 0;\n  stats->retries_cnt = 0;\n  stats->retries_min = ULONG_MAX;\n  stats->retries_max = 0;\n\n  stm_set_specific(mod_stats_key, stats);\n}\n\n/*\n * Called upon thread deletion.\n */\nstatic void mod_stats_on_thread_exit(void *arg)\n{\n  mod_stats_data_t *stats;\n  unsigned long max, min;\n\n  stats = (mod_stats_data_t *)stm_get_specific(mod_stats_key);\n  assert(stats != NULL);\n\n  ATOMIC_FETCH_ADD_FULL(&mod_stats_global.commits, stats->commits);\n  ATOMIC_FETCH_ADD_FULL(&mod_stats_global.retries_cnt, stats->retries_cnt);\n  ATOMIC_FETCH_ADD_FULL(&mod_stats_global.retries_acc, stats->retries_acc);\nretry_max:\n  max = ATOMIC_LOAD(&mod_stats_global.retries_max);\n  if (stats->retries_max > max) {\n    if (ATOMIC_CAS_FULL(&mod_stats_global.retries_max, max, stats->retries_max) == 0)\n      goto retry_max;\n  }\nretry_min:\n  min = ATOMIC_LOAD(&mod_stats_global.retries_min);\n  if (stats->retries_min < min) {\n    if (ATOMIC_CAS_FULL(&mod_stats_global.retries_min, min, stats->retries_min) == 0)\n      goto retry_min;\n  }\n\n  xfree(stats);\n}\n\n/*\n * Called upon transaction commit.\n */\nstatic void mod_stats_on_commit(void *arg)\n{\n  mod_stats_data_t *stats;\n\n  stats = (mod_stats_data_t *)stm_get_specific(mod_stats_key);\n  assert(stats != NULL);\n  stats->commits++;\n  stats->retries_acc += stats->retries;\n  stats->retries_cnt++;\n  if (stats->retries_min > stats->retries)\n    stats->retries_min = stats->retries;\n  if (stats->retries_max < stats->retries)\n    stats->retries_max = stats->retries;\n  stats->retries = 0;\n}\n\n/*\n * Called upon transaction abort.\n */\nstatic void mod_stats_on_abort(void *arg)\n{\n  mod_stats_data_t *stats;\n\n  stats = (mod_stats_data_t *)stm_get_specific(mod_stats_key);\n  assert(stats != NULL);\n\n  stats->retries++;\n}\n\n/*\n * Initialize module.\n */\nvoid mod_stats_init(void)\n{\n  if (mod_stats_initialized)\n    return;\n\n  if (!stm_register(mod_stats_on_thread_init, mod_stats_on_thread_exit, NULL, NULL, mod_stats_on_commit, mod_stats_on_abort, NULL)) {\n    fprintf(stderr, \"Cannot register callbacks\\n\");\n    exit(1);\n  }\n  mod_stats_key = stm_create_specific();\n  if (mod_stats_key < 0) {\n    fprintf(stderr, \"Cannot create specific key\\n\");\n    exit(1);\n  }\n  mod_stats_initialized = 1;\n}\n"
  },
  {
    "path": "stms/tinystm/src/stm.c",
    "content": "/*\n * File:\n *   stm.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM functions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <signal.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <pthread.h>\n#include <sched.h>\n\n#include \"stm.h\"\n#include \"stm_internal.h\"\n\n#include \"utils.h\"\n#include \"atomic.h\"\n#include \"gc.h\"\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n\n/* Indexes are defined in stm_internal.h  */\nstatic const char *design_names[] = {\n  /* 0 */ \"WRITE-BACK (ETL)\",\n  /* 1 */ \"WRITE-BACK (CTL)\",\n  /* 2 */ \"WRITE-THROUGH\",\n  /* 3 */ \"WRITE-MODULAR\"\n};\n\nstatic const char *cm_names[] = {\n  /* 0 */ \"SUICIDE\",\n  /* 1 */ \"DELAY\",\n  /* 2 */ \"BACKOFF\",\n  /* 3 */ \"MODULAR\"\n};\n\n/* Global variables */\nglobal_t _tinystm =\n    { .nb_specific = 0\n    , .initialized = 0\n#ifdef IRREVOCABLE_ENABLED\n    , .irrevocable = 0\n#endif /* IRREVOCABLE_ENABLED */\n    };\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\n\n/*\n * Transaction nesting is supported in a minimalist way (flat nesting):\n * - When a transaction is started in the context of another\n *   transaction, we simply increment a nesting counter but do not\n *   actually start a new transaction.\n * - The environment to be used for setjmp/longjmp is only returned when\n *   no transaction is active so that it is not overwritten by nested\n *   transactions. This allows for composability as the caller does not\n *   need to know whether it executes inside another transaction.\n * - The commit of a nested transaction simply decrements the nesting\n *   counter. Only the commit of the top-level transaction will actually\n *   carry through updates to shared memory.\n * - An abort of a nested transaction will rollback the top-level\n *   transaction and reset the nesting counter. The call to longjmp will\n *   restart execution before the top-level transaction.\n * Using nested transactions without setjmp/longjmp is not recommended\n * as one would need to explicitly jump back outside of the top-level\n * transaction upon abort of a nested transaction. This breaks\n * composability.\n */\n\n/*\n * Reading from the previous version of locked addresses is implemented\n * by peeking into the write set of the transaction that owns the\n * lock. Each transaction has a unique identifier, updated even upon\n * retry. A special \"commit\" bit of this identifier is set upon commit,\n * right before writing the values from the redo log to shared memory. A\n * transaction can read a locked address if the identifier of the owner\n * does not change between before and after reading the value and\n * version, and it does not have the commit bit set.\n */\n\n/* ################################################################### *\n * THREAD-LOCAL\n * ################################################################### */\n\n#if defined(TLS_POSIX) || defined(TLS_DARWIN)\n/* TODO this may lead to false sharing. */\n/* TODO this could be renamed with tinystm prefix */\npthread_key_t thread_tx;\npthread_key_t thread_gc;\n#elif defined(TLS_COMPILER)\n__thread stm_tx_t* thread_tx = NULL;\n__thread long thread_gc = 0;\n#endif /* defined(TLS_COMPILER) */\n\n/* ################################################################### *\n * STATIC\n * ################################################################### */\n\n#if CM == CM_MODULAR\n/*\n * Kill other.\n */\nstatic int\ncm_aggressive(struct stm_tx *me, struct stm_tx *other, int conflict)\n{\n  return KILL_OTHER;\n}\n\n/*\n * Kill self.\n */\nstatic int\ncm_suicide(struct stm_tx *me, struct stm_tx *other, int conflict)\n{\n  return KILL_SELF;\n}\n\n/*\n * Kill self and wait before restart.\n */\nstatic int\ncm_delay(struct stm_tx *me, struct stm_tx *other, int conflict)\n{\n  return KILL_SELF | DELAY_RESTART;\n}\n\n/*\n * Oldest transaction has priority.\n */\nstatic int\ncm_timestamp(struct stm_tx *me, struct stm_tx *other, int conflict)\n{\n  if (me->timestamp < other->timestamp)\n    return KILL_OTHER;\n  if (me->timestamp == other->timestamp && (uintptr_t)me < (uintptr_t)other)\n    return KILL_OTHER;\n  return KILL_SELF | DELAY_RESTART;\n}\n\n/*\n * Transaction with more work done has priority.\n */\nstatic int\ncm_karma(struct stm_tx *me, struct stm_tx *other, int conflict)\n{\n  unsigned int me_work, other_work;\n\n  me_work = (me->w_set.nb_entries << 1) + me->r_set.nb_entries;\n  other_work = (other->w_set.nb_entries << 1) + other->r_set.nb_entries;\n\n  if (me_work < other_work)\n    return KILL_OTHER;\n  if (me_work == other_work && (uintptr_t)me < (uintptr_t)other)\n    return KILL_OTHER;\n  return KILL_SELF;\n}\n\nstruct {\n  const char *name;\n  int (*f)(stm_tx_t *, stm_tx_t *, int);\n} cms[] = {\n  { \"aggressive\", cm_aggressive },\n  { \"suicide\", cm_suicide },\n  { \"delay\", cm_delay },\n  { \"timestamp\", cm_timestamp },\n  { \"karma\", cm_karma },\n  { NULL, NULL }\n};\n#endif /* CM == CM_MODULAR */\n\n#ifdef SIGNAL_HANDLER\n/*\n * Catch signal (to emulate non-faulting load).\n */\nstatic void\nsignal_catcher(int sig)\n{\n  sigset_t block_signal;\n  stm_tx_t *tx = tls_get_tx();\n\n  /* A fault might only occur upon a load concurrent with a free (read-after-free) */\n  PRINT_DEBUG(\"Caught signal: %d\\n\", sig);\n\n  /* TODO: TX_KILLED should be also allowed */\n  if (tx == NULL || tx->attr.no_retry || GET_STATUS(tx->status) != TX_ACTIVE) {\n    /* There is not much we can do: execution will restart at faulty load */\n    fprintf(stderr, \"Error: invalid memory accessed and no longjmp destination\\n\");\n    exit(1);\n  }\n\n  /* Unblock the signal since there is no return to signal handler */\n  sigemptyset(&block_signal);\n  sigaddset(&block_signal, sig);\n  pthread_sigmask(SIG_UNBLOCK, &block_signal, NULL);\n\n  /* Will cause a longjmp */\n  stm_rollback(tx, STM_ABORT_SIGNAL);\n}\n#endif /* SIGNAL_HANDLER */\n\n/* ################################################################### *\n * STM FUNCTIONS\n * ################################################################### */\n\n/*\n * Called once (from main) to initialize STM infrastructure.\n */\n_CALLCONV void\nstm_init(void)\n{\n#if CM == CM_MODULAR\n  char *s;\n#endif /* CM == CM_MODULAR */\n#ifdef SIGNAL_HANDLER\n  struct sigaction act;\n#endif /* SIGNAL_HANDLER */\n\n  PRINT_DEBUG(\"==> stm_init()\\n\");\n\n  if (_tinystm.initialized)\n    return;\n\n  PRINT_DEBUG(\"\\tsizeof(word)=%d\\n\", (int)sizeof(stm_word_t));\n\n  PRINT_DEBUG(\"\\tVERSION_MAX=0x%lx\\n\", (unsigned long)VERSION_MAX);\n\n  COMPILE_TIME_ASSERT(sizeof(stm_word_t) == sizeof(void *));\n  COMPILE_TIME_ASSERT(sizeof(stm_word_t) == sizeof(atomic_t));\n\n#ifdef EPOCH_GC\n  gc_init(stm_get_clock);\n#endif /* EPOCH_GC */\n\n#if CM == CM_MODULAR\n  s = getenv(VR_THRESHOLD);\n  if (s != NULL)\n    _tinystm.vr_threshold = (int)strtol(s, NULL, 10);\n  else\n    _tinystm.vr_threshold = VR_THRESHOLD_DEFAULT;\n  PRINT_DEBUG(\"\\tVR_THRESHOLD=%d\\n\", _tinystm.vr_threshold);\n#endif /* CM == CM_MODULAR */\n\n  /* Set locks and clock but should be already to 0 */\n  memset((void *)_tinystm.locks, 0, LOCK_ARRAY_SIZE * sizeof(stm_word_t));\n  CLOCK = 0;\n\n  stm_quiesce_init();\n\n  tls_init();\n\n#ifdef SIGNAL_HANDLER\n  if (getenv(NO_SIGNAL_HANDLER) == NULL) {\n    /* Catch signals for non-faulting load */\n    act.sa_handler = signal_catcher;\n    act.sa_flags = 0;\n    sigemptyset(&act.sa_mask);\n    if (sigaction(SIGBUS, &act, NULL) < 0 || sigaction(SIGSEGV, &act, NULL) < 0) {\n      perror(\"sigaction\");\n      exit(1);\n    }\n  }\n#endif /* SIGNAL_HANDLER */\n  _tinystm.initialized = 1;\n}\n\n/*\n * Called once (from main) to clean up STM infrastructure.\n */\n_CALLCONV void\nstm_exit(void)\n{\n  PRINT_DEBUG(\"==> stm_exit()\\n\");\n\n  if (!_tinystm.initialized)\n    return;\n\n  tls_exit();\n  stm_quiesce_exit();\n\n#ifdef EPOCH_GC\n  gc_exit();\n#endif /* EPOCH_GC */\n\n  _tinystm.initialized = 0;\n}\n\n/*\n * Called by the CURRENT thread to initialize thread-local STM data.\n */\n_CALLCONV stm_tx_t *\nstm_init_thread(void)\n{\n  return int_stm_init_thread();\n}\n\n/*\n * Called by the CURRENT thread to cleanup thread-local STM data.\n */\n_CALLCONV void\nstm_exit_thread(void)\n{\n  TX_GET;\n  int_stm_exit_thread(tx);\n}\n\n_CALLCONV void\nstm_exit_thread_tx(stm_tx_t *tx)\n{\n  int_stm_exit_thread(tx);\n}\n\n/*\n * Called by the CURRENT thread to start a transaction.\n */\n_CALLCONV sigjmp_buf *\nstm_start(stm_tx_attr_t attr)\n{\n  TX_GET;\n  return int_stm_start(tx, attr);\n}\n\n_CALLCONV sigjmp_buf *\nstm_start_tx(stm_tx_t *tx, stm_tx_attr_t attr)\n{\n  return int_stm_start(tx, attr);\n}\n\n/*\n * Called by the CURRENT thread to commit a transaction.\n */\n_CALLCONV int\nstm_commit(void)\n{\n  TX_GET;\n  return int_stm_commit(tx);\n}\n\n_CALLCONV int\nstm_commit_tx(stm_tx_t *tx)\n{\n  return int_stm_commit(tx);\n}\n\n/*\n * Called by the CURRENT thread to abort a transaction.\n */\n_CALLCONV void\nstm_abort(int reason)\n{\n  TX_GET;\n  stm_rollback(tx, reason | STM_ABORT_EXPLICIT);\n}\n\n_CALLCONV void\nstm_abort_tx(stm_tx_t *tx, int reason)\n{\n  stm_rollback(tx, reason | STM_ABORT_EXPLICIT);\n}\n\n/*\n * Called by the CURRENT thread to load a word-sized value.\n */\n_CALLCONV ALIGNED stm_word_t\nstm_load(volatile stm_word_t *addr)\n{\n  TX_GET;\n  return int_stm_load(tx, addr);\n}\n\n_CALLCONV stm_word_t\nstm_load_tx(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  return int_stm_load(tx, addr);\n}\n\n/*\n * Called by the CURRENT thread to store a word-sized value.\n */\n_CALLCONV ALIGNED void\nstm_store(volatile stm_word_t *addr, stm_word_t value)\n{\n  TX_GET;\n  int_stm_store(tx, addr, value);\n}\n\n_CALLCONV void\nstm_store_tx(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value)\n{\n  int_stm_store(tx, addr, value);\n}\n\n/*\n * Called by the CURRENT thread to store part of a word-sized value.\n */\n_CALLCONV ALIGNED void\nstm_store2(volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  TX_GET;\n  int_stm_store2(tx, addr, value, mask);\n}\n\n_CALLCONV void\nstm_store2_tx(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  int_stm_store2(tx, addr, value, mask);\n}\n\n/*\n * Called by the CURRENT thread to inquire about the status of a transaction.\n */\n_CALLCONV int\nstm_active(void)\n{\n  TX_GET;\n  return int_stm_active(tx);\n}\n\n_CALLCONV int\nstm_active_tx(stm_tx_t *tx)\n{\n  return int_stm_active(tx);\n}\n\n/*\n * Called by the CURRENT thread to inquire about the status of a transaction.\n */\n_CALLCONV int\nstm_aborted(void)\n{\n  TX_GET;\n  return int_stm_aborted(tx);\n}\n\n_CALLCONV int\nstm_aborted_tx(stm_tx_t *tx)\n{\n  return int_stm_aborted(tx);\n}\n\n/*\n * Called by the CURRENT thread to inquire about the status of a transaction.\n */\n_CALLCONV int\nstm_irrevocable(void)\n{\n  TX_GET;\n  return int_stm_irrevocable(tx);\n}\n\n_CALLCONV int\nstm_irrevocable_tx(stm_tx_t *tx)\n{\n  return int_stm_irrevocable(tx);\n}\n\n/*\n * Called by the CURRENT thread to inquire about the status of a transaction.\n */\n_CALLCONV int\nstm_killed(void)\n{\n  TX_GET;\n  return int_stm_killed(tx);\n}\n\n_CALLCONV int\nstm_killed_tx(stm_tx_t *tx)\n{\n  return int_stm_killed(tx);\n}\n\n/*\n * Called by the CURRENT thread to obtain an environment for setjmp/longjmp.\n */\n_CALLCONV sigjmp_buf *\nstm_get_env(void)\n{\n  TX_GET;\n  return int_stm_get_env(tx);\n}\n\n_CALLCONV sigjmp_buf *\nstm_get_env_tx(stm_tx_t *tx)\n{\n  return int_stm_get_env(tx);\n}\n\n/*\n * Get transaction attributes.\n */\n_CALLCONV stm_tx_attr_t\nstm_get_attributes(void)\n{\n  TX_GET;\n  assert (tx != NULL);\n  return tx->attr;\n}\n\n/*\n * Get transaction attributes from a specifc transaction.\n */\n_CALLCONV stm_tx_attr_t\nstm_get_attributes_tx(struct stm_tx *tx)\n{\n  assert (tx != NULL);\n  return tx->attr;\n}\n\n/*\n * Return statistics about a thread/transaction.\n */\n_CALLCONV int\nstm_get_stats(const char *name, void *val)\n{\n  TX_GET;\n  return int_stm_get_stats(tx, name, val);\n}\n\n_CALLCONV int\nstm_get_stats_tx(stm_tx_t *tx, const char *name, void *val)\n{\n  return int_stm_get_stats(tx, name, val);\n}\n\n/*\n * Return STM parameters.\n */\n_CALLCONV int\nstm_get_parameter(const char *name, void *val)\n{\n  if (strcmp(\"contention_manager\", name) == 0) {\n    *(const char **)val = cm_names[CM];\n    return 1;\n  }\n  if (strcmp(\"design\", name) == 0) {\n    *(const char **)val = design_names[DESIGN];\n    return 1;\n  }\n  if (strcmp(\"initial_rw_set_size\", name) == 0) {\n    *(int *)val = RW_SET_SIZE;\n    return 1;\n  }\n#if CM == CM_BACKOFF\n  if (strcmp(\"min_backoff\", name) == 0) {\n    *(unsigned long *)val = MIN_BACKOFF;\n    return 1;\n  }\n  if (strcmp(\"max_backoff\", name) == 0) {\n    *(unsigned long *)val = MAX_BACKOFF;\n    return 1;\n  }\n#endif /* CM == CM_BACKOFF */\n#if CM == CM_MODULAR\n  if (strcmp(\"vr_threshold\", name) == 0) {\n    *(int *)val = _tinystm.vr_threshold;\n    return 1;\n  }\n#endif /* CM == CM_MODULAR */\n#ifdef COMPILE_FLAGS\n  if (strcmp(\"compile_flags\", name) == 0) {\n    *(const char **)val = XSTR(COMPILE_FLAGS);\n    return 1;\n  }\n#endif /* COMPILE_FLAGS */\n  return 0;\n}\n\n/*\n * Set STM parameters.\n */\n_CALLCONV int\nstm_set_parameter(const char *name, void *val)\n{\n#if CM == CM_MODULAR\n  int i;\n\n  if (strcmp(\"cm_policy\", name) == 0) {\n    for (i = 0; cms[i].name != NULL; i++) {\n      if (strcasecmp(cms[i].name, (const char *)val) == 0) {\n        _tinystm.contention_manager = cms[i].f;\n        return 1;\n      }\n    }\n    return 0;\n  }\n  if (strcmp(\"cm_function\", name) == 0) {\n    _tinystm.contention_manager = (int (*)(stm_tx_t *, stm_tx_t *, int))val;\n    return 1;\n  }\n  if (strcmp(\"vr_threshold\", name) == 0) {\n    _tinystm.vr_threshold = *(int *)val;\n    return 1;\n  }\n#endif /* CM == CM_MODULAR */\n  return 0;\n}\n\n/*\n * Create transaction-specific data (return -1 on error).\n */\n_CALLCONV int\nstm_create_specific(void)\n{\n  if (_tinystm.nb_specific >= MAX_SPECIFIC) {\n    fprintf(stderr, \"Error: maximum number of specific slots reached\\n\");\n    return -1;\n  }\n  return _tinystm.nb_specific++;\n}\n\n/*\n * Store transaction-specific data.\n */\n_CALLCONV void\nstm_set_specific(int key, void *data)\n{\n  TX_GET;\n  int_stm_set_specific(tx, key, data);\n}\n\n/*\n * Store transaction-specific data to a specifc transaction.\n */\n_CALLCONV void\nstm_set_specific_tx(stm_tx_t *tx, int key, void *data)\n{\n  int_stm_set_specific(tx, key, data);\n}\n\n\n/*\n * Fetch transaction-specific data.\n */\n_CALLCONV void *\nstm_get_specific(int key)\n{\n  TX_GET;\n  return int_stm_get_specific(tx, key);\n}\n\n/*\n * Fetch transaction-specific data from a specific transaction.\n */\n_CALLCONV void *\nstm_get_specific_tx(stm_tx_t *tx, int key)\n{\n  return int_stm_get_specific(tx, key);\n}\n\n/*\n * Register callbacks for an external module (must be called before creating transactions).\n */\n_CALLCONV int\nstm_register(void (*on_thread_init)(void *arg),\n             void (*on_thread_exit)(void *arg),\n             void (*on_start)(void *arg),\n             void (*on_precommit)(void *arg),\n             void (*on_commit)(void *arg),\n             void (*on_abort)(void *arg),\n             void *arg)\n{\n  if ((on_thread_init != NULL && _tinystm.nb_init_cb >= MAX_CB) ||\n      (on_thread_exit != NULL && _tinystm.nb_exit_cb >= MAX_CB) ||\n      (on_start != NULL && _tinystm.nb_start_cb >= MAX_CB) ||\n      (on_precommit != NULL && _tinystm.nb_precommit_cb >= MAX_CB) ||\n      (on_commit != NULL && _tinystm.nb_commit_cb >= MAX_CB) ||\n      (on_abort != NULL && _tinystm.nb_abort_cb >= MAX_CB)) {\n    fprintf(stderr, \"Error: maximum number of modules reached\\n\");\n    return 0;\n  }\n  /* New callback */\n  if (on_thread_init != NULL) {\n    _tinystm.init_cb[_tinystm.nb_init_cb].f = on_thread_init;\n    _tinystm.init_cb[_tinystm.nb_init_cb++].arg = arg;\n  }\n  /* Delete callback */\n  if (on_thread_exit != NULL) {\n    _tinystm.exit_cb[_tinystm.nb_exit_cb].f = on_thread_exit;\n    _tinystm.exit_cb[_tinystm.nb_exit_cb++].arg = arg;\n  }\n  /* Start callback */\n  if (on_start != NULL) {\n    _tinystm.start_cb[_tinystm.nb_start_cb].f = on_start;\n    _tinystm.start_cb[_tinystm.nb_start_cb++].arg = arg;\n  }\n  /* Pre-commit callback */\n  if (on_precommit != NULL) {\n    _tinystm.precommit_cb[_tinystm.nb_precommit_cb].f = on_precommit;\n    _tinystm.precommit_cb[_tinystm.nb_precommit_cb++].arg = arg;\n  }\n  /* Commit callback */\n  if (on_commit != NULL) {\n    _tinystm.commit_cb[_tinystm.nb_commit_cb].f = on_commit;\n    _tinystm.commit_cb[_tinystm.nb_commit_cb++].arg = arg;\n  }\n  /* Abort callback */\n  if (on_abort != NULL) {\n    _tinystm.abort_cb[_tinystm.nb_abort_cb].f = on_abort;\n    _tinystm.abort_cb[_tinystm.nb_abort_cb++].arg = arg;\n  }\n\n  return 1;\n}\n\n/*\n * Called by the CURRENT thread to load a word-sized value in a unit transaction.\n */\n_CALLCONV stm_word_t\nstm_unit_load(volatile stm_word_t *addr, stm_word_t *timestamp)\n{\n#ifdef UNIT_TX\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, value;\n\n  PRINT_DEBUG2(\"==> stm_unit_load(a=%p)\\n\", addr);\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Read lock, value, lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked: wait until lock is free */\n#ifdef WAIT_YIELD\n    sched_yield();\n#endif /* WAIT_YIELD */\n    goto restart;\n  }\n  /* Not locked */\n  value = ATOMIC_LOAD_ACQ(addr);\n  l2 = ATOMIC_LOAD_ACQ(lock);\n  if (l != l2) {\n    l = l2;\n    goto restart_no_load;\n  }\n\n  if (timestamp != NULL)\n    *timestamp = LOCK_GET_TIMESTAMP(l);\n\n  return value;\n#else /* ! UNIT_TX */\n  fprintf(stderr, \"Unit transaction is not enabled\\n\");\n  exit(-1);\n  return 1;\n#endif /* ! UNIT_TX */\n}\n\n/*\n * Store a word-sized value in a unit transaction.\n */\nstatic INLINE int\nstm_unit_write(volatile stm_word_t *addr, stm_word_t value, stm_word_t mask, stm_word_t *timestamp)\n{\n#ifdef UNIT_TX\n  volatile stm_word_t *lock;\n  stm_word_t l;\n\n  PRINT_DEBUG2(\"==> stm_unit_write(a=%p,d=%p-%lu,m=0x%lx)\\n\",\n               addr, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Try to acquire lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked: wait until lock is free */\n#ifdef WAIT_YIELD\n    sched_yield();\n#endif /* WAIT_YIELD */\n    goto restart;\n  }\n  /* Not locked */\n  if (timestamp != NULL && LOCK_GET_TIMESTAMP(l) > *timestamp) {\n    /* Return current timestamp */\n    *timestamp = LOCK_GET_TIMESTAMP(l);\n    return 0;\n  }\n  /* TODO: would need to store thread ID to be able to kill it (for wait freedom) */\n  if (ATOMIC_CAS_FULL(lock, l, LOCK_UNIT) == 0)\n    goto restart;\n  ATOMIC_STORE(addr, value);\n  /* Update timestamp with newer value (may exceed VERSION_MAX by up to MAX_THREADS) */\n  l = FETCH_INC_CLOCK + 1;\n  if (timestamp != NULL)\n    *timestamp = l;\n  /* Make sure that lock release becomes visible */\n  ATOMIC_STORE_REL(lock, LOCK_SET_TIMESTAMP(l));\n  if (unlikely(l >= VERSION_MAX)) {\n    /* Block all transactions and reset clock (current thread is not in active transaction) */\n    stm_quiesce_barrier(NULL, rollover_clock, NULL);\n  }\n  return 1;\n#else /* ! UNIT_TX */\n  fprintf(stderr, \"Unit transaction is not enabled\\n\");\n  exit(-1);\n  return 1;\n#endif /* ! UNIT_TX */\n}\n\n/*\n * Called by the CURRENT thread to store a word-sized value in a unit transaction.\n */\n_CALLCONV int\nstm_unit_store(volatile stm_word_t *addr, stm_word_t value, stm_word_t *timestamp)\n{\n  return stm_unit_write(addr, value, ~(stm_word_t)0, timestamp);\n}\n\n/*\n * Called by the CURRENT thread to store part of a word-sized value in a unit transaction.\n */\n_CALLCONV int\nstm_unit_store2(volatile stm_word_t *addr, stm_word_t value, stm_word_t mask, stm_word_t *timestamp)\n{\n  return stm_unit_write(addr, value, mask, timestamp);\n}\n\n/*\n * Enable or disable extensions and set upper bound on snapshot.\n */\nstatic INLINE void\nint_stm_set_extension(stm_tx_t *tx, int enable, stm_word_t *timestamp)\n{\n#ifdef UNIT_TX\n  tx->attr.no_extend = !enable;\n  if (timestamp != NULL && *timestamp < tx->end)\n    tx->end = *timestamp;\n#else /* ! UNIT_TX */\n  fprintf(stderr, \"Unit transaction is not enabled\\n\");\n  exit(-1);\n#endif /* ! UNIT_TX */\n}\n\n_CALLCONV void\nstm_set_extension(int enable, stm_word_t *timestamp)\n{\n  TX_GET;\n  int_stm_set_extension(tx, enable, timestamp);\n}\n\n_CALLCONV void\nstm_set_extension_tx(stm_tx_t *tx, int enable, stm_word_t *timestamp)\n{\n  int_stm_set_extension(tx, enable, timestamp);\n}\n\n/*\n * Get curent value of global clock.\n */\n_CALLCONV stm_word_t\nstm_get_clock(void)\n{\n  return GET_CLOCK;\n}\n\n/*\n * Get current transaction descriptor.\n */\n_CALLCONV stm_tx_t *\nstm_current_tx(void)\n{\n  return tls_get_tx();\n}\n\n/* ################################################################### *\n * UNDOCUMENTED STM FUNCTIONS (USE WITH CARE!)\n * ################################################################### */\n\n#ifdef CONFLICT_TRACKING\n/*\n * Get thread identifier of other transaction.\n */\n_CALLCONV int\nstm_get_thread_id(stm_tx_t *tx, pthread_t *id)\n{\n  *id = tx->thread_id;\n  return 1;\n}\n\n/*\n * Set global conflict callback.\n */\n_CALLCONV int\nstm_set_conflict_cb(void (*on_conflict)(stm_tx_t *tx1, stm_tx_t *tx2))\n{\n  _tinystm.conflict_cb = on_conflict;\n  return 1;\n}\n#endif /* CONFLICT_TRACKING */\n\n/*\n * Set the CURRENT transaction as irrevocable.\n */\nstatic INLINE int\nint_stm_set_irrevocable(stm_tx_t *tx, int serial)\n{\n#ifdef IRREVOCABLE_ENABLED\n# if CM == CM_MODULAR\n  stm_word_t t;\n# endif /* CM == CM_MODULAR */\n\n  if (!IS_ACTIVE(tx->status) && serial != -1) {\n    /* Request irrevocability outside of a transaction or in abort handler (for next execution) */\n    tx->irrevocable = 1 + (serial ? 0x08 : 0);\n    return 0;\n  }\n\n  /* Are we already in irrevocable mode? */\n  if ((tx->irrevocable & 0x07) == 3) {\n    return 1;\n  }\n\n  if (tx->irrevocable == 0) {\n    /* Acquire irrevocability for the first time */\n    tx->irrevocable = 1 + (serial ? 0x08 : 0);\n    /* Try acquiring global lock */\n    if (_tinystm.irrevocable == 1 || ATOMIC_CAS_FULL(&_tinystm.irrevocable, 0, 1) == 0) {\n      /* Transaction will acquire irrevocability after rollback */\n      stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n      return 0;\n    }\n    /* Success: remember we have the lock */\n    tx->irrevocable++;\n    /* Try validating transaction */\n#if DESIGN == WRITE_BACK_ETL\n    if (!stm_wbetl_validate(tx)) {\n      stm_rollback(tx, STM_ABORT_VALIDATE);\n      return 0;\n    }\n#elif DESIGN == WRITE_BACK_CTL\n    if (!stm_wbctl_validate(tx)) {\n      stm_rollback(tx, STM_ABORT_VALIDATE);\n      return 0;\n    }\n#elif DESIGN == WRITE_THROUGH\n    if (!stm_wt_validate(tx)) {\n      stm_rollback(tx, STM_ABORT_VALIDATE);\n      return 0;\n    }\n#elif DESIGN == MODULAR\n    if ((tx->attr.id == WRITE_BACK_CTL && stm_wbctl_validate(tx))\n       || (tx->attr.id == WRITE_THROUGH && stm_wt_validate(tx))\n       || (tx->attr.id != WRITE_BACK_CTL && tx->attr.id != WRITE_THROUGH && stm_wbetl_validate(tx))) {\n      stm_rollback(tx, STM_ABORT_VALIDATE);\n      return 0;\n    }\n#endif /* DESIGN == MODULAR */\n\n# if CM == CM_MODULAR\n   /* We might still abort if we cannot set status (e.g., we are being killed) */\n    t = tx->status;\n    if (GET_STATUS(t) != TX_ACTIVE || ATOMIC_CAS_FULL(&tx->status, t, t + (TX_IRREVOCABLE - TX_ACTIVE)) == 0) {\n      stm_rollback(tx, STM_ABORT_KILLED);\n      return 0;\n    }\n# endif /* CM == CM_MODULAR */\n    if (serial && tx->w_set.nb_entries != 0) {\n      /* TODO: or commit the transaction when we have the irrevocability. */\n      /* Don't mix transactional and direct accesses => restart with direct accesses */\n      stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n      return 0;\n    }\n  } else if ((tx->irrevocable & 0x07) == 1) {\n    /* Acquire irrevocability after restart (no need to validate) */\n    while (_tinystm.irrevocable == 1 || ATOMIC_CAS_FULL(&_tinystm.irrevocable, 0, 1) == 0)\n      ;\n    /* Success: remember we have the lock */\n    tx->irrevocable++;\n  }\n  assert((tx->irrevocable & 0x07) == 2);\n\n  /* Are we in serial irrevocable mode? */\n  if ((tx->irrevocable & 0x08) != 0) {\n    /* Stop all other threads */\n    if (stm_quiesce(tx, 1) != 0) {\n      /* Another thread is quiescing and we are active (trying to acquire irrevocability) */\n      assert(serial != -1);\n      stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n      return 0;\n    }\n  }\n\n  /* We are in irrevocable mode */\n  tx->irrevocable++;\n\n#else /* ! IRREVOCABLE_ENABLED */\n  fprintf(stderr, \"Irrevocability is not supported in this configuration\\n\");\n  exit(-1);\n#endif /* ! IRREVOCABLE_ENABLED */\n  return 1;\n}\n\n_CALLCONV NOINLINE int\nstm_set_irrevocable(int serial)\n{\n  TX_GET;\n  return int_stm_set_irrevocable(tx, serial);\n}\n\n_CALLCONV NOINLINE int\nstm_set_irrevocable_tx(stm_tx_t *tx, int serial)\n{\n  return int_stm_set_irrevocable(tx, serial);\n}\n\n/*\n * Increment the value of global clock (Only for TinySTM developers).\n */\nvoid\nstm_inc_clock(void)\n{\n  FETCH_INC_CLOCK;\n}\n\n"
  },
  {
    "path": "stms/tinystm/src/stm_internal.h",
    "content": "/*\n * File:\n *   stm_internal.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM internal functions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _STM_INTERNAL_H_\n#define _STM_INTERNAL_H_\n\n#include <pthread.h>\n#include <string.h>\n#include <stm.h>\n#include \"tls.h\"\n#include \"utils.h\"\n#include \"atomic.h\"\n#include \"gc.h\"\n\n/* ################################################################### *\n * DEFINES\n * ################################################################### */\n\n/* Designs */\n#define WRITE_BACK_ETL                  0\n#define WRITE_BACK_CTL                  1\n#define WRITE_THROUGH                   2\n#define MODULAR                         3\n\n#ifndef DESIGN\n# define DESIGN                         WRITE_BACK_ETL\n#endif /* ! DESIGN */\n\n/* Contention managers */\n#define CM_SUICIDE                      0\n#define CM_DELAY                        1\n#define CM_BACKOFF                      2\n#define CM_MODULAR                      3\n\n#ifndef CM\n# define CM                             CM_SUICIDE\n#endif /* ! CM */\n\n#if DESIGN != WRITE_BACK_ETL && CM == CM_MODULAR\n# error \"MODULAR contention manager can only be used with WB-ETL design\"\n#endif /* DESIGN != WRITE_BACK_ETL && CM == CM_MODULAR */\n\n#if defined(CONFLICT_TRACKING) && ! defined(EPOCH_GC)\n# error \"CONFLICT_TRACKING requires EPOCH_GC\"\n#endif /* defined(CONFLICT_TRACKING) && ! defined(EPOCH_GC) */\n\n#if CM == CM_MODULAR && ! defined(EPOCH_GC)\n# error \"MODULAR contention manager requires EPOCH_GC\"\n#endif /* CM == CM_MODULAR && ! defined(EPOCH_GC) */\n\n#if defined(READ_LOCKED_DATA) && CM != CM_MODULAR\n# error \"READ_LOCKED_DATA can only be used with MODULAR contention manager\"\n#endif /* defined(READ_LOCKED_DATA) && CM != CM_MODULAR */\n\n#if defined(EPOCH_GC) && defined(SIGNAL_HANDLER)\n# error \"SIGNAL_HANDLER can only be used without EPOCH_GC\"\n#endif /* defined(EPOCH_GC) && defined(SIGNAL_HANDLER) */\n\n#define TX_GET                          stm_tx_t *tx = tls_get_tx()\n\n#ifndef RW_SET_SIZE\n# define RW_SET_SIZE                    4096                /* Initial size of read/write sets */\n#endif /* ! RW_SET_SIZE */\n\n#ifndef LOCK_ARRAY_LOG_SIZE\n# define LOCK_ARRAY_LOG_SIZE            20                  /* Size of lock array: 2^20 = 1M */\n#endif /* LOCK_ARRAY_LOG_SIZE */\n\n#ifndef LOCK_SHIFT_EXTRA\n# define LOCK_SHIFT_EXTRA               2                   /* 2 extra shift */\n#endif /* LOCK_SHIFT_EXTRA */\n\n#if CM == CM_BACKOFF\n# ifndef MIN_BACKOFF\n#  define MIN_BACKOFF                   (1UL << 2)\n# endif /* MIN_BACKOFF */\n# ifndef MAX_BACKOFF\n#  define MAX_BACKOFF                   (1UL << 31)\n# endif /* MAX_BACKOFF */\n#endif /* CM == CM_BACKOFF */\n\n#if CM == CM_MODULAR\n# define VR_THRESHOLD                   \"VR_THRESHOLD\"\n# ifndef VR_THRESHOLD_DEFAULT\n#  define VR_THRESHOLD_DEFAULT          3                   /* -1 means no visible reads. 0 means always use visible reads. */\n# endif /* VR_THRESHOLD_DEFAULT */\n#endif /* CM == CM_MODULAR */\n\n#define NO_SIGNAL_HANDLER               \"NO_SIGNAL_HANDLER\"\n\n#if defined(CTX_LONGJMP)\n# define JMP_BUF                        jmp_buf\n# define LONGJMP(ctx, value)            longjmp(ctx, value)\n#elif defined(CTX_ITM)\n/* TODO adjust size to real size. */\n# define JMP_BUF                        jmp_buf\n# define LONGJMP(ctx, value)            CTX_ITM(value, ctx)\n#else /* !CTX_LONGJMP && !CTX_ITM */\n# define JMP_BUF                        sigjmp_buf\n# define LONGJMP(ctx, value)            siglongjmp(ctx, value)\n#endif /* !CTX_LONGJMP && !CTX_ITM */\n\n\n/* ################################################################### *\n * TYPES\n * ################################################################### */\n\nenum {                                  /* Transaction status */\n  TX_IDLE = 0,\n  TX_ACTIVE = 1,                        /* Lowest bit indicates activity */\n  TX_COMMITTED = (1 << 1),\n  TX_ABORTED = (2 << 1),\n  TX_COMMITTING = (1 << 1) | TX_ACTIVE,\n  TX_ABORTING = (2 << 1) | TX_ACTIVE,\n  TX_KILLED = (3 << 1) | TX_ACTIVE,\n  TX_IRREVOCABLE = 0x08 | TX_ACTIVE     /* Fourth bit indicates irrevocability */\n};\n#define STATUS_BITS                     4\n#define STATUS_MASK                     ((1 << STATUS_BITS) - 1)\n\n#if CM == CM_MODULAR\n# define SET_STATUS(s, v)               ATOMIC_STORE_REL(&(s), ((s) & ~(stm_word_t)STATUS_MASK) | (v))\n# define INC_STATUS_COUNTER(s)          ((((s) >> STATUS_BITS) + 1) << STATUS_BITS)\n# define UPDATE_STATUS(s, v)            ATOMIC_STORE_REL(&(s), INC_STATUS_COUNTER(s) | (v))\n# define GET_STATUS(s)                  ((s) & STATUS_MASK)\n# define GET_STATUS_COUNTER(s)          ((s) >> STATUS_BITS)\n#else /* CM != CM_MODULAR */\n# define SET_STATUS(s, v)               ((s) = (v))\n# define UPDATE_STATUS(s, v)            ((s) = (v))\n# define GET_STATUS(s)                  ((s))\n#endif /* CM != CM_MODULAR */\n#define IS_ACTIVE(s)                    ((GET_STATUS(s) & 0x01) == TX_ACTIVE)\n\n/* ################################################################### *\n * LOCKS\n * ################################################################### */\n\n/*\n * A lock is a unsigned integer of the size of a pointer.\n * The LSB is the lock bit. If it is set, this means:\n * - At least some covered memory addresses is being written.\n * - All bits of the lock apart from the lock bit form\n *   a pointer that points to the write log entry holding the new\n *   value. Multiple values covered by the same log entry and orginized\n *   in a linked list in the write log.\n * If the lock bit is not set, then:\n * - All covered memory addresses contain consistent values.\n * - All bits of the lock besides the lock bit contain a version number\n *   (timestamp).\n *   - The high order bits contain the commit time.\n *   - The low order bits contain an incarnation number (incremented\n *     upon abort while writing the covered memory addresses).\n * When visible reads are enabled, two bits are used as read and write\n * locks. A read-locked address can be read by an invisible reader.\n */\n\n#if CM == CM_MODULAR\n# define OWNED_BITS                     2                   /* 2 bits */\n# define WRITE_MASK                     0x01                /* 1 bit */\n# define READ_MASK                      0x02                /* 1 bit */\n# define OWNED_MASK                     (WRITE_MASK | READ_MASK)\n#else /* CM != CM_MODULAR */\n# define OWNED_BITS                     1                   /* 1 bit */\n# define WRITE_MASK                     0x01                /* 1 bit */\n# define OWNED_MASK                     (WRITE_MASK)\n#endif /* CM != CM_MODULAR */\n#define INCARNATION_BITS                3                   /* 3 bits */\n#define INCARNATION_MAX                 ((1 << INCARNATION_BITS) - 1)\n#define INCARNATION_MASK                (INCARNATION_MAX << 1)\n#define LOCK_BITS                       (OWNED_BITS + INCARNATION_BITS)\n#define MAX_THREADS                     8192                /* Upper bound (large enough) */\n#define VERSION_MAX                     ((~(stm_word_t)0 >> LOCK_BITS) - MAX_THREADS)\n\n#define LOCK_GET_OWNED(l)               (l & OWNED_MASK)\n#define LOCK_GET_WRITE(l)               (l & WRITE_MASK)\n#define LOCK_SET_ADDR_WRITE(a)          (a | WRITE_MASK)    /* WRITE bit set */\n#define LOCK_GET_ADDR(l)                (l & ~(stm_word_t)OWNED_MASK)\n#if CM == CM_MODULAR\n# define LOCK_GET_READ(l)               (l & READ_MASK)\n# define LOCK_SET_ADDR_READ(a)          (a | READ_MASK)     /* READ bit set */\n# define LOCK_UPGRADE(l)                (l | WRITE_MASK)\n#endif /* CM == CM_MODULAR */\n#define LOCK_GET_TIMESTAMP(l)           (l >> (LOCK_BITS))\n#define LOCK_SET_TIMESTAMP(t)           (t << (LOCK_BITS))\n#define LOCK_GET_INCARNATION(l)         ((l & INCARNATION_MASK) >> OWNED_BITS)\n#define LOCK_SET_INCARNATION(i)         (i << OWNED_BITS)   /* OWNED bit not set */\n#define LOCK_UPD_INCARNATION(l, i)      ((l & ~(stm_word_t)(INCARNATION_MASK | OWNED_MASK)) | LOCK_SET_INCARNATION(i))\n#ifdef UNIT_TX\n# define LOCK_UNIT                       (~(stm_word_t)0)\n#endif /* UNIT_TX */\n\n/*\n * We use the very same hash functions as TL2 for degenerate Bloom\n * filters on 32 bits.\n */\n#ifdef USE_BLOOM_FILTER\n# define FILTER_HASH(a)                 (((stm_word_t)a >> 2) ^ ((stm_word_t)a >> 5))\n# define FILTER_BITS(a)                 (1 << (FILTER_HASH(a) & 0x1F))\n#endif /* USE_BLOOM_FILTER */\n\n/*\n * We use an array of locks and hash the address to find the location of the lock.\n * We try to avoid collisions as much as possible (two addresses covered by the same lock).\n */\n#define LOCK_ARRAY_SIZE                 (1 << LOCK_ARRAY_LOG_SIZE)\n#define LOCK_MASK                       (LOCK_ARRAY_SIZE - 1)\n#define LOCK_SHIFT                      (((sizeof(stm_word_t) == 4) ? 2 : 3) + LOCK_SHIFT_EXTRA)\n#define LOCK_IDX(a)                     (((stm_word_t)(a) >> LOCK_SHIFT) & LOCK_MASK)\n#ifdef LOCK_IDX_SWAP\n# if LOCK_ARRAY_LOG_SIZE < 16\n#  error \"LOCK_IDX_SWAP requires LOCK_ARRAY_LOG_SIZE to be at least 16\"\n# endif /* LOCK_ARRAY_LOG_SIZE < 16 */\n# define GET_LOCK(a)                    (_tinystm.locks + lock_idx_swap(LOCK_IDX(a)))\n#else /* ! LOCK_IDX_SWAP */\n# define GET_LOCK(a)                    (_tinystm.locks + LOCK_IDX(a))\n#endif /* ! LOCK_IDX_SWAP */\n\n/* ################################################################### *\n * CLOCK\n * ################################################################### */\n\n/* At least twice a cache line (not required if properly aligned and padded) */\n#define CLOCK                           (_tinystm.gclock[(CACHELINE_SIZE * 2) / sizeof(stm_word_t)])\n\n#define GET_CLOCK                       (ATOMIC_LOAD_ACQ(&CLOCK))\n#define FETCH_INC_CLOCK                 (ATOMIC_FETCH_INC_FULL(&CLOCK))\n\n/* ################################################################### *\n * CALLBACKS\n * ################################################################### */\n\n/* The number of 7 is chosen to make fit the number and the array in a\n * same cacheline (assuming 64bytes cacheline and 64bits CPU). */\n#define MAX_CB                          7\n\n/* Declare as static arrays (vs. lists) to improve cache locality */\n/* The number transaction local specific for modules. */\n#ifndef MAX_SPECIFIC\n# define MAX_SPECIFIC                   7\n#endif /* MAX_SPECIFIC */\n\n\ntypedef struct r_entry {                /* Read set entry */\n  stm_word_t version;                   /* Version read */\n  volatile stm_word_t *lock;            /* Pointer to lock (for fast access) */\n} r_entry_t;\n\ntypedef struct r_set {                  /* Read set */\n  r_entry_t *entries;                   /* Array of entries */\n  unsigned int nb_entries;              /* Number of entries */\n  unsigned int size;                    /* Size of array */\n} r_set_t;\n\ntypedef struct w_entry {                /* Write set entry */\n  union {                               /* For padding... */\n    struct {\n      volatile stm_word_t *addr;        /* Address written */\n      stm_word_t value;                 /* New (write-back) or old (write-through) value */\n      stm_word_t mask;                  /* Write mask */\n      stm_word_t version;               /* Version overwritten */\n      volatile stm_word_t *lock;        /* Pointer to lock (for fast access) */\n#if CM == CM_MODULAR || defined(CONFLICT_TRACKING)\n      struct stm_tx *tx;                /* Transaction owning the write set */\n#endif /* CM == CM_MODULAR || defined(CONFLICT_TRACKING) */\n      union {\n        struct w_entry *next;           /* WRITE_BACK_ETL || WRITE_THROUGH: Next address covered by same lock (if any) */\n        stm_word_t no_drop;             /* WRITE_BACK_CTL: Should we drop lock upon abort? */\n      };\n    };\n    char padding[CACHELINE_SIZE];       /* Padding (multiple of a cache line) */\n    /* Note padding is not useful here as long as the address can be defined in the lock scheme. */\n  };\n} w_entry_t;\n\ntypedef struct w_set {                  /* Write set */\n  w_entry_t *entries;                   /* Array of entries */\n  unsigned int nb_entries;              /* Number of entries */\n  unsigned int size;                    /* Size of array */\n  union {\n    unsigned int has_writes;            /* WRITE_BACK_ETL: Has the write set any real write (vs. visible reads) */\n    unsigned int nb_acquired;           /* WRITE_BACK_CTL: Number of locks acquired */\n  };\n#ifdef USE_BLOOM_FILTER\n  stm_word_t bloom;                     /* WRITE_BACK_CTL: Same Bloom filter as in TL2 */\n#endif /* USE_BLOOM_FILTER */\n} w_set_t;\n\ntypedef struct cb_entry {               /* Callback entry */\n  void (*f)(void *);                    /* Function */\n  void *arg;                            /* Argument to be passed to function */\n} cb_entry_t;\n\ntypedef struct stm_tx {                 /* Transaction descriptor */\n  JMP_BUF env;                          /* Environment for setjmp/longjmp */\n  stm_tx_attr_t attr;                   /* Transaction attributes (user-specified) */\n  volatile stm_word_t status;           /* Transaction status */\n  stm_word_t start;                     /* Start timestamp */\n  stm_word_t end;                       /* End timestamp (validity range) */\n  r_set_t r_set;                        /* Read set */\n  w_set_t w_set;                        /* Write set */\n#ifdef IRREVOCABLE_ENABLED\n  unsigned int irrevocable:4;           /* Is this execution irrevocable? */\n#endif /* IRREVOCABLE_ENABLED */\n  unsigned int nesting;                 /* Nesting level */\n#if CM == CM_MODULAR\n  stm_word_t timestamp;                 /* Timestamp (not changed upon restart) */\n#endif /* CM == CM_MODULAR */\n  void *data[MAX_SPECIFIC];             /* Transaction-specific data (fixed-size array for better speed) */\n  struct stm_tx *next;                  /* For keeping track of all transactional threads */\n#ifdef CONFLICT_TRACKING\n  pthread_t thread_id;                  /* Thread identifier (immutable) */\n#endif /* CONFLICT_TRACKING */\n#if CM == CM_DELAY || CM == CM_MODULAR\n  volatile stm_word_t *c_lock;          /* Pointer to contented lock (cause of abort) */\n#endif /* CM == CM_DELAY || CM == CM_MODULAR */\n#if CM == CM_BACKOFF\n  unsigned long backoff;                /* Maximum backoff duration */\n  unsigned long seed;                   /* RNG seed */\n#endif /* CM == CM_BACKOFF */\n#if CM == CM_MODULAR\n  int visible_reads;                    /* Should we use visible reads? */\n#endif /* CM == CM_MODULAR */\n#if CM == CM_MODULAR || defined(TM_STATISTICS)\n  unsigned int stat_retries;            /* Number of consecutive aborts (retries) */\n#endif /* CM == CM_MODULAR || defined(TM_STATISTICS) */\n#ifdef TM_STATISTICS\n  unsigned int stat_commits;            /* Total number of commits (cumulative) */\n  unsigned int stat_aborts;             /* Total number of aborts (cumulative) */\n  unsigned int stat_retries_max;        /* Maximum number of consecutive aborts (retries) */\n#endif /* TM_STATISTICS */\n#ifdef TM_STATISTICS2\n  unsigned int stat_aborts_1;           /* Total number of transactions that abort once or more (cumulative) */\n  unsigned int stat_aborts_2;           /* Total number of transactions that abort twice or more (cumulative) */\n  unsigned int stat_aborts_r[16];       /* Total number of transactions that abort wrt. abort reason (cumulative) */\n# ifdef READ_LOCKED_DATA\n  unsigned int stat_locked_reads_ok;    /* Successful reads of previous value */\n  unsigned int stat_locked_reads_failed;/* Failed reads of previous value */\n# endif /* READ_LOCKED_DATA */\n#endif /* TM_STATISTICS2 */\n} stm_tx_t;\n\n/* This structure should be ordered by hot and cold variables */\ntypedef struct {\n  volatile stm_word_t locks[LOCK_ARRAY_SIZE] ALIGNED;\n  volatile stm_word_t gclock[512 / sizeof(stm_word_t)] ALIGNED;\n  unsigned int nb_specific;             /* Number of specific slots used (<= MAX_SPECIFIC) */\n  unsigned int nb_init_cb;\n  cb_entry_t init_cb[MAX_CB];           /* Init thread callbacks */\n  unsigned int nb_exit_cb;\n  cb_entry_t exit_cb[MAX_CB];           /* Exit thread callbacks */\n  unsigned int nb_start_cb;\n  cb_entry_t start_cb[MAX_CB];          /* Start callbacks */\n  unsigned int nb_precommit_cb;\n  cb_entry_t precommit_cb[MAX_CB];      /* Commit callbacks */\n  unsigned int nb_commit_cb;\n  cb_entry_t commit_cb[MAX_CB];         /* Commit callbacks */\n  unsigned int nb_abort_cb;\n  cb_entry_t abort_cb[MAX_CB];          /* Abort callbacks */\n  unsigned int initialized;             /* Has the library been initialized? */\n#ifdef IRREVOCABLE_ENABLED\n  volatile stm_word_t irrevocable;      /* Irrevocability status */\n#endif /* IRREVOCABLE_ENABLED */\n  volatile stm_word_t quiesce;          /* Prevent threads from entering transactions upon quiescence */\n  volatile stm_word_t threads_nb;       /* Number of active threads */\n  stm_tx_t *threads;                    /* Head of linked list of threads */\n  pthread_mutex_t quiesce_mutex;        /* Mutex to support quiescence */\n  pthread_cond_t quiesce_cond;          /* Condition variable to support quiescence */\n#if CM == CM_MODULAR\n  int vr_threshold;                     /* Number of retries before to switch to visible reads. */\n#endif /* CM == CM_MODULAR */\n#ifdef CONFLICT_TRACKING\n  void (*conflict_cb)(stm_tx_t *, stm_tx_t *);\n#endif /* CONFLICT_TRACKING */\n#if CM == CM_MODULAR\n  int (*contention_manager)(stm_tx_t *, stm_tx_t *, int);\n#endif /* CM == CM_MODULAR */\n  /* At least twice a cache line (256 bytes to be on the safe side) */\n  char padding[CACHELINE_SIZE];\n} ALIGNED global_t;\n\nextern global_t _tinystm;\n\n#if CM == CM_MODULAR\n# define KILL_SELF                      0x00\n# define KILL_OTHER                     0x01\n# define DELAY_RESTART                  0x04\n\n# define RR_CONFLICT                    0x00\n# define RW_CONFLICT                    0x01\n# define WR_CONFLICT                    0x02\n# define WW_CONFLICT                    0x03\n#endif /* CM == CM_MODULAR */\n\n/* ################################################################### *\n * FUNCTIONS DECLARATIONS\n * ################################################################### */\n\nstatic NOINLINE void\nstm_rollback(stm_tx_t *tx, unsigned int reason);\n\n/* ################################################################### *\n * INLINE FUNCTIONS\n * ################################################################### */\n\n#ifdef LOCK_IDX_SWAP\n/*\n * Compute index in lock table (swap bytes to avoid consecutive addresses to have neighboring locks).\n */\nstatic INLINE unsigned int\nlock_idx_swap(unsigned int idx)\n{\n  return (idx & ~(unsigned int)0xFFFF) | ((idx & 0x00FF) << 8) | ((idx & 0xFF00) >> 8);\n}\n#endif /* LOCK_IDX_SWAP */\n\n\n/*\n * Initialize quiescence support.\n */\nstatic INLINE void\nstm_quiesce_init(void)\n{\n  PRINT_DEBUG(\"==> stm_quiesce_init()\\n\");\n\n  if (pthread_mutex_init(&_tinystm.quiesce_mutex, NULL) != 0) {\n    fprintf(stderr, \"Error creating mutex\\n\");\n    exit(1);\n  }\n  if (pthread_cond_init(&_tinystm.quiesce_cond, NULL) != 0) {\n    fprintf(stderr, \"Error creating condition variable\\n\");\n    exit(1);\n  }\n  _tinystm.quiesce = 0;\n  _tinystm.threads_nb = 0;\n  _tinystm.threads = NULL;\n}\n\n/*\n * Clean up quiescence support.\n */\nstatic INLINE void\nstm_quiesce_exit(void)\n{\n  PRINT_DEBUG(\"==> stm_quiesce_exit()\\n\");\n\n  pthread_cond_destroy(&_tinystm.quiesce_cond);\n  pthread_mutex_destroy(&_tinystm.quiesce_mutex);\n}\n\n/*\n * Called by each thread upon initialization for quiescence support.\n */\nstatic INLINE void\nstm_quiesce_enter_thread(stm_tx_t *tx)\n{\n  PRINT_DEBUG(\"==> stm_quiesce_enter_thread(%p)\\n\", tx);\n\n  pthread_mutex_lock(&_tinystm.quiesce_mutex);\n  /* Add new descriptor at head of list */\n  tx->next = _tinystm.threads;\n  _tinystm.threads = tx;\n  _tinystm.threads_nb++;\n  pthread_mutex_unlock(&_tinystm.quiesce_mutex);\n}\n\n/*\n * Called by each thread upon exit for quiescence support.\n */\nstatic INLINE void\nstm_quiesce_exit_thread(stm_tx_t *tx)\n{\n  stm_tx_t *t, *p;\n\n  PRINT_DEBUG(\"==> stm_quiesce_exit_thread(%p)\\n\", tx);\n\n  /* Can only be called if non-active */\n  assert(!IS_ACTIVE(tx->status));\n\n  pthread_mutex_lock(&_tinystm.quiesce_mutex);\n  /* Remove descriptor from list */\n  p = NULL;\n  t = _tinystm.threads;\n  while (t != tx) {\n    assert(t != NULL);\n    p = t;\n    t = t->next;\n  }\n  if (p == NULL)\n    _tinystm.threads = t->next;\n  else\n    p->next = t->next;\n  _tinystm.threads_nb--;\n  if (_tinystm.quiesce) {\n    /* Wake up someone in case other threads are waiting for us */\n    pthread_cond_signal(&_tinystm.quiesce_cond);\n  }\n  pthread_mutex_unlock(&_tinystm.quiesce_mutex);\n}\n\n/*\n * Wait for all transactions to be block on a barrier.\n */\nstatic NOINLINE void\nstm_quiesce_barrier(stm_tx_t *tx, void (*f)(void *), void *arg)\n{\n  PRINT_DEBUG(\"==> stm_quiesce_barrier()\\n\");\n\n  /* Can only be called if non-active */\n  assert(tx == NULL || !IS_ACTIVE(tx->status));\n\n  pthread_mutex_lock(&_tinystm.quiesce_mutex);\n  /* Wait for all other transactions to block on barrier */\n  _tinystm.threads_nb--;\n  if (_tinystm.quiesce == 0) {\n    /* We are first on the barrier */\n    _tinystm.quiesce = 1;\n  }\n  while (_tinystm.quiesce) {\n    if (_tinystm.threads_nb == 0) {\n      /* Everybody is blocked */\n      if (f != NULL)\n        f(arg);\n      /* Release transactional threads */\n      _tinystm.quiesce = 0;\n      pthread_cond_broadcast(&_tinystm.quiesce_cond);\n    } else {\n      /* Wait for other transactions to stop */\n      pthread_cond_wait(&_tinystm.quiesce_cond, &_tinystm.quiesce_mutex);\n    }\n  }\n  _tinystm.threads_nb++;\n  pthread_mutex_unlock(&_tinystm.quiesce_mutex);\n}\n\n/*\n * Wait for all transactions to be out of their current transaction.\n */\nstatic INLINE int\nstm_quiesce(stm_tx_t *tx, int block)\n{\n  stm_tx_t *t;\n#if CM == CM_MODULAR\n  stm_word_t s, c;\n#endif /* CM == CM_MODULAR */\n\n  PRINT_DEBUG(\"==> stm_quiesce(%p,%d)\\n\", tx, block);\n\n  if (IS_ACTIVE(tx->status)) {\n    /* Only one active transaction can quiesce at a time, others must abort */\n    if (pthread_mutex_trylock(&_tinystm.quiesce_mutex) != 0)\n      return 1;\n  } else {\n    /* We can safely block because we are inactive */\n    pthread_mutex_lock(&_tinystm.quiesce_mutex);\n  }\n  /* We own the lock at this point */\n  if (block)\n    ATOMIC_STORE_REL(&_tinystm.quiesce, 2);\n  /* Make sure we read latest status data */\n  ATOMIC_MB_FULL;\n  /* Not optimal as we check transaction sequentially and might miss some inactivity states */\n  for (t = _tinystm.threads; t != NULL; t = t->next) {\n    if (t == tx)\n      continue;\n    /* Wait for all other transactions to become inactive */\n#if CM == CM_MODULAR\n    s = t->status;\n    if (IS_ACTIVE(s)) {\n      c = GET_STATUS_COUNTER(s);\n      do {\n        s = t->status;\n      } while (IS_ACTIVE(s) && c == GET_STATUS_COUNTER(s));\n    }\n#else /* CM != CM_MODULAR */\n    while (IS_ACTIVE(t->status))\n      ;\n#endif /* CM != CM_MODULAR */\n  }\n  if (!block)\n    pthread_mutex_unlock(&_tinystm.quiesce_mutex);\n  return 0;\n}\n\n/*\n * Check if transaction must block.\n */\nstatic INLINE int\nstm_check_quiesce(stm_tx_t *tx)\n{\n  stm_word_t s;\n\n  /* Must be called upon start (while already active but before acquiring any lock) */\n  assert(IS_ACTIVE(tx->status));\n\n  /* ATOMIC_MB_FULL;  The full memory barrier is not required here since quiesce\n   * is atomic. Only a compiler barrier is needed to avoid reordering. */\n  ATOMIC_CB;\n\n  if (unlikely(ATOMIC_LOAD_ACQ(&_tinystm.quiesce) == 2)) {\n#ifdef IRREVOCABLE_ENABLED\n    /* Only test it when quiesce == 2, it avoids one comparison for fast-path. */\n    /* TODO check if it is correct. */\n    if (unlikely((tx->irrevocable & 0x08) != 0)) {\n      /* Serial irrevocable mode: we are executing alone */\n      return 0;\n    }\n#endif /* IRREVOCABLE_ENABLED */\n    s = ATOMIC_LOAD(&tx->status);\n    SET_STATUS(tx->status, TX_IDLE);\n    while (ATOMIC_LOAD_ACQ(&_tinystm.quiesce) == 2) {\n#ifdef WAIT_YIELD\n      sched_yield();\n#endif /* WAIT_YIELD */\n    }\n    SET_STATUS(tx->status, GET_STATUS(s));\n    return 1;\n  }\n  return 0;\n}\n\n/*\n * Release threads blocked after quiescence.\n */\nstatic INLINE void\nstm_quiesce_release(stm_tx_t *tx)\n{\n  ATOMIC_STORE_REL(&_tinystm.quiesce, 0);\n  pthread_mutex_unlock(&_tinystm.quiesce_mutex);\n}\n\n/*\n * Reset clock and timestamps\n */\nstatic INLINE void\nrollover_clock(void *arg)\n{\n  PRINT_DEBUG(\"==> rollover_clock()\\n\");\n\n  /* Reset clock */\n  CLOCK = 0;\n  /* Reset timestamps */\n  memset((void *)_tinystm.locks, 0, LOCK_ARRAY_SIZE * sizeof(stm_word_t));\n# ifdef EPOCH_GC\n  /* Reset GC */\n  gc_reset();\n# endif /* EPOCH_GC */\n}\n\n/*\n * Check if stripe has been read previously.\n */\nstatic INLINE r_entry_t *\nstm_has_read(stm_tx_t *tx, volatile stm_word_t *lock)\n{\n  r_entry_t *r;\n  int i;\n\n  PRINT_DEBUG(\"==> stm_has_read(%p[%lu-%lu],%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, lock);\n\n#if CM == CM_MODULAR\n  /* TODO case of visible read is not handled */\n#endif /* CM == CM_MODULAR */\n\n  /* Look for read */\n  r = tx->r_set.entries;\n  for (i = tx->r_set.nb_entries; i > 0; i--, r++) {\n    if (r->lock == lock) {\n      /* Return first match*/\n      return r;\n    }\n  }\n  return NULL;\n}\n\n/*\n * Check if address has been written previously.\n */\nstatic INLINE w_entry_t *\nstm_has_written(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  w_entry_t *w;\n  int i;\n# ifdef USE_BLOOM_FILTER\n  stm_word_t mask;\n# endif /* USE_BLOOM_FILTER */\n\n  PRINT_DEBUG(\"==> stm_has_written(%p[%lu-%lu],%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\n# ifdef USE_BLOOM_FILTER\n  mask = FILTER_BITS(addr);\n  if ((tx->w_set.bloom & mask) != mask)\n    return NULL;\n# endif /* USE_BLOOM_FILTER */\n\n  /* Look for write */\n  w = tx->w_set.entries;\n  for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n    if (w->addr == addr) {\n      return w;\n    }\n  }\n  return NULL;\n}\n\n/*\n * (Re)allocate read set entries.\n */\nstatic NOINLINE void\nstm_allocate_rs_entries(stm_tx_t *tx, int extend)\n{\n  PRINT_DEBUG(\"==> stm_allocate_rs_entries(%p[%lu-%lu],%d)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, extend);\n\n  if (extend) {\n    /* Extend read set */\n    tx->r_set.size *= 2;\n    tx->r_set.entries = (r_entry_t *)xrealloc(tx->r_set.entries, tx->r_set.size * sizeof(r_entry_t));\n  } else {\n    /* Allocate read set */\n    tx->r_set.entries = (r_entry_t *)xmalloc_aligned(tx->r_set.size * sizeof(r_entry_t));\n  }\n}\n\n/*\n * (Re)allocate write set entries.\n */\nstatic NOINLINE void\nstm_allocate_ws_entries(stm_tx_t *tx, int extend)\n{\n#if CM == CM_MODULAR || defined(CONFLICT_TRACKING)\n  int i, first = (extend ? tx->w_set.size : 0);\n#endif /* CM == CM_MODULAR || defined(CONFLICT_TRACKING) */\n#ifdef EPOCH_GC\n  void *a;\n#endif /* ! EPOCH_GC */\n\n  PRINT_DEBUG(\"==> stm_allocate_ws_entries(%p[%lu-%lu],%d)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, extend);\n\n  if (extend) {\n    /* Extend write set */\n    /* Transaction must be inactive for WRITE_THROUGH or WRITE_BACK_ETL */\n    tx->w_set.size *= 2;\n#ifdef EPOCH_GC\n    a = tx->w_set.entries;\n    tx->w_set.entries = (w_entry_t *)xmalloc_aligned(tx->w_set.size * sizeof(w_entry_t));\n    memcpy(tx->w_set.entries, a, tx->w_set.size / 2 * sizeof(w_entry_t));\n    gc_free(a, GET_CLOCK);\n#else /* ! EPOCH_GC */\n    tx->w_set.entries = (w_entry_t *)xrealloc(tx->w_set.entries, tx->w_set.size * sizeof(w_entry_t));\n#endif /* ! EPOCH_GC */\n  } else {\n    /* Allocate write set */\n    tx->w_set.entries = (w_entry_t *)xmalloc_aligned(tx->w_set.size * sizeof(w_entry_t));\n  }\n  /* Ensure that memory is aligned. */\n  assert((((stm_word_t)tx->w_set.entries) & OWNED_MASK) == 0);\n\n#if CM == CM_MODULAR || defined(CONFLICT_TRACKING)\n  /* Initialize fields */\n  for (i = first; i < tx->w_set.size; i++)\n    tx->w_set.entries[i].tx = tx;\n#endif /* CM == CM_MODULAR || defined(CONFLICT_TRACKING) */\n}\n\n\n#if DESIGN == WRITE_BACK_ETL\n# include \"stm_wbetl.h\"\n#elif DESIGN == WRITE_BACK_CTL\n# include \"stm_wbctl.h\"\n#elif DESIGN == WRITE_THROUGH\n# include \"stm_wt.h\"\n#elif DESIGN == MODULAR\n# include \"stm_wbetl.h\"\n# include \"stm_wbctl.h\"\n# include \"stm_wt.h\"\n#endif /* DESIGN == MODULAR */\n\n#if CM == CM_MODULAR\n/*\n * Kill other transaction.\n */\nstatic NOINLINE int\nstm_kill(stm_tx_t *tx, stm_tx_t *other, stm_word_t status)\n{\n  stm_word_t c, t;\n\n  PRINT_DEBUG(\"==> stm_kill(%p[%lu-%lu],%p,s=%d)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, other, status);\n\n# ifdef CONFLICT_TRACKING\n  if (_tinystm.conflict_cb != NULL)\n    _tinystm.conflict_cb(tx, other);\n# endif /* CONFLICT_TRACKING */\n\n# ifdef IRREVOCABLE_ENABLED\n  if (GET_STATUS(status) == TX_IRREVOCABLE)\n    return 0;\n# endif /* IRREVOCABLE_ENABLED */\n  if (GET_STATUS(status) == TX_ABORTED || GET_STATUS(status) == TX_COMMITTED || GET_STATUS(status) == TX_KILLED || GET_STATUS(status) == TX_IDLE)\n    return 0;\n  if (GET_STATUS(status) == TX_ABORTING || GET_STATUS(status) == TX_COMMITTING) {\n    /* Transaction is already aborting or committing: wait */\n    while (other->status == status)\n      ;\n    return 0;\n  }\n  assert(IS_ACTIVE(status));\n  /* Set status to KILLED */\n  if (ATOMIC_CAS_FULL(&other->status, status, status + (TX_KILLED - TX_ACTIVE)) == 0) {\n    /* Transaction is committing/aborting (or has committed/aborted) */\n    c = GET_STATUS_COUNTER(status);\n    do {\n      t = other->status;\n# ifdef IRREVOCABLE_ENABLED\n      if (GET_STATUS(t) == TX_IRREVOCABLE)\n        return 0;\n# endif /* IRREVOCABLE_ENABLED */\n    } while (GET_STATUS(t) != TX_ABORTED && GET_STATUS(t) != TX_COMMITTED && GET_STATUS(t) != TX_KILLED && GET_STATUS(t) != TX_IDLE && GET_STATUS_COUNTER(t) == c);\n    return 0;\n  }\n  /* We have killed the transaction: we can steal the lock */\n  return 1;\n}\n\n/*\n * Drop locks after having been killed.\n */\nstatic NOINLINE void\nstm_drop(stm_tx_t *tx)\n{\n  w_entry_t *w;\n  stm_word_t l;\n  int i;\n\n  PRINT_DEBUG(\"==> stm_drop(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Drop locks */\n  i = tx->w_set.nb_entries;\n  if (i > 0) {\n    w = tx->w_set.entries;\n    for (; i > 0; i--, w++) {\n      l = ATOMIC_LOAD_ACQ(w->lock);\n      if (LOCK_GET_OWNED(l) && (w_entry_t *)LOCK_GET_ADDR(l) == w) {\n        /* Drop using CAS */\n        ATOMIC_CAS_FULL(w->lock, l, LOCK_SET_TIMESTAMP(w->version));\n        /* If CAS fail, lock has been stolen or already released in case a lock covers multiple addresses */\n      }\n    }\n    /* We need to reallocate the write set to avoid an ABA problem (the\n     * transaction could reuse the same entry after having been killed\n     * and restarted, and another slow transaction could steal the lock\n     * using CAS without noticing the restart) */\n    gc_free(tx->w_set.entries, GET_CLOCK);\n    stm_allocate_ws_entries(tx, 0);\n  }\n}\n#endif /* CM == CM_MODULAR */\n\n/*\n * Initialize the transaction descriptor before start or restart.\n */\nstatic INLINE void\nint_stm_prepare(stm_tx_t *tx)\n{\n#if CM == CM_MODULAR\n  if (tx->attr.visible_reads || (tx->visible_reads >= _tinystm.vr_threshold && _tinystm.vr_threshold >= 0)) {\n    /* Use visible read */\n    tx->attr.visible_reads = 1;\n    tx->attr.read_only = 0;\n  }\n#endif /* CM == CM_MODULAR */\n\n  /* Read/write set */\n  /* has_writes / nb_acquired are the same field. */\n  tx->w_set.has_writes = 0;\n  /* tx->w_set.nb_acquired = 0; */\n#ifdef USE_BLOOM_FILTER\n  tx->w_set.bloom = 0;\n#endif /* USE_BLOOM_FILTER */\n  tx->w_set.nb_entries = 0;\n  tx->r_set.nb_entries = 0;\n\n start:\n  /* Start timestamp */\n  tx->start = tx->end = GET_CLOCK; /* OPT: Could be delayed until first read/write */\n  if (unlikely(tx->start >= VERSION_MAX)) {\n    /* Block all transactions and reset clock */\n    stm_quiesce_barrier(tx, rollover_clock, NULL);\n    goto start;\n  }\n#if CM == CM_MODULAR\n  if (tx->stat_retries == 0)\n    tx->timestamp = tx->start;\n#endif /* CM == CM_MODULAR */\n\n#ifdef EPOCH_GC\n  gc_set_epoch(tx->start);\n#endif /* EPOCH_GC */\n\n#ifdef IRREVOCABLE_ENABLED\n  if (unlikely(tx->irrevocable != 0)) {\n    assert(!IS_ACTIVE(tx->status));\n    stm_set_irrevocable_tx(tx, -1);\n    UPDATE_STATUS(tx->status, TX_IRREVOCABLE);\n  } else\n    UPDATE_STATUS(tx->status, TX_ACTIVE);\n#else /* ! IRREVOCABLE_ENABLED */\n  /* Set status */\n  UPDATE_STATUS(tx->status, TX_ACTIVE);\n#endif /* ! IRREVOCABLE_ENABLED */\n\n  stm_check_quiesce(tx);\n}\n\n/*\n * Rollback transaction.\n */\nstatic NOINLINE void\nstm_rollback(stm_tx_t *tx, unsigned int reason)\n{\n#if CM == CM_BACKOFF\n  unsigned long wait;\n  volatile int j;\n#endif /* CM == CM_BACKOFF */\n#if CM == CM_MODULAR\n  stm_word_t t;\n#endif /* CM == CM_MODULAR */\n\n  PRINT_DEBUG(\"==> stm_rollback(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  assert(IS_ACTIVE(tx->status));\n\n#ifdef IRREVOCABLE_ENABLED\n  /* Irrevocable cannot abort */\n  assert((tx->irrevocable & 0x07) != 3);\n#endif /* IRREVOCABLE_ENABLED */\n\n#if CM == CM_MODULAR\n  /* Set status to ABORTING */\n  t = tx->status;\n  if (GET_STATUS(t) == TX_KILLED || (GET_STATUS(t) == TX_ACTIVE && ATOMIC_CAS_FULL(&tx->status, t, t + (TX_ABORTING - TX_ACTIVE)) == 0)) {\n    /* We have been killed */\n    assert(GET_STATUS(tx->status) == TX_KILLED);\n    /* Release locks */\n    stm_drop(tx);\n    goto dropped;\n  }\n#endif /* CM == CM_MODULAR */\n\n#if DESIGN == WRITE_BACK_ETL\n  stm_wbetl_rollback(tx);\n#elif DESIGN == WRITE_BACK_CTL\n  stm_wbctl_rollback(tx);\n#elif DESIGN == WRITE_THROUGH\n  stm_wt_rollback(tx);\n#elif DESIGN == MODULAR\n  if (tx->attr.id == WRITE_BACK_CTL)\n    stm_wbctl_rollback(tx);\n  else if (tx->attr.id == WRITE_THROUGH)\n    stm_wt_rollback(tx);\n  else\n    stm_wbetl_rollback(tx);\n#endif /* DESIGN == MODULAR */\n\n#if CM == CM_MODULAR\n dropped:\n#endif /* CM == CM_MODULAR */\n\n#if CM == CM_MODULAR || defined(TM_STATISTICS)\n  tx->stat_retries++;\n#endif /* CM == CM_MODULAR || defined(TM_STATISTICS) */\n#ifdef TM_STATISTICS\n  tx->stat_aborts++;\n  if (tx->stat_retries_max < tx->stat_retries)\n    tx->stat_retries_max = tx->stat_retries;\n#endif /* TM_STATISTICS */\n#ifdef TM_STATISTICS2\n  /* Aborts stats wrt reason */\n  tx->stat_aborts_r[(reason >> 8) & 0x0F]++;\n  if (tx->stat_retries == 1)\n    tx->stat_aborts_1++;\n  else if (tx->stat_retries == 2)\n    tx->stat_aborts_2++;\n#endif /* TM_STATISTICS2 */\n\n  /* Set status to ABORTED */\n  SET_STATUS(tx->status, TX_ABORTED);\n\n  /* Abort for extending the write set */\n  if (unlikely(reason == STM_ABORT_EXTEND_WS)) {\n    stm_allocate_ws_entries(tx, 1);\n  }\n\n  /* Reset nesting level */\n  tx->nesting = 1;\n\n  /* Callbacks */\n  if (likely(_tinystm.nb_abort_cb != 0)) {\n    unsigned int cb;\n    for (cb = 0; cb < _tinystm.nb_abort_cb; cb++)\n      _tinystm.abort_cb[cb].f(_tinystm.abort_cb[cb].arg);\n  }\n\n#if CM == CM_BACKOFF\n  /* Simple RNG (good enough for backoff) */\n  tx->seed ^= (tx->seed << 17);\n  tx->seed ^= (tx->seed >> 13);\n  tx->seed ^= (tx->seed << 5);\n  wait = tx->seed % tx->backoff;\n  for (j = 0; j < wait; j++) {\n    /* Do nothing */\n  }\n  if (tx->backoff < MAX_BACKOFF)\n    tx->backoff <<= 1;\n#endif /* CM == CM_BACKOFF */\n\n#if CM == CM_DELAY || CM == CM_MODULAR\n  /* Wait until contented lock is free */\n  if (tx->c_lock != NULL) {\n    /* Busy waiting (yielding is expensive) */\n    while (LOCK_GET_OWNED(ATOMIC_LOAD(tx->c_lock))) {\n# ifdef WAIT_YIELD\n      sched_yield();\n# endif /* WAIT_YIELD */\n    }\n    tx->c_lock = NULL;\n  }\n#endif /* CM == CM_DELAY || CM == CM_MODULAR */\n\n  /* Don't prepare a new transaction if no retry. */\n  if (tx->attr.no_retry || (reason & STM_ABORT_NO_RETRY) == STM_ABORT_NO_RETRY) {\n    tx->nesting = 0;\n    return;\n  }\n\n  /* Reset field to restart transaction */\n  int_stm_prepare(tx);\n\n  /* Jump back to transaction start */\n  /* Note: ABI usually requires 0x09 (runInstrumented+restoreLiveVariable) */\n#ifdef IRREVOCABLE_ENABLED\n  /* If the transaction is serial irrevocable, indicate that uninstrumented\n   * code path must be executed (mixing instrumented and uninstrumented\n   * accesses are not allowed) */\n  reason |= (tx->irrevocable == 0x0B) ? STM_PATH_UNINSTRUMENTED : STM_PATH_INSTRUMENTED;\n#else /* ! IRREVOCABLE_ENABLED */\n  reason |= STM_PATH_INSTRUMENTED;\n#endif /* ! IRREVOCABLE_ENABLED */\n  LONGJMP(tx->env, reason);\n}\n\n/*\n * Store a word-sized value (return write set entry or NULL).\n */\nstatic INLINE w_entry_t *\nstm_write(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  w_entry_t *w;\n\n  PRINT_DEBUG2(\"==> stm_write(t=%p[%lu-%lu],a=%p,d=%p-%lu,m=0x%lx)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n#if CM == CM_MODULAR\n  if (GET_STATUS(tx->status) == TX_KILLED) {\n    stm_rollback(tx, STM_ABORT_KILLED);\n    return NULL;\n  }\n#else /* CM != CM_MODULAR */\n  assert(IS_ACTIVE(tx->status));\n#endif /* CM != CM_MODULAR */\n\n#ifdef DEBUG\n  /* Check consistency with read_only attribute. */\n  assert(!tx->attr.read_only);\n#endif /* DEBUG */\n\n#if DESIGN == WRITE_BACK_ETL\n  w = stm_wbetl_write(tx, addr, value, mask);\n#elif DESIGN == WRITE_BACK_CTL\n  w = stm_wbctl_write(tx, addr, value, mask);\n#elif DESIGN == WRITE_THROUGH\n  w = stm_wt_write(tx, addr, value, mask);\n#elif DESIGN == MODULAR\n  if (tx->attr.id == WRITE_BACK_CTL)\n    w = stm_wbctl_write(tx, addr, value, mask);\n  else if (tx->attr.id == WRITE_THROUGH)\n    w = stm_wt_write(tx, addr, value, mask);\n  else\n    w = stm_wbetl_write(tx, addr, value, mask);\n#endif /* DESIGN == WRITE_THROUGH */\n\n  return w;\n}\n\nstatic INLINE stm_word_t\nint_stm_RaR(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  stm_word_t value;\n#if DESIGN == WRITE_BACK_ETL\n  value = stm_wbetl_RaR(tx, addr);\n#elif DESIGN == WRITE_BACK_CTL\n  value = stm_wbctl_RaR(tx, addr);\n#elif DESIGN == WRITE_THROUGH\n  value = stm_wt_RaR(tx, addr);\n#endif /* DESIGN == WRITE_THROUGH */\n  return value;\n}\n\nstatic INLINE stm_word_t\nint_stm_RaW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  stm_word_t value;\n#if DESIGN == WRITE_BACK_ETL\n  value = stm_wbetl_RaW(tx, addr);\n#elif DESIGN == WRITE_BACK_CTL\n  value = stm_wbctl_RaW(tx, addr);\n#elif DESIGN == WRITE_THROUGH\n  value = stm_wt_RaW(tx, addr);\n#endif /* DESIGN == WRITE_THROUGH */\n  return value;\n}\n\nstatic INLINE stm_word_t\nint_stm_RfW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  stm_word_t value;\n#if DESIGN == WRITE_BACK_ETL\n  value = stm_wbetl_RfW(tx, addr);\n#elif DESIGN == WRITE_BACK_CTL\n  value = stm_wbctl_RfW(tx, addr);\n#elif DESIGN == WRITE_THROUGH\n  value = stm_wt_RfW(tx, addr);\n#endif /* DESIGN == WRITE_THROUGH */\n  return value;\n}\n\nstatic INLINE void\nint_stm_WaR(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n#if DESIGN == WRITE_BACK_ETL\n  stm_wbetl_WaR(tx, addr, value, mask);\n#elif DESIGN == WRITE_BACK_CTL\n  stm_wbctl_WaR(tx, addr, value, mask);\n#elif DESIGN == WRITE_THROUGH\n  stm_wt_WaR(tx, addr, value, mask);\n#endif /* DESIGN == WRITE_THROUGH */\n}\n\nstatic INLINE void\nint_stm_WaW(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n#if DESIGN == WRITE_BACK_ETL\n  stm_wbetl_WaW(tx, addr, value, mask);\n#elif DESIGN == WRITE_BACK_CTL\n  stm_wbctl_WaW(tx, addr, value, mask);\n#elif DESIGN == WRITE_THROUGH\n  stm_wt_WaW(tx, addr, value, mask);\n#endif /* DESIGN == WRITE_THROUGH */\n}\n\nstatic INLINE stm_tx_t *\nint_stm_init_thread(void)\n{\n  stm_tx_t *tx;\n\n  PRINT_DEBUG(\"==> stm_init_thread()\\n\");\n\n  /* Avoid initializing more than once */\n  if ((tx = tls_get_tx()) != NULL)\n    return tx;\n\n#ifdef EPOCH_GC\n  gc_init_thread();\n#endif /* EPOCH_GC */\n\n  /* Allocate descriptor */\n  tx = (stm_tx_t *)xmalloc_aligned(sizeof(stm_tx_t));\n  /* Set attribute */\n  tx->attr = (stm_tx_attr_t)0;\n  /* Set status (no need for CAS or atomic op) */\n  tx->status = TX_IDLE;\n  /* Read set */\n  tx->r_set.nb_entries = 0;\n  tx->r_set.size = RW_SET_SIZE;\n  stm_allocate_rs_entries(tx, 0);\n  /* Write set */\n  tx->w_set.nb_entries = 0;\n  tx->w_set.size = RW_SET_SIZE;\n  /* has_writes / nb_acquired are the same field. */\n  tx->w_set.has_writes = 0;\n  /* tx->w_set.nb_acquired = 0; */\n#ifdef USE_BLOOM_FILTER\n  tx->w_set.bloom = 0;\n#endif /* USE_BLOOM_FILTER */\n  stm_allocate_ws_entries(tx, 0);\n  /* Nesting level */\n  tx->nesting = 0;\n  /* Transaction-specific data */\n  memset(tx->data, 0, MAX_SPECIFIC * sizeof(void *));\n#ifdef CONFLICT_TRACKING\n  /* Thread identifier */\n  tx->thread_id = pthread_self();\n#endif /* CONFLICT_TRACKING */\n#if CM == CM_DELAY || CM == CM_MODULAR\n  /* Contented lock */\n  tx->c_lock = NULL;\n#endif /* CM == CM_DELAY || CM == CM_MODULAR */\n#if CM == CM_BACKOFF\n  /* Backoff */\n  tx->backoff = MIN_BACKOFF;\n  tx->seed = 123456789UL;\n#endif /* CM == CM_BACKOFF */\n#if CM == CM_MODULAR\n  tx->visible_reads = 0;\n  tx->timestamp = 0;\n#endif /* CM == CM_MODULAR */\n#if CM == CM_MODULAR || defined(TM_STATISTICS)\n  tx->stat_retries = 0;\n#endif /* CM == CM_MODULAR || defined(TM_STATISTICS) */\n#ifdef TM_STATISTICS\n  /* Statistics */\n  tx->stat_commits = 0;\n  tx->stat_aborts = 0;\n  tx->stat_retries_max = 0;\n#endif /* TM_STATISTICS */\n#ifdef TM_STATISTICS2\n  tx->stat_aborts_1 = 0;\n  tx->stat_aborts_2 = 0;\n  memset(tx->stat_aborts_r, 0, sizeof(unsigned int) * 16);\n# ifdef READ_LOCKED_DATA\n  tx->stat_locked_reads_ok = 0;\n  tx->stat_locked_reads_failed = 0;\n# endif /* READ_LOCKED_DATA */\n#endif /* TM_STATISTICS2 */\n#ifdef IRREVOCABLE_ENABLED\n  tx->irrevocable = 0;\n#endif /* IRREVOCABLE_ENABLED */\n  /* Store as thread-local data */\n  tls_set_tx(tx);\n  stm_quiesce_enter_thread(tx);\n\n  /* Callbacks */\n  if (likely(_tinystm.nb_init_cb != 0)) {\n    unsigned int cb;\n    for (cb = 0; cb < _tinystm.nb_init_cb; cb++)\n      _tinystm.init_cb[cb].f(_tinystm.init_cb[cb].arg);\n  }\n\n  return tx;\n}\n\nstatic INLINE void\nint_stm_exit_thread(stm_tx_t *tx)\n{\n#ifdef EPOCH_GC\n  stm_word_t t;\n#endif /* EPOCH_GC */\n\n  PRINT_DEBUG(\"==> stm_exit_thread(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Avoid finalizing again a thread */\n  if (tx == NULL)\n    return;\n\n  /* Callbacks */\n  if (likely(_tinystm.nb_exit_cb != 0)) {\n    unsigned int cb;\n    for (cb = 0; cb < _tinystm.nb_exit_cb; cb++)\n      _tinystm.exit_cb[cb].f(_tinystm.exit_cb[cb].arg);\n  }\n\n#ifdef TM_STATISTICS\n  /* Display statistics before to lose it */\n  if (getenv(\"TM_STATISTICS\") != NULL) {\n    double avg_aborts = .0;\n    if (tx->stat_commits)\n      avg_aborts = (double)tx->stat_aborts / tx->stat_commits;\n    printf(\"Thread %p | commits:%12u avg_aborts:%12.2f max_retries:%12u\\n\", (void *)pthread_self(), tx->stat_commits, avg_aborts, tx->stat_retries_max);\n  }\n#endif /* TM_STATISTICS */\n\n  stm_quiesce_exit_thread(tx);\n\n#ifdef EPOCH_GC\n  t = GET_CLOCK;\n  gc_free(tx->r_set.entries, t);\n  gc_free(tx->w_set.entries, t);\n  gc_free(tx, t);\n  gc_exit_thread();\n#else /* ! EPOCH_GC */\n  xfree(tx->r_set.entries);\n  xfree(tx->w_set.entries);\n  xfree(tx);\n#endif /* ! EPOCH_GC */\n\n  tls_set_tx(NULL);\n}\n\nstatic INLINE sigjmp_buf *\nint_stm_start(stm_tx_t *tx, stm_tx_attr_t attr)\n{\n  PRINT_DEBUG(\"==> stm_start(%p)\\n\", tx);\n\n  /* TODO Nested transaction attributes are not checked if they are coherent\n   * with parent ones.  */\n\n  /* Increment nesting level */\n  if (tx->nesting++ > 0)\n    return NULL;\n\n  /* Attributes */\n  tx->attr = attr;\n\n  /* Initialize transaction descriptor */\n  int_stm_prepare(tx);\n\n  /* Callbacks */\n  if (likely(_tinystm.nb_start_cb != 0)) {\n    unsigned int cb;\n    for (cb = 0; cb < _tinystm.nb_start_cb; cb++)\n      _tinystm.start_cb[cb].f(_tinystm.start_cb[cb].arg);\n  }\n\n  return &tx->env;\n}\n\nstatic INLINE int\nint_stm_commit(stm_tx_t *tx)\n{\n#if CM == CM_MODULAR\n  stm_word_t t;\n#endif /* CM == CM_MODULAR */\n\n  PRINT_DEBUG(\"==> stm_commit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Decrement nesting level */\n  if (unlikely(--tx->nesting > 0))\n    return 1;\n\n  /* Callbacks */\n  if (unlikely(_tinystm.nb_precommit_cb != 0)) {\n    unsigned int cb;\n    for (cb = 0; cb < _tinystm.nb_precommit_cb; cb++)\n      _tinystm.precommit_cb[cb].f(_tinystm.precommit_cb[cb].arg);\n  }\n\n  assert(IS_ACTIVE(tx->status));\n\n#if CM == CM_MODULAR\n  /* Set status to COMMITTING */\n  t = tx->status;\n  if (GET_STATUS(t) == TX_KILLED || ATOMIC_CAS_FULL(&tx->status, t, t + (TX_COMMITTING - GET_STATUS(t))) == 0) {\n    /* We have been killed */\n    assert(GET_STATUS(tx->status) == TX_KILLED);\n    stm_rollback(tx, STM_ABORT_KILLED);\n    return 0;\n  }\n#endif /* CM == CM_MODULAR */\n\n  /* A read-only transaction can commit immediately */\n  if (unlikely(tx->w_set.nb_entries == 0))\n    goto end;\n\n  /* Update transaction */\n#if DESIGN == WRITE_BACK_ETL\n  stm_wbetl_commit(tx);\n#elif DESIGN == WRITE_BACK_CTL\n  stm_wbctl_commit(tx);\n#elif DESIGN == WRITE_THROUGH\n  stm_wt_commit(tx);\n#elif DESIGN == MODULAR\n  if (tx->attr.id == WRITE_BACK_CTL)\n    stm_wbctl_commit(tx);\n  else if (tx->attr.id == WRITE_THROUGH)\n    stm_wt_commit(tx);\n  else\n    stm_wbetl_commit(tx);\n#endif /* DESIGN == MODULAR */\n\n end:\n#ifdef TM_STATISTICS\n  tx->stat_commits++;\n#endif /* TM_STATISTICS */\n#if CM == CM_MODULAR || defined(TM_STATISTICS)\n  tx->stat_retries = 0;\n#endif /* CM == CM_MODULAR || defined(TM_STATISTICS) */\n\n#if CM == CM_BACKOFF\n  /* Reset backoff */\n  tx->backoff = MIN_BACKOFF;\n#endif /* CM == CM_BACKOFF */\n\n#if CM == CM_MODULAR\n  tx->visible_reads = 0;\n#endif /* CM == CM_MODULAR */\n\n#ifdef IRREVOCABLE_ENABLED\n  if (unlikely(tx->irrevocable)) {\n    ATOMIC_STORE(&_tinystm.irrevocable, 0);\n    if ((tx->irrevocable & 0x08) != 0)\n      stm_quiesce_release(tx);\n    tx->irrevocable = 0;\n  }\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Set status to COMMITTED */\n  SET_STATUS(tx->status, TX_COMMITTED);\n\n  /* Callbacks */\n  if (likely(_tinystm.nb_commit_cb != 0)) {\n    unsigned int cb;\n    for (cb = 0; cb < _tinystm.nb_commit_cb; cb++)\n      _tinystm.commit_cb[cb].f(_tinystm.commit_cb[cb].arg);\n  }\n\n  return 1;\n}\n\nstatic INLINE stm_word_t\nint_stm_load(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n#if DESIGN == WRITE_BACK_ETL\n  return stm_wbetl_read(tx, addr);\n#elif DESIGN == WRITE_BACK_CTL\n  return stm_wbctl_read(tx, addr);\n#elif DESIGN == WRITE_THROUGH\n  return stm_wt_read(tx, addr);\n#elif DESIGN == MODULAR\n  if (tx->attr.id == WRITE_BACK_CTL)\n    return stm_wbctl_read(tx, addr);\n  else if (tx->attr.id == WRITE_THROUGH)\n    return stm_wt_read(tx, addr);\n  else\n    return stm_wbetl_read(tx, addr);\n#endif /* DESIGN == MODULAR */\n}\n\nstatic INLINE void\nint_stm_store(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value)\n{\n  stm_write(tx, addr, value, ~(stm_word_t)0);\n}\n\nstatic INLINE void\nint_stm_store2(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  stm_write(tx, addr, value, mask);\n}\n\nstatic INLINE int\nint_stm_active(stm_tx_t *tx)\n{\n  assert (tx != NULL);\n  return IS_ACTIVE(tx->status);\n}\n\nstatic INLINE int\nint_stm_aborted(stm_tx_t *tx)\n{\n  assert (tx != NULL);\n  return (GET_STATUS(tx->status) == TX_ABORTED);\n}\n\nstatic INLINE int\nint_stm_irrevocable(stm_tx_t *tx)\n{\n  assert (tx != NULL);\n#ifdef IRREVOCABLE_ENABLED\n  return ((tx->irrevocable & 0x07) == 3);\n#else /* ! IRREVOCABLE_ENABLED */\n  return 0;\n#endif /* ! IRREVOCABLE_ENABLED */\n}\n\nstatic INLINE int\nint_stm_killed(stm_tx_t *tx)\n{\n  assert (tx != NULL);\n  return (GET_STATUS(tx->status) == TX_KILLED);\n}\n\nstatic INLINE sigjmp_buf *\nint_stm_get_env(stm_tx_t *tx)\n{\n  assert (tx != NULL);\n  /* Only return environment for top-level transaction */\n  return tx->nesting == 0 ? &tx->env : NULL;\n}\n\nstatic INLINE int\nint_stm_get_stats(stm_tx_t *tx, const char *name, void *val)\n{\n  assert (tx != NULL);\n\n  if (strcmp(\"read_set_size\", name) == 0) {\n    *(unsigned int *)val = tx->r_set.size;\n    return 1;\n  }\n  if (strcmp(\"write_set_size\", name) == 0) {\n    *(unsigned int *)val = tx->w_set.size;\n    return 1;\n  }\n  if (strcmp(\"read_set_nb_entries\", name) == 0) {\n    *(unsigned int *)val = tx->r_set.nb_entries;\n    return 1;\n  }\n  if (strcmp(\"write_set_nb_entries\", name) == 0) {\n    *(unsigned int *)val = tx->w_set.nb_entries;\n    return 1;\n  }\n  if (strcmp(\"read_only\", name) == 0) {\n    *(unsigned int *)val = tx->attr.read_only;\n    return 1;\n  }\n#ifdef TM_STATISTICS\n  if (strcmp(\"nb_commits\", name) == 0) {\n    *(unsigned int *)val = tx->stat_commits;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts;\n    return 1;\n  }\n  if (strcmp(\"avg_aborts\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts / tx->stat_commits;\n    return 1;\n  }\n  if (strcmp(\"max_retries\", name) == 0) {\n    *(unsigned int *)val = tx->stat_retries_max;\n    return 1;\n  }\n#endif /* TM_STATISTICS */\n#ifdef TM_STATISTICS2\n  if (strcmp(\"nb_aborts_1\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_1;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_2\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_2;\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_locked_read\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_WR_CONFLICT >> 8];\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_locked_write\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_WW_CONFLICT >> 8];\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_validate_read\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_VAL_READ >> 8];\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_validate_write\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_VAL_WRITE >> 8];\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_validate_commit\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_VALIDATE >> 8];\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_killed\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_KILLED >> 8];\n    return 1;\n  }\n  if (strcmp(\"nb_aborts_invalid_memory\", name) == 0) {\n    *(unsigned int *)val = tx->stat_aborts_r[STM_ABORT_SIGNAL >> 8];\n    return 1;\n  }\n# ifdef READ_LOCKED_DATA\n  if (strcmp(\"locked_reads_ok\", name) == 0) {\n    *(unsigned int *)val = tx->stat_locked_reads_ok;\n    return 1;\n  }\n  if (strcmp(\"locked_reads_failed\", name) == 0) {\n    *(unsigned int *)val = tx->stat_locked_reads_failed;\n    return 1;\n  }\n# endif /* READ_LOCKED_DATA */\n#endif /* TM_STATISTICS2 */\n  return 0;\n}\n\nstatic INLINE void\nint_stm_set_specific(stm_tx_t *tx, int key, void *data)\n{\n  assert (tx != NULL && key >= 0 && key < _tinystm.nb_specific);\n  ATOMIC_STORE(&tx->data[key], data);\n}\n\nstatic INLINE void *\nint_stm_get_specific(stm_tx_t *tx, int key)\n{\n  assert (tx != NULL && key >= 0 && key < _tinystm.nb_specific);\n  return (void *)ATOMIC_LOAD(&tx->data[key]);\n}\n\n#endif /* _STM_INTERNAL_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/src/stm_wbctl.h",
    "content": "/*\n * File:\n *   stm_wbctl.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM internal functions for write-back CTL.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _STM_WBCTL_H_\n#define _STM_WBCTL_H_\n\nstatic INLINE int\nstm_wbctl_validate(stm_tx_t *tx)\n{\n  r_entry_t *r;\n  int i;\n  stm_word_t l;\n\n  PRINT_DEBUG(\"==> stm_wbctl_validate(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Validate reads */\n  r = tx->r_set.entries;\n  for (i = tx->r_set.nb_entries; i > 0; i--, r++) {\n    /* Read lock */\n    l = ATOMIC_LOAD(r->lock);\n    /* Unlocked and still the same version? */\n    if (LOCK_GET_OWNED(l)) {\n      /* Do we own the lock? */\n      w_entry_t *w = (w_entry_t *)LOCK_GET_ADDR(l);\n      /* Simply check if address falls inside our write set (avoids non-faulting load) */\n      if (!(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries))\n      {\n        /* Locked by another transaction: cannot validate */\n#ifdef CONFLICT_TRACKING\n        if (_tinystm.conflict_cb != NULL) {\n# ifdef UNIT_TX\n          if (l != LOCK_UNIT) {\n# endif /* UNIT_TX */\n            /* Call conflict callback */\n            stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n            _tinystm.conflict_cb(tx, other);\n# ifdef UNIT_TX\n          }\n# endif /* UNIT_TX */\n        }\n#endif /* CONFLICT_TRACKING */\n        return 0;\n      }\n      /* We own the lock: OK */\n      if (w->version != r->version) {\n        /* Other version: cannot validate */\n        return 0;\n      }\n    } else {\n      if (LOCK_GET_TIMESTAMP(l) != r->version) {\n        /* Other version: cannot validate */\n        return 0;\n      }\n      /* Same version: OK */\n    }\n  }\n  return 1;\n}\n\n/*\n * Extend snapshot range.\n */\nstatic INLINE int\nstm_wbctl_extend(stm_tx_t *tx)\n{\n  stm_word_t now;\n\n  PRINT_DEBUG(\"==> stm_wbctl_extend(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n#ifdef UNIT_TX\n  /* Extension is disabled */\n  if (tx->attr.no_extend)\n    return 0;\n#endif /* UNIT_TX */\n\n  /* Get current time */\n  now = GET_CLOCK;\n  /* No need to check clock overflow here. The clock can exceed up to MAX_THREADS and it will be reset when the quiescence is reached. */\n\n  /* Try to validate read set */\n  if (stm_wbctl_validate(tx)) {\n    /* It works: we can extend until now */\n    tx->end = now;\n    return 1;\n  }\n  return 0;\n}\n\nstatic INLINE void\nstm_wbctl_rollback(stm_tx_t *tx)\n{\n  w_entry_t *w;\n\n  PRINT_DEBUG(\"==> stm_wbctl_rollback(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  assert(IS_ACTIVE(tx->status));\n\n  if (tx->w_set.nb_acquired > 0) {\n    w = tx->w_set.entries + tx->w_set.nb_entries;\n    do {\n      w--;\n      if (!w->no_drop) {\n        if (--tx->w_set.nb_acquired == 0) {\n          /* Make sure that all lock releases become visible to other threads */\n          ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(w->version));\n        } else {\n          ATOMIC_STORE(w->lock, LOCK_SET_TIMESTAMP(w->version));\n        }\n      }\n    } while (tx->w_set.nb_acquired > 0);\n  }\n}\n\nstatic INLINE stm_word_t\nstm_wbctl_read(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, value, version;\n  r_entry_t *r;\n  w_entry_t *written = NULL;\n\n  PRINT_DEBUG2(\"==> stm_wbctl_read(t=%p[%lu-%lu],a=%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\n  assert(IS_ACTIVE(tx->status));\n\n  /* Did we previously write the same address? */\n  written = stm_has_written(tx, addr);\n  if (written != NULL) {\n    /* Yes: get value from write set if possible */\n    if (written->mask == ~(stm_word_t)0) {\n      value = written->value;\n      /* No need to add to read set */\n      return value;\n    }\n  }\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Note: we could check for duplicate reads and get value from read set */\n\n  /* Read lock, value, lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_WRITE(l)) {\n    /* Locked */\n    /* Do we own the lock? */\n    /* Spin while locked (should not last long) */\n    goto restart;\n  } else {\n    /* Not locked */\n    value = ATOMIC_LOAD_ACQ(addr);\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (l != l2) {\n      l = l2;\n      goto restart_no_load;\n    }\n#ifdef IRREVOCABLE_ENABLED\n    /* In irrevocable mode, no need check timestamp nor add entry to read set */\n    if (tx->irrevocable)\n      goto return_value;\n#endif /* IRREVOCABLE_ENABLED */\n    /* Check timestamp */\n    version = LOCK_GET_TIMESTAMP(l);\n    /* Valid version? */\n    if (version > tx->end) {\n      /* No: try to extend first (except for read-only transactions: no read set) */\n      if (tx->attr.read_only || !stm_wbctl_extend(tx)) {\n        /* Not much we can do: abort */\n        stm_rollback(tx, STM_ABORT_VAL_READ);\n        return 0;\n      }\n      /* Verify that version has not been overwritten (read value has not\n       * yet been added to read set and may have not been checked during\n       * extend) */\n      l = ATOMIC_LOAD_ACQ(lock);\n      if (l != l2) {\n        l = l2;\n        goto restart_no_load;\n      }\n      /* Worked: we now have a good version (version <= tx->end) */\n    }\n  }\n  /* We have a good version: add to read set (update transactions) and return value */\n\n  /* Did we previously write the same address? */\n  if (written != NULL) {\n    value = (value & ~written->mask) | (written->value & written->mask);\n    /* Must still add to read set */\n  }\n#ifdef READ_LOCKED_DATA\n add_to_read_set:\n#endif /* READ_LOCKED_DATA */\n  if (!tx->attr.read_only) {\n#ifdef NO_DUPLICATES_IN_RW_SETS\n    if (stm_has_read(tx, lock) != NULL)\n      goto return_value;\n#endif /* NO_DUPLICATES_IN_RW_SETS */\n    /* Add address and version to read set */\n    if (tx->r_set.nb_entries == tx->r_set.size)\n      stm_allocate_rs_entries(tx, 1);\n    r = &tx->r_set.entries[tx->r_set.nb_entries++];\n    r->version = version;\n    r->lock = lock;\n  }\n return_value:\n  return value;\n}\n\nstatic INLINE w_entry_t *\nstm_wbctl_write(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, version;\n  w_entry_t *w;\n\n  PRINT_DEBUG2(\"==> stm_wbctl_write(t=%p[%lu-%lu],a=%p,d=%p-%lu,m=0x%lx)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Try to acquire lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked */\n    /* Spin while locked (should not last long) */\n    goto restart;\n  }\n  /* Not locked */\n  w = stm_has_written(tx, addr);\n  if (w != NULL) {\n    w->value = (w->value & ~mask) | (value & mask);\n    w->mask |= mask;\n    return w;\n  }\n  /* Handle write after reads (before CAS) */\n  version = LOCK_GET_TIMESTAMP(l);\n#ifdef IRREVOCABLE_ENABLED\n  /* In irrevocable mode, no need to revalidate */\n  if (tx->irrevocable)\n    goto acquire_no_check;\n#endif /* IRREVOCABLE_ENABLED */\n acquire:\n  if (version > tx->end) {\n    /* We might have read an older version previously */\n#ifdef UNIT_TX\n    if (tx->attr.no_extend) {\n      stm_rollback(tx, STM_ABORT_VAL_WRITE);\n      return NULL;\n    }\n#endif /* UNIT_TX */\n    if (stm_has_read(tx, lock) != NULL) {\n      /* Read version must be older (otherwise, tx->end >= version) */\n      /* Not much we can do: abort */\n      stm_rollback(tx, STM_ABORT_VAL_WRITE);\n      return NULL;\n    }\n  }\n  /* Acquire lock (ETL) */\n#ifdef IRREVOCABLE_ENABLED\n acquire_no_check:\n#endif /* IRREVOCABLE_ENABLED */\n  /* We own the lock here (ETL) */\ndo_write:\n  /* Add address to write set */\n  if (tx->w_set.nb_entries == tx->w_set.size)\n    stm_allocate_ws_entries(tx, 1);\n  w = &tx->w_set.entries[tx->w_set.nb_entries++];\n  w->addr = addr;\n  w->mask = mask;\n  w->lock = lock;\n  if (mask == 0) {\n    /* Do not write anything */\n#ifndef NDEBUG\n    w->value = 0;\n#endif /* ! NDEBUG */\n  } else {\n    /* Remember new value */\n    w->value = value;\n  }\n# ifndef NDEBUG\n  w->version = version;\n# endif /* !NDEBUG */\n  w->no_drop = 1;\n# ifdef USE_BLOOM_FILTER\n  tx->w_set.bloom |= FILTER_BITS(addr) ;\n# endif /* USE_BLOOM_FILTER */\n\n  return w;\n}\n\nstatic INLINE stm_word_t\nstm_wbctl_RaR(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* Possible optimization: avoid adding to read set. */\n  return stm_wbctl_read(tx, addr);\n}\n\nstatic INLINE stm_word_t\nstm_wbctl_RaW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* Cannot be much better than regular due to mask == 0 case. */\n  return stm_wbctl_read(tx, addr);\n}\n\nstatic INLINE stm_word_t\nstm_wbctl_RfW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* We need to return the value here, so write with mask=0 is not enough. */\n  return stm_wbctl_read(tx, addr);\n}\n\nstatic INLINE void\nstm_wbctl_WaR(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  /* Probably no optimization can be done here. */\n  stm_wbctl_write(tx, addr, value, mask);\n}\n\nstatic INLINE void\nstm_wbctl_WaW(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  w_entry_t *w;\n  /* Get the write set entry. */\n  w = stm_has_written(tx, addr);\n  assert(w != NULL);\n  /* Update directly into the write set. */\n  w->value = (w->value & ~mask) | (value & mask);\n  w->mask |= mask;\n}\n\nstatic INLINE int\nstm_wbctl_commit(stm_tx_t *tx)\n{\n  w_entry_t *w;\n  stm_word_t t;\n  int i;\n  stm_word_t l, value;\n\n  PRINT_DEBUG(\"==> stm_wbctl_commit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Acquire locks (in reverse order) */\n  w = tx->w_set.entries + tx->w_set.nb_entries;\n  do {\n    w--;\n    /* Try to acquire lock */\n restart:\n    l = ATOMIC_LOAD(w->lock);\n    if (LOCK_GET_OWNED(l)) {\n      /* Do we already own the lock? */\n      if (tx->w_set.entries <= (w_entry_t *)LOCK_GET_ADDR(l) && (w_entry_t *)LOCK_GET_ADDR(l) < tx->w_set.entries + tx->w_set.nb_entries) {\n        /* Yes: ignore */\n        continue;\n      }\n      /* Conflict: CM kicks in */\n# if CM == CM_DELAY\n      tx->c_lock = w->lock;\n# endif /* CM == CM_DELAY */\n\n#ifdef IRREVOCABLE_ENABLED\n      if (tx->irrevocable) {\n# ifdef IRREVOCABLE_IMPROVED\n        if (ATOMIC_LOAD(&_tinystm.irrevocable) == 1)\n          ATOMIC_STORE(&_tinystm.irrevocable, 2);\n# endif /* IRREVOCABLE_IMPROVED */\n        /* Spin while locked */\n        goto restart;\n      }\n#endif /* IRREVOCABLE_ENABLED */\n\n      /* Abort self */\n      stm_rollback(tx, STM_ABORT_WW_CONFLICT);\n      return 0;\n    }\n    if (ATOMIC_CAS_FULL(w->lock, l, LOCK_SET_ADDR_WRITE((stm_word_t)w)) == 0)\n      goto restart;\n    /* We own the lock here */\n    w->no_drop = 0;\n    /* Store version for validation of read set */\n    w->version = LOCK_GET_TIMESTAMP(l);\n    tx->w_set.nb_acquired++;\n  } while (w > tx->w_set.entries);\n\n#ifdef IRREVOCABLE_ENABLED\n  /* Verify if there is an irrevocable transaction once all locks have been acquired */\n# ifdef IRREVOCABLE_IMPROVED\n  /* FIXME: it is bogus. the status should be changed to idle otherwise stm_quiesce will not progress */\n  if (unlikely(!tx->irrevocable)) {\n    do {\n      t = ATOMIC_LOAD(&_tinystm.irrevocable);\n      /* If the irrevocable transaction have encountered an acquired lock, abort */\n      if (t == 2) {\n        stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n        return 0;\n      }\n    } while (t);\n  }\n# else /* ! IRREVOCABLE_IMPROVED */\n  if (!tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable)) {\n    stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n    return 0;\n  }\n# endif /* ! IRREVOCABLE_IMPROVED */\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Get commit timestamp (may exceed VERSION_MAX by up to MAX_THREADS) */\n  t = FETCH_INC_CLOCK + 1;\n\n#ifdef IRREVOCABLE_ENABLED\n  if (unlikely(tx->irrevocable))\n    goto release_locks;\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Try to validate (only if a concurrent transaction has committed since tx->start) */\n  if (unlikely(tx->start != t - 1 && !stm_wbctl_validate(tx))) {\n    /* Cannot commit */\n    stm_rollback(tx, STM_ABORT_VALIDATE);\n    return 0;\n  }\n\n#ifdef IRREVOCABLE_ENABLED\n  release_locks:\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Install new versions, drop locks and set new timestamp */\n  w = tx->w_set.entries;\n  for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n    if (w->mask == ~(stm_word_t)0) {\n      ATOMIC_STORE(w->addr, w->value);\n    } else if (w->mask != 0) {\n      value = (ATOMIC_LOAD(w->addr) & ~w->mask) | (w->value & w->mask);\n      ATOMIC_STORE(w->addr, value);\n    }\n    /* Only drop lock for last covered address in write set (cannot be \"no drop\") */\n    if (!w->no_drop)\n      ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(t));\n  }\n\n end:\n  return 1;\n}\n\n#endif /* _STM_WBCTL_H_ */\n"
  },
  {
    "path": "stms/tinystm/src/stm_wbetl.h",
    "content": "/*\n * File:\n *   stm_wbetl.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM internal functions for Write-back ETL.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _STM_WBETL_H_\n#define _STM_WBETL_H_\n\n#include \"stm_internal.h\"\n#include \"atomic.h\"\n\n#if CM == CM_MODULAR\n/* Function declaration */\nstatic NOINLINE void stm_drop(stm_tx_t *tx);\nstatic NOINLINE int stm_kill(stm_tx_t *tx, stm_tx_t *other, stm_word_t status);\n#endif /* CM == CM_MODULAR */\n\nstatic INLINE int\nstm_wbetl_validate(stm_tx_t *tx)\n{\n  r_entry_t *r;\n  int i;\n  stm_word_t l;\n\n  PRINT_DEBUG(\"==> stm_wbetl_validate(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Validate reads */\n  r = tx->r_set.entries;\n  for (i = tx->r_set.nb_entries; i > 0; i--, r++) {\n    /* Read lock */\n    l = ATOMIC_LOAD(r->lock);\n    /* Unlocked and still the same version? */\n    if (LOCK_GET_OWNED(l)) {\n      /* Do we own the lock? */\n      w_entry_t *w = (w_entry_t *)LOCK_GET_ADDR(l);\n      /* Simply check if address falls inside our write set (avoids non-faulting load) */\n      if (!(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries))\n      {\n        /* Locked by another transaction: cannot validate */\n#ifdef CONFLICT_TRACKING\n        if (_tinystm.conflict_cb != NULL) {\n# ifdef UNIT_TX\n          if (l != LOCK_UNIT) {\n# endif /* UNIT_TX */\n            /* Call conflict callback */\n            stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n            _tinystm.conflict_cb(tx, other);\n# ifdef UNIT_TX\n          }\n# endif /* UNIT_TX */\n        }\n#endif /* CONFLICT_TRACKING */\n        return 0;\n      }\n      /* We own the lock: OK */\n    } else {\n      if (LOCK_GET_TIMESTAMP(l) != r->version) {\n        /* Other version: cannot validate */\n        return 0;\n      }\n      /* Same version: OK */\n    }\n  }\n  return 1;\n}\n\n/*\n * Extend snapshot range.\n */\nstatic INLINE int\nstm_wbetl_extend(stm_tx_t *tx)\n{\n  stm_word_t now;\n\n  PRINT_DEBUG(\"==> stm_wbetl_extend(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n#ifdef UNIT_TX\n  /* Extension is disabled */\n  if (tx->attr.no_extend)\n    return 0;\n#endif /* UNIT_TX */\n\n  /* Get current time */\n  now = GET_CLOCK;\n  /* No need to check clock overflow here. The clock can exceed up to MAX_THREADS and it will be reset when the quiescence is reached. */\n\n  /* Try to validate read set */\n  if (stm_wbetl_validate(tx)) {\n    /* It works: we can extend until now */\n    tx->end = now;\n    return 1;\n  }\n  return 0;\n}\n\nstatic INLINE void\nstm_wbetl_rollback(stm_tx_t *tx)\n{\n  w_entry_t *w;\n  int i;\n#if CM == CM_MODULAR\n  stm_word_t t;\n#endif /* CM == CM_MODULAR */\n#if CM == CM_BACKOFF\n  unsigned long wait;\n  volatile int j;\n#endif /* CM == CM_BACKOFF */\n\n  PRINT_DEBUG(\"==> stm_wbetl_rollback(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  assert(IS_ACTIVE(tx->status));\n#if CM == CM_MODULAR\n  /* Set status to ABORTING */\n  t = tx->status;\n  if (GET_STATUS(t) == TX_KILLED || (GET_STATUS(t) == TX_ACTIVE && ATOMIC_CAS_FULL(&tx->status, t, t + (TX_ABORTING - TX_ACTIVE)) == 0)) {\n    /* We have been killed */\n    assert(GET_STATUS(tx->status) == TX_KILLED);\n    /* Release locks */\n    stm_drop(tx);\n    return;\n  }\n#endif /* CM == CM_MODULAR */\n\n  /* Drop locks */\n  i = tx->w_set.nb_entries;\n  if (i > 0) {\n    w = tx->w_set.entries;\n    for (; i > 0; i--, w++) {\n      if (w->next == NULL) {\n        /* Only drop lock for last covered address in write set */\n        ATOMIC_STORE(w->lock, LOCK_SET_TIMESTAMP(w->version));\n      }\n    }\n    /* Make sure that all lock releases become visible */\n    ATOMIC_MB_WRITE;\n  }\n}\n\n/*\n * Load a word-sized value (invisible read).\n */\nstatic INLINE stm_word_t\nstm_wbetl_read_invisible(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, value, version;\n  r_entry_t *r;\n  w_entry_t *w;\n#if CM == CM_MODULAR\n  stm_word_t t;\n  int decision;\n#endif /* CM == CM_MODULAR */\n\n  PRINT_DEBUG2(\"==> stm_wbetl_read_invisible(t=%p[%lu-%lu],a=%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\n#if CM != CM_MODULAR\n  assert(IS_ACTIVE(tx->status));\n#endif /* CM != CM_MODULAR */\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Note: we could check for duplicate reads and get value from read set */\n\n  /* Read lock, value, lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (unlikely(LOCK_GET_WRITE(l))) {\n    /* Locked */\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (likely(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries)) {\n      /* Yes: did we previously write the same address? */\n      while (1) {\n        if (addr == w->addr) {\n          /* Yes: get value from write set (or from memory if mask was empty) */\n          value = (w->mask == 0 ? ATOMIC_LOAD(addr) : w->value);\n          break;\n        }\n        if (w->next == NULL) {\n          /* No: get value from memory */\n          value = ATOMIC_LOAD(addr);\n# if CM == CM_MODULAR\n          if (GET_STATUS(tx->status) == TX_KILLED) {\n            stm_rollback(tx, STM_ABORT_KILLED);\n            return 0;\n          }\n# endif /* CM == CM_MODULAR */\n          break;\n        }\n        w = w->next;\n      }\n      /* No need to add to read set (will remain valid) */\n      return value;\n    }\n\n# ifdef UNIT_TX\n    if (l == LOCK_UNIT) {\n      /* Data modified by a unit store: should not last long => retry */\n      goto restart;\n    }\n# endif /* UNIT_TX */\n\n    /* Conflict: CM kicks in (we could also check for duplicate reads and get value from read set) */\n# if defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED)\n    if (tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable) == 1)\n      ATOMIC_STORE(&_tinystm.irrevocable, 2);\n# endif /* defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED) */\n# if CM != CM_MODULAR && defined(IRREVOCABLE_ENABLED)\n    if (unlikely(tx->irrevocable)) {\n      /* Spin while locked */\n      goto restart;\n    }\n# endif /* CM != CM_MODULAR && defined(IRREVOCABLE_ENABLED) */\n# if CM == CM_MODULAR\n    t = w->tx->status;\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (l != l2) {\n      l = l2;\n      goto restart_no_load;\n    }\n    if (t != w->tx->status) {\n      /* Transaction status has changed: restart the whole procedure */\n      goto restart;\n    }\n#  ifdef READ_LOCKED_DATA\n#   ifdef IRREVOCABLE_ENABLED\n    if (IS_ACTIVE(t) && !tx->irrevocable)\n#   else /* ! IRREVOCABLE_ENABLED */\n    if (GET_STATUS(t) == TX_ACTIVE)\n#   endif /* ! IRREVOCABLE_ENABLED */\n    {\n      /* Read old version */\n      version = ATOMIC_LOAD(&w->version);\n      /* Read data */\n      value = ATOMIC_LOAD(addr);\n      /* Check that data has not been written */\n      if (t != w->tx->status) {\n        /* Data concurrently modified: a new version might be available => retry */\n        goto restart;\n      }\n      if (version >= tx->start && (version <= tx->end || (!tx->attr.read_only && stm_wbetl_extend(tx)))) {\n      /* Success */\n#  ifdef TM_STATISTICS2\n        tx->stat_locked_reads_ok++;\n#  endif /* TM_STATISTICS2 */\n        goto add_to_read_set;\n      }\n      /* Invalid version: not much we can do => fail */\n#  ifdef TM_STATISTICS2\n      tx->stat_locked_reads_failed++;\n#  endif /* TM_STATISTICS2 */\n    }\n#  endif /* READ_LOCKED_DATA */\n    if (GET_STATUS(t) == TX_KILLED) {\n      /* We can safely steal lock */\n      decision = KILL_OTHER;\n    } else {\n      decision =\n#  ifdef IRREVOCABLE_ENABLED\n        GET_STATUS(tx->status) == TX_IRREVOCABLE ? KILL_OTHER :\n        GET_STATUS(t) == TX_IRREVOCABLE ? KILL_SELF :\n#  endif /* IRREVOCABLE_ENABLED */\n        GET_STATUS(tx->status) == TX_KILLED ? KILL_SELF :\n        (_tinystm.contention_manager != NULL ? _tinystm.contention_manager(tx, w->tx, WR_CONFLICT) : KILL_SELF);\n      if (decision == KILL_OTHER) {\n        /* Kill other */\n        if (!stm_kill(tx, w->tx, t)) {\n          /* Transaction may have committed or aborted: retry */\n          goto restart;\n        }\n      }\n    }\n    if (decision == KILL_OTHER) {\n      /* Steal lock */\n      l2 = LOCK_SET_TIMESTAMP(w->version);\n      if (ATOMIC_CAS_FULL(lock, l, l2) == 0)\n        goto restart;\n      l = l2;\n      goto restart_no_load;\n    }\n    /* Kill self */\n    if ((decision & DELAY_RESTART) != 0)\n      tx->c_lock = lock;\n# elif CM == CM_DELAY\n    tx->c_lock = lock;\n# endif /* CM == CM_DELAY */\n    /* Abort */\n# ifdef CONFLICT_TRACKING\n    if (_tinystm.conflict_cb != NULL) {\n#  ifdef UNIT_TX\n      if (l != LOCK_UNIT) {\n#  endif /* UNIT_TX */\n        /* Call conflict callback */\n        stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n        _tinystm.conflict_cb(tx, other);\n#  ifdef UNIT_TX\n      }\n#  endif /* UNIT_TX */\n    }\n# endif /* CONFLICT_TRACKING */\n    stm_rollback(tx, STM_ABORT_RW_CONFLICT);\n    return 0;\n  } else {\n    /* Not locked */\n    value = ATOMIC_LOAD_ACQ(addr);\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (unlikely(l != l2)) {\n      l = l2;\n      goto restart_no_load;\n    }\n#ifdef IRREVOCABLE_ENABLED\n    /* In irrevocable mode, no need check timestamp nor add entry to read set */\n    if (unlikely(tx->irrevocable))\n      goto return_value;\n#endif /* IRREVOCABLE_ENABLED */\n    /* Check timestamp */\n#if CM == CM_MODULAR\n    if (LOCK_GET_READ(l))\n      version = ((w_entry_t *)LOCK_GET_ADDR(l))->version;\n    else\n      version = LOCK_GET_TIMESTAMP(l);\n#else /* CM != CM_MODULAR */\n    version = LOCK_GET_TIMESTAMP(l);\n#endif /* CM != CM_MODULAR */\n    /* Valid version? */\n    if (unlikely(version > tx->end)) {\n      /* No: try to extend first (except for read-only transactions: no read set) */\n      if (tx->attr.read_only || !stm_wbetl_extend(tx)) {\n        /* Not much we can do: abort */\n#if CM == CM_MODULAR\n        /* Abort caused by invisible reads */\n        tx->visible_reads++;\n#endif /* CM == CM_MODULAR */\n        stm_rollback(tx, STM_ABORT_VAL_READ);\n        return 0;\n      }\n      /* Verify that version has not been overwritten (read value has not\n       * yet been added to read set and may have not been checked during\n       * extend) */\n      l2 = ATOMIC_LOAD_ACQ(lock);\n      if (l != l2) {\n        l = l2;\n        goto restart_no_load;\n      }\n      /* Worked: we now have a good version (version <= tx->end) */\n    }\n#if CM == CM_MODULAR\n    /* Check if killed (necessary to avoid possible race on read-after-write) */\n    if (GET_STATUS(tx->status) == TX_KILLED) {\n      stm_rollback(tx, STM_ABORT_KILLED);\n      return 0;\n    }\n#endif /* CM == CM_MODULAR */\n  }\n  /* We have a good version: add to read set (update transactions) and return value */\n\n#ifdef READ_LOCKED_DATA\n add_to_read_set:\n#endif /* READ_LOCKED_DATA */\n  if (!tx->attr.read_only) {\n#ifdef NO_DUPLICATES_IN_RW_SETS\n    if (stm_has_read(tx, lock) != NULL)\n      goto return_value;\n#endif /* NO_DUPLICATES_IN_RW_SETS */\n    /* Add address and version to read set */\n    if (tx->r_set.nb_entries == tx->r_set.size)\n      stm_allocate_rs_entries(tx, 1);\n    r = &tx->r_set.entries[tx->r_set.nb_entries++];\n    r->version = version;\n    r->lock = lock;\n  }\n return_value:\n  return value;\n}\n\n#if CM == CM_MODULAR\n/*\n * Load a word-sized value (visible read).\n */\nstatic INLINE stm_word_t\nstm_wbetl_read_visible(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, t, value, version;\n  w_entry_t *w;\n  int decision;\n\n  PRINT_DEBUG2(\"==> stm_wbetl_read_visible(t=%p[%lu-%lu],a=%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\n  if (GET_STATUS(tx->status) == TX_KILLED) {\n    stm_rollback(tx, STM_ABORT_KILLED);\n    return 0;\n  }\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Try to acquire lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked */\n#ifdef UNIT_TX\n    if (l == LOCK_UNIT) {\n      /* Data modified by a unit store: should not last long => retry */\n      goto restart;\n    }\n#endif /* UNIT_TX */\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries) {\n      /* Yes: is it only read-locked? */\n      if (!LOCK_GET_WRITE(l)) {\n        /* Yes: get value from memory */\n        value = ATOMIC_LOAD(addr);\n      } else {\n        /* No: did we previously write the same address? */\n        while (1) {\n          if (addr == w->addr) {\n            /* Yes: get value from write set (or from memory if mask was empty) */\n            value = (w->mask == 0 ? ATOMIC_LOAD(addr) : w->value);\n            break;\n          }\n          if (w->next == NULL) {\n            /* No: get value from memory */\n            value = ATOMIC_LOAD(addr);\n            break;\n          }\n          w = w->next;\n        }\n      }\n      if (GET_STATUS(tx->status) == TX_KILLED) {\n        stm_rollback(tx, STM_ABORT_KILLED);\n        return 0;\n      }\n      /* No need to add to read set (will remain valid) */\n      return value;\n    }\n    /* Conflict: CM kicks in */\n# if defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED)\n    if (tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable) == 1)\n      ATOMIC_STORE(&_tinystm.irrevocable, 2);\n# endif /* defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED) */\n    t = w->tx->status;\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (l != l2) {\n      l = l2;\n      goto restart_no_load;\n    }\n    if (t != w->tx->status) {\n      /* Transaction status has changed: restart the whole procedure */\n      goto restart;\n    }\n    if (GET_STATUS(t) == TX_KILLED) {\n      /* We can safely steal lock */\n      decision = KILL_OTHER;\n    } else {\n      decision =\n# ifdef IRREVOCABLE_ENABLED\n        GET_STATUS(tx->status) == TX_IRREVOCABLE ? KILL_OTHER :\n        GET_STATUS(t) == TX_IRREVOCABLE ? KILL_SELF :\n# endif /* IRREVOCABLE_ENABLED */\n        GET_STATUS(tx->status) == TX_KILLED ? KILL_SELF :\n        (_tinystm.contention_manager != NULL ? _tinystm.contention_manager(tx, w->tx, (LOCK_GET_WRITE(l) ? WR_CONFLICT : RR_CONFLICT)) : KILL_SELF);\n      if (decision == KILL_OTHER) {\n        /* Kill other */\n        if (!stm_kill(tx, w->tx, t)) {\n          /* Transaction may have committed or aborted: retry */\n          goto restart;\n        }\n      }\n    }\n    if (decision == KILL_OTHER) {\n      version = w->version;\n      goto acquire;\n    }\n    /* Kill self */\n    if ((decision & DELAY_RESTART) != 0)\n      tx->c_lock = lock;\n    /* Abort */\n# ifdef CONFLICT_TRACKING\n    if (_tinystm.conflict_cb != NULL) {\n#  ifdef UNIT_TX\n      if (l != LOCK_UNIT) {\n#  endif /* UNIT_TX */\n        /* Call conflict callback */\n        stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n        _tinystm.conflict_cb(tx, other);\n#  ifdef UNIT_TX\n      }\n#  endif /* UNIT_TX */\n    }\n# endif /* CONFLICT_TRACKING */\n    stm_rollback(tx, (LOCK_GET_WRITE(l) ? STM_ABORT_WR_CONFLICT : STM_ABORT_RR_CONFLICT));\n    return 0;\n  }\n  /* Not locked */\n  version = LOCK_GET_TIMESTAMP(l);\n acquire:\n  /* Acquire lock (ETL) */\n  if (tx->w_set.nb_entries == tx->w_set.size)\n    stm_rollback(tx, STM_ABORT_EXTEND_WS);\n  w = &tx->w_set.entries[tx->w_set.nb_entries];\n  w->version = version;\n  value = ATOMIC_LOAD(addr);\n  if (ATOMIC_CAS_FULL(lock, l, LOCK_SET_ADDR_READ((stm_word_t)w)) == 0)\n    goto restart;\n  /* Add entry to write set */\n  w->addr = addr;\n  w->mask = 0;\n  w->lock = lock;\n  w->value = value;\n  w->next = NULL;\n  tx->w_set.nb_entries++;\n  return value;\n}\n#endif /* CM == CM_MODULAR */\n\nstatic INLINE stm_word_t\nstm_wbetl_read(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n#if CM == CM_MODULAR\n  if (unlikely((tx->attr.visible_reads))) {\n    /* Use visible read */\n    return stm_wbetl_read_visible(tx, addr);\n  }\n#endif /* CM == CM_MODULAR */\n  return stm_wbetl_read_invisible(tx, addr);\n}\n\nstatic INLINE w_entry_t *\nstm_wbetl_write(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, version;\n  w_entry_t *w;\n  w_entry_t *prev = NULL;\n#if CM == CM_MODULAR\n  int decision;\n  stm_word_t l2, t;\n#endif /* CM == CM_MODULAR */\n\n  PRINT_DEBUG2(\"==> stm_wbetl_write(t=%p[%lu-%lu],a=%p,d=%p-%lu,m=0x%lx)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Try to acquire lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (unlikely(LOCK_GET_OWNED(l))) {\n    /* Locked */\n\n#ifdef UNIT_TX\n    if (l == LOCK_UNIT) {\n      /* Data modified by a unit store: should not last long => retry */\n      goto restart;\n    }\n#endif /* UNIT_TX */\n\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (likely(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries)) {\n      /* Yes */\n#if CM == CM_MODULAR\n      /* If read-locked: upgrade lock */\n      if (!LOCK_GET_WRITE(l)) {\n        if (ATOMIC_CAS_FULL(lock, l, LOCK_UPGRADE(l)) == 0) {\n          /* Lock must have been stolen: abort */\n          stm_rollback(tx, STM_ABORT_KILLED);\n          return NULL;\n        }\n        tx->w_set.has_writes++;\n      }\n#endif /* CM == CM_MODULAR */\n      if (mask == 0) {\n        /* No need to insert new entry or modify existing one */\n        return w;\n      }\n      prev = w;\n      /* Did we previously write the same address? */\n      while (1) {\n        if (addr == prev->addr) {\n          /* No need to add to write set */\n          if (mask != ~(stm_word_t)0) {\n            if (prev->mask == 0)\n              prev->value = ATOMIC_LOAD(addr);\n            value = (prev->value & ~mask) | (value & mask);\n          }\n          prev->value = value;\n          prev->mask |= mask;\n          return prev;\n        }\n        if (prev->next == NULL) {\n          /* Remember last entry in linked list (for adding new entry) */\n          break;\n        }\n        prev = prev->next;\n      }\n      /* Get version from previous write set entry (all entries in linked list have same version) */\n      version = prev->version;\n      /* Must add to write set */\n      if (tx->w_set.nb_entries == tx->w_set.size)\n        stm_rollback(tx, STM_ABORT_EXTEND_WS);\n      w = &tx->w_set.entries[tx->w_set.nb_entries];\n#if CM == CM_MODULAR\n      w->version = version;\n#endif /* CM == CM_MODULAR */\n      goto do_write;\n    }\n    /* Conflict: CM kicks in */\n#if defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED)\n    if (tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable) == 1)\n      ATOMIC_STORE(&_tinystm.irrevocable, 2);\n#endif /* defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED) */\n#if CM != CM_MODULAR && defined(IRREVOCABLE_ENABLED)\n    if (tx->irrevocable) {\n      /* Spin while locked */\n      goto restart;\n    }\n#endif /* CM != CM_MODULAR && defined(IRREVOCABLE_ENABLED) */\n#if CM == CM_MODULAR\n    t = w->tx->status;\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (l != l2) {\n      l = l2;\n      goto restart_no_load;\n    }\n    if (t != w->tx->status) {\n      /* Transaction status has changed: restart the whole procedure */\n      goto restart;\n    }\n    if (GET_STATUS(t) == TX_KILLED) {\n      /* We can safely steal lock */\n      decision = KILL_OTHER;\n    } else {\n      decision =\n# ifdef IRREVOCABLE_ENABLED\n        GET_STATUS(tx->status) == TX_IRREVOCABLE ? KILL_OTHER :\n        GET_STATUS(t) == TX_IRREVOCABLE ? KILL_SELF :\n# endif /* IRREVOCABLE_ENABLED */\n        GET_STATUS(tx->status) == TX_KILLED ? KILL_SELF :\n        (_tinystm.contention_manager != NULL ? _tinystm.contention_manager(tx, w->tx, WW_CONFLICT) : KILL_SELF);\n      if (decision == KILL_OTHER) {\n        /* Kill other */\n        if (!stm_kill(tx, w->tx, t)) {\n          /* Transaction may have committed or aborted: retry */\n          goto restart;\n        }\n      }\n    }\n    if (decision == KILL_OTHER) {\n      /* Handle write after reads (before CAS) */\n      version = w->version;\n      goto acquire;\n    }\n    /* Kill self */\n    if ((decision & DELAY_RESTART) != 0)\n      tx->c_lock = lock;\n#elif CM == CM_DELAY\n    tx->c_lock = lock;\n#endif /* CM == CM_DELAY */\n    /* Abort */\n#ifdef CONFLICT_TRACKING\n    if (_tinystm.conflict_cb != NULL) {\n# ifdef UNIT_TX\n      if (l != LOCK_UNIT) {\n# endif /* UNIT_TX */\n        /* Call conflict callback */\n        stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n        _tinystm.conflict_cb(tx, other);\n# ifdef UNIT_TX\n      }\n# endif /* UNIT_TX */\n    }\n#endif /* CONFLICT_TRACKING */\n    stm_rollback(tx, STM_ABORT_WW_CONFLICT);\n    return NULL;\n  }\n  /* Not locked */\n  /* Handle write after reads (before CAS) */\n  version = LOCK_GET_TIMESTAMP(l);\n#ifdef IRREVOCABLE_ENABLED\n  /* In irrevocable mode, no need to revalidate */\n  if (unlikely(tx->irrevocable))\n    goto acquire_no_check;\n#endif /* IRREVOCABLE_ENABLED */\n acquire:\n  if (unlikely(version > tx->end)) {\n    /* We might have read an older version previously */\n#ifdef UNIT_TX\n    if (unlikely(tx->attr.no_extend)) {\n      stm_rollback(tx, STM_ABORT_VAL_WRITE);\n      return NULL;\n    }\n#endif /* UNIT_TX */\n    if (unlikely(stm_has_read(tx, lock) != NULL)) {\n      /* Read version must be older (otherwise, tx->end >= version) */\n      /* Not much we can do: abort */\n#if CM == CM_MODULAR\n      /* Abort caused by invisible reads */\n      tx->visible_reads++;\n#endif /* CM == CM_MODULAR */\n      stm_rollback(tx, STM_ABORT_VAL_WRITE);\n      return NULL;\n    }\n  }\n  /* Acquire lock (ETL) */\n#ifdef IRREVOCABLE_ENABLED\n acquire_no_check:\n#endif /* IRREVOCABLE_ENABLED */\n  if (unlikely(tx->w_set.nb_entries == tx->w_set.size))\n    stm_rollback(tx, STM_ABORT_EXTEND_WS);\n  w = &tx->w_set.entries[tx->w_set.nb_entries];\n#if CM == CM_MODULAR\n  w->version = version;\n#endif /* if CM == CM_MODULAR */\n  if (unlikely(ATOMIC_CAS_FULL(lock, l, LOCK_SET_ADDR_WRITE((stm_word_t)w)) == 0))\n    goto restart;\n  /* We own the lock here (ETL) */\ndo_write:\n  /* Add address to write set */\n  w->addr = addr;\n  w->mask = mask;\n  w->lock = lock;\n  if (unlikely(mask == 0)) {\n    /* Do not write anything */\n#ifndef NDEBUG\n    w->value = 0;\n#endif /* ! NDEBUG */\n  } else {\n    /* Remember new value */\n    if (mask != ~(stm_word_t)0)\n      value = (ATOMIC_LOAD(addr) & ~mask) | (value & mask);\n    w->value = value;\n  }\n#if CM != CM_MODULAR\n  w->version = version;\n#endif /* CM != CM_MODULAR */\n  w->next = NULL;\n  if (prev != NULL) {\n    /* Link new entry in list */\n    prev->next = w;\n  }\n  tx->w_set.nb_entries++;\n  tx->w_set.has_writes++;\n\n  return w;\n}\n\nstatic INLINE stm_word_t\nstm_wbetl_RaR(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* Possible optimization: avoid adding to read set again */\n  return stm_wbetl_read(tx, addr);\n}\n\nstatic INLINE stm_word_t\nstm_wbetl_RaW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  stm_word_t l;\n  w_entry_t *w;\n\n  l = ATOMIC_LOAD_ACQ(GET_LOCK(addr));\n  /* Does the lock owned? */\n  assert(LOCK_GET_WRITE(l));\n  /* Do we own the lock? */\n  w = (w_entry_t *)LOCK_GET_ADDR(l);\n  assert(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries);\n\n  /* Read directly from write set entry. */\n  return w->value;\n}\n\nstatic INLINE stm_word_t\nstm_wbetl_RfW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* Acquire lock as write. */\n  stm_wbetl_write(tx, addr, 0, 0);\n  /* Now the lock is owned, read directly from memory is safe. */\n  /* TODO Unsafe with CM_MODULAR */\n  return *addr;\n}\n\nstatic INLINE void\nstm_wbetl_WaR(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  /* Probably no optimization can be done here. */\n  stm_wbetl_write(tx, addr, value, mask);\n}\n\nstatic INLINE void\nstm_wbetl_WaW(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  stm_word_t l;\n  w_entry_t *w;\n\n  l = ATOMIC_LOAD_ACQ(GET_LOCK(addr));\n  /* Does the lock owned? */\n  assert(LOCK_GET_WRITE(l));\n  /* Do we own the lock? */\n  w = (w_entry_t *)LOCK_GET_ADDR(l);\n  assert(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries);\n  /* in WaW, mask can never be 0 */\n  assert(mask != 0);\n  while (1) {\n    if (addr == w->addr) {\n      /* No need to add to write set */\n      if (mask != ~(stm_word_t)0) {\n        if (w->mask == 0)\n          w->value = ATOMIC_LOAD(addr);\n        value = (w->value & ~mask) | (value & mask);\n      }\n      w->value = value;\n      w->mask |= mask;\n      return;\n    }\n    /* The entry must exist */\n    assert (w->next != NULL);\n    w = w->next;\n  }\n}\n\nstatic INLINE int\nstm_wbetl_commit(stm_tx_t *tx)\n{\n  w_entry_t *w;\n  stm_word_t t;\n  int i;\n\n  PRINT_DEBUG(\"==> stm_wbetl_commit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n#if CM == CM_MODULAR\n  /* A read-only transaction with visible reads must simply drop locks */\n  /* FIXME: if killed? */\n  if (tx->w_set.has_writes == 0) {\n    w = tx->w_set.entries;\n    for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n      /* Only drop lock for last covered address in write set */\n      if (w->next == NULL)\n        ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(w->version));\n    }\n    /* Update clock so that future transactions get higher timestamp (liveness of timestamp CM) */\n    FETCH_INC_CLOCK;\n    goto end;\n  }\n#endif /* CM == CM_MODULAR */\n\n  /* Update transaction */\n#ifdef IRREVOCABLE_ENABLED\n  /* Verify if there is an irrevocable transaction once all locks have been acquired */\n# ifdef IRREVOCABLE_IMPROVED\n  /* FIXME: it is bogus. the status should be changed to idle otherwise stm_quiesce will not progress */\n  if (unlikely(!tx->irrevocable)) {\n    do {\n      t = ATOMIC_LOAD(&_tinystm.irrevocable);\n      /* If the irrevocable transaction have encountered an acquired lock, abort */\n      if (t == 2) {\n        stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n        return 0;\n      }\n    } while (t);\n  }\n# else /* ! IRREVOCABLE_IMPROVED */\n  if (!tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable)) {\n    stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n    return 0;\n  }\n# endif /* ! IRREVOCABLE_IMPROVED */\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Get commit timestamp (may exceed VERSION_MAX by up to MAX_THREADS) */\n  t = FETCH_INC_CLOCK + 1;\n#ifdef IRREVOCABLE_ENABLED\n  if (unlikely(tx->irrevocable))\n    goto release_locks;\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Try to validate (only if a concurrent transaction has committed since tx->start) */\n  if (unlikely(tx->start != t - 1 && !stm_wbetl_validate(tx))) {\n    /* Cannot commit */\n#if CM == CM_MODULAR\n    /* Abort caused by invisible reads */\n    tx->visible_reads++;\n#endif /* CM == CM_MODULAR */\n    stm_rollback(tx, STM_ABORT_VALIDATE);\n    return 0;\n  }\n\n#ifdef IRREVOCABLE_ENABLED\n  release_locks:\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Install new versions, drop locks and set new timestamp */\n  w = tx->w_set.entries;\n  for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n    if (w->mask != 0)\n      ATOMIC_STORE(w->addr, w->value);\n    /* Only drop lock for last covered address in write set */\n    if (w->next == NULL) {\n# if CM == CM_MODULAR\n      /* In case of visible read, reset lock to its previous timestamp */\n      if (w->mask == 0)\n        ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(w->version));\n      else\n# endif /* CM == CM_MODULAR */\n        ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(t));\n    }\n  }\n\n end:\n  return 1;\n}\n\n#endif /* _STM_WBETL_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/src/stm_wt.h",
    "content": "/*\n * File:\n *   stm_wt.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM internal functions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _STM_WT_H_\n#define _STM_WT_H_\n\nstatic INLINE int\nstm_wt_validate(stm_tx_t *tx)\n{\n  r_entry_t *r;\n  int i;\n  stm_word_t l;\n\n  PRINT_DEBUG(\"==> stm_wt_validate(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Validate reads */\n  r = tx->r_set.entries;\n  for (i = tx->r_set.nb_entries; i > 0; i--, r++) {\n    /* Read lock */\n    l = ATOMIC_LOAD(r->lock);\n    /* Unlocked and still the same version? */\n    if (LOCK_GET_OWNED(l)) {\n      /* Do we own the lock? */\n      w_entry_t *w = (w_entry_t *)LOCK_GET_ADDR(l);\n      /* Simply check if address falls inside our write set (avoids non-faulting load) */\n      if (!(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries))\n      {\n        /* Locked by another transaction: cannot validate */\n#ifdef CONFLICT_TRACKING\n        if (_tinystm.conflict_cb != NULL) {\n# ifdef UNIT_TX\n          if (l != LOCK_UNIT) {\n# endif /* UNIT_TX */\n            /* Call conflict callback */\n            stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n            _tinystm.conflict_cb(tx, other);\n# ifdef UNIT_TX\n          }\n# endif /* UNIT_TX */\n        }\n#endif /* CONFLICT_TRACKING */\n        return 0;\n      }\n      /* We own the lock: OK */\n    } else {\n      if (LOCK_GET_TIMESTAMP(l) != r->version) {\n        /* Other version: cannot validate */\n        return 0;\n      }\n      /* Same version: OK */\n    }\n  }\n  return 1;\n}\n\n/*\n * Extend snapshot range.\n */\nstatic INLINE int\nstm_wt_extend(stm_tx_t *tx)\n{\n  stm_word_t now;\n\n  PRINT_DEBUG(\"==> stm_wt_extend(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n#ifdef UNIT_TX\n  /* Extension is disabled */\n  if (tx->attr.no_extend)\n    return 0;\n#endif /* UNIT_TX */\n\n  /* Get current time */\n  now = GET_CLOCK;\n  /* No need to check clock overflow here. The clock can exceed up to MAX_THREADS and it will be reset when the quiescence is reached. */\n\n  /* Try to validate read set */\n  if (stm_wt_validate(tx)) {\n    /* It works: we can extend until now */\n    tx->end = now;\n    return 1;\n  }\n  return 0;\n}\n\nstatic INLINE void\nstm_wt_rollback(stm_tx_t *tx)\n{\n  int i;\n  w_entry_t *w;\n  stm_word_t t;\n\n  PRINT_DEBUG(\"==> stm_wt_rollback(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  assert(IS_ACTIVE(tx->status));\n\n  t = 0;\n  /* Undo writes and drop locks */\n  w = tx->w_set.entries;\n  for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n    stm_word_t j;\n    /* Restore previous value */\n    if (w->mask != 0)\n      ATOMIC_STORE(w->addr, w->value);\n    if (w->next != NULL)\n      continue;\n    /* Incarnation numbers allow readers to detect dirty reads */\n    j = LOCK_GET_INCARNATION(w->version) + 1;\n    if (j > INCARNATION_MAX) {\n      /* Simple approach: write new version (might trigger unnecessary aborts) */\n      if (t == 0) {\n        /* Get new version (may exceed VERSION_MAX by up to MAX_THREADS) */\n        t = FETCH_INC_CLOCK + 1;\n      }\n      ATOMIC_STORE_REL(w->lock, LOCK_SET_TIMESTAMP(t));\n    } else {\n      /* Use new incarnation number */\n      ATOMIC_STORE_REL(w->lock, LOCK_UPD_INCARNATION(w->version, j));\n    }\n  }\n  /* Make sure that all lock releases become visible */\n  ATOMIC_MB_WRITE;\n}\n\nstatic INLINE void\nstm_wt_add_to_rs(stm_tx_t *tx, stm_word_t version, volatile stm_word_t *lock)\n{\n  r_entry_t *r;\n\n  /* No need to add to read set for read-only transaction */\n  if (tx->attr.read_only)\n    return;\n\n#ifdef NO_DUPLICATES_IN_RW_SETS\n  if (stm_has_read(tx, lock) != NULL)\n    return value;\n#endif /* NO_DUPLICATES_IN_RW_SETS */\n\n  /* Add address and version to read set */\n  if (tx->r_set.nb_entries == tx->r_set.size)\n    stm_allocate_rs_entries(tx, 1);\n  r = &tx->r_set.entries[tx->r_set.nb_entries++];\n  r->version = version;\n  r->lock = lock;\n}\n\nstatic INLINE stm_word_t\nstm_wt_read(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, l2, value, version;\n  w_entry_t *w;\n\n  PRINT_DEBUG2(\"==> stm_wt_read(t=%p[%lu-%lu],a=%p)\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end, addr);\n\n  assert(IS_ACTIVE(tx->status));\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Note: we could check for duplicate reads and get value from read set */\n\n  /* Read lock, value, lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (likely(!LOCK_GET_WRITE(l))) {\n    /* Not locked */\n    value = ATOMIC_LOAD_ACQ(addr);\n    l2 = ATOMIC_LOAD_ACQ(lock);\n    if (l != l2) {\n      l = l2;\n      goto restart_no_load;\n    }\n\n#ifdef IRREVOCABLE_ENABLED\n    /* In irrevocable mode, no need check timestamp nor add entry to read set */\n    if (unlikely(tx->irrevocable))\n      goto no_check;\n#endif /* IRREVOCABLE_ENABLED */\n\n    /* Check timestamp */\n    version = LOCK_GET_TIMESTAMP(l);\n\n    /* Add to read set (update transactions only) */\n    stm_wt_add_to_rs(tx, version, lock);\n\n    /* Valid version? */\n    if (unlikely(version > tx->end)) {\n      /* No: try to extend first (except for read-only transactions: no read set) */\n      if (tx->attr.read_only || !stm_wt_extend(tx)) {\n        /* Not much we can do: abort */\n        stm_rollback(tx, STM_ABORT_VAL_READ);\n        return 0;\n      }\n      /* Worked: we now have a good version (version <= tx->end) */\n    }\n\n#ifdef IRREVOCABLE_ENABLED\n no_check:\n#endif /* IRREVOCABLE_ENABLED */\n    /* We have a good version: return value */\n    return value;\n  } else {\n    /* Locked */\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (likely(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries)) {\n      /* Yes: we have a version locked by us that was valid at write time */\n      value = ATOMIC_LOAD(addr);\n      /* No need to add to read set (will remain valid) */\n      return value;\n    }\n\n# ifdef UNIT_TX\n    if (l == LOCK_UNIT) {\n      /* Data modified by a unit store: should not last long => retry */\n      goto restart;\n    }\n# endif /* UNIT_TX */\n\n    /* Conflict: CM kicks in (we could also check for duplicate reads and get value from read set) */\n# if defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED)\n    if (tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable) == 1)\n      ATOMIC_STORE(&_tinystm.irrevocable, 2);\n# endif /* defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED) */\n# if defined(IRREVOCABLE_ENABLED)\n    if (tx->irrevocable) {\n      /* Spin while locked */\n      goto restart;\n    }\n# endif /* defined(IRREVOCABLE_ENABLED) */\n# if CM == CM_DELAY\n    tx->c_lock = lock;\n# endif /* CM == CM_DELAY */\n\n    /* Abort */\n# ifdef CONFLICT_TRACKING\n    if (_tinystm.conflict_cb != NULL) {\n#  ifdef UNIT_TX\n      if (l != LOCK_UNIT) {\n#  endif /* UNIT_TX */\n        /* Call conflict callback */\n        stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n        _tinystm.conflict_cb(tx, other);\n#  ifdef UNIT_TX\n      }\n#  endif /* UNIT_TX */\n    }\n# endif /* CONFLICT_TRACKING */\n\n    stm_rollback(tx, STM_ABORT_RW_CONFLICT);\n    return 0;\n  }\n}\n\nstatic INLINE w_entry_t *\nstm_wt_write(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  volatile stm_word_t *lock;\n  stm_word_t l, version;\n  w_entry_t *w;\n  w_entry_t *prev = NULL;\n\n  PRINT_DEBUG2(\"==> stm_wt_write(t=%p[%lu-%lu],a=%p,d=%p-%lu,m=0x%lx)\\n\",\n               tx, (unsigned long)tx->start, (unsigned long)tx->end, addr, (void *)value, (unsigned long)value, (unsigned long)mask);\n\n  /* Get reference to lock */\n  lock = GET_LOCK(addr);\n\n  /* Try to acquire lock */\n restart:\n  l = ATOMIC_LOAD_ACQ(lock);\n restart_no_load:\n  if (LOCK_GET_OWNED(l)) {\n    /* Locked */\n\n#ifdef UNIT_TX\n    if (l == LOCK_UNIT) {\n      /* Data modified by a unit store: should not last long => retry */\n      goto restart;\n    }\n#endif /* UNIT_TX */\n\n    /* Do we own the lock? */\n    w = (w_entry_t *)LOCK_GET_ADDR(l);\n    /* Simply check if address falls inside our write set (avoids non-faulting load) */\n    if (likely(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries)) {\n      if (mask == 0) {\n        /* No need to insert new entry or modify existing one */\n        return w;\n      }\n      prev = w;\n      /* Did we previously write the same address? */\n      while (1) {\n        if (addr == prev->addr) {\n          if (w->mask == 0) {\n            /* Remember old value */\n            w->value = ATOMIC_LOAD(addr);\n            w->mask = mask;\n          }\n          /* Yes: only write to memory */\n          if (mask != ~(stm_word_t)0)\n            value = (ATOMIC_LOAD(addr) & ~mask) | (value & mask);\n          ATOMIC_STORE(addr, value);\n          return w;\n        }\n        if (prev->next == NULL) {\n          /* Remember last entry in linked list (for adding new entry) */\n          break;\n        }\n        prev = prev->next;\n      }\n      /* Must add to write set */\n      if (tx->w_set.nb_entries == tx->w_set.size)\n        stm_rollback(tx, STM_ABORT_EXTEND_WS);\n      w = &tx->w_set.entries[tx->w_set.nb_entries];\n      /* Get version from previous write set entry (all entries in linked list have same version) */\n      w->version = prev->version;\n      goto do_write;\n    }\n    /* Conflict: CM kicks in */\n# if defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED)\n    if (tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable) == 1)\n      ATOMIC_STORE(&_tinystm.irrevocable, 2);\n# endif /* defined(IRREVOCABLE_ENABLED) && defined(IRREVOCABLE_IMPROVED) */\n# if defined(IRREVOCABLE_ENABLED)\n    if (tx->irrevocable) {\n      /* Spin while locked */\n      goto restart;\n    }\n# endif /* defined(IRREVOCABLE_ENABLED) */\n# if CM == CM_DELAY\n    tx->c_lock = lock;\n# endif /* CM == CM_DELAY */\n\n    /* Abort */\n# ifdef CONFLICT_TRACKING\n    if (_tinystm.conflict_cb != NULL) {\n#  ifdef UNIT_TX\n      if (l != LOCK_UNIT) {\n#  endif /* UNIT_TX */\n        /* Call conflict callback */\n        stm_tx_t *other = ((w_entry_t *)LOCK_GET_ADDR(l))->tx;\n        _tinystm.conflict_cb(tx, other);\n#  ifdef UNIT_TX\n      }\n#  endif /* UNIT_TX */\n    }\n# endif /* CONFLICT_TRACKING */\n\n    stm_rollback(tx, STM_ABORT_WW_CONFLICT);\n    return NULL;\n  }\n  /* Not locked */\n  /* Handle write after reads (before CAS) */\n  version = LOCK_GET_TIMESTAMP(l);\n#ifdef IRREVOCABLE_ENABLED\n  /* In irrevocable mode, no need to revalidate */\n  if (tx->irrevocable)\n    goto acquire_no_check;\n#endif /* IRREVOCABLE_ENABLED */\n acquire:\n  if (unlikely(version > tx->end)) {\n    /* We might have read an older version previously */\n#ifdef UNIT_TX\n    if (tx->attr.no_extend) {\n      stm_rollback(tx, STM_ABORT_VAL_WRITE);\n      return NULL;\n    }\n#endif /* UNIT_TX */\n    if (stm_has_read(tx, lock) != NULL) {\n      /* Read version must be older (otherwise, tx->end >= version) */\n      /* Not much we can do: abort */\n      stm_rollback(tx, STM_ABORT_VAL_WRITE);\n      return NULL;\n    }\n  }\n  /* Acquire lock (ETL) */\n#ifdef IRREVOCABLE_ENABLED\n acquire_no_check:\n#endif /* IRREVOCABLE_ENABLED */\n  if (tx->w_set.nb_entries == tx->w_set.size)\n    stm_rollback(tx, STM_ABORT_EXTEND_WS);\n  w = &tx->w_set.entries[tx->w_set.nb_entries];\n  if (ATOMIC_CAS_FULL(lock, l, LOCK_SET_ADDR_WRITE((stm_word_t)w)) == 0)\n    goto restart;\n  /* We store the old value of the lock (timestamp and incarnation) */\n  w->version = l;\n  /* We own the lock here (ETL) */\ndo_write:\n  /* Add address to write set */\n  w->addr = addr;\n  w->mask = mask;\n  w->lock = lock;\n  if (mask == 0) {\n    /* Do not write anything */\n#ifndef NDEBUG\n    w->value = 0;\n#endif /* ! NDEBUG */\n  } else {\n    /* Remember old value */\n    w->value = ATOMIC_LOAD(addr);\n  }\n  if (mask != 0) {\n    if (mask != ~(stm_word_t)0)\n      value = (w->value & ~mask) | (value & mask);\n    ATOMIC_STORE(addr, value);\n  }\n  w->next = NULL;\n  if (prev != NULL) {\n    /* Link new entry in list */\n    prev->next = w;\n  }\n  tx->w_set.nb_entries++;\n\n  return w;\n}\n\nstatic INLINE stm_word_t\nstm_wt_RaR(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* TODO same as fast read but no need to add into the RS */\n  return stm_wt_read(tx, addr);\n}\n\nstatic INLINE stm_word_t\nstm_wt_RaW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n#ifndef NDEBUG\n  stm_word_t l;\n  w_entry_t *w;\n  l = ATOMIC_LOAD_ACQ(GET_LOCK(addr));\n  /* Does the lock owned? */\n  assert(LOCK_GET_WRITE(l));\n  /* Do we own the lock? */\n  w = (w_entry_t *)LOCK_GET_ADDR(l);\n  assert(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries);\n#endif /* ! NDEBUG */\n\n  /* Read directly from memory. */\n  return *addr;\n}\n\nstatic INLINE stm_word_t\nstm_wt_RfW(stm_tx_t *tx, volatile stm_word_t *addr)\n{\n  /* Acquire lock as write. */\n  stm_wt_write(tx, addr, 0, 0);\n  /* Now the lock is owned, read directly from memory is safe. */\n  return *addr;\n}\n\nstatic INLINE void\nstm_wt_WaR(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n  /* Probably no optimization can be done here. */\n  stm_wt_write(tx, addr, value, mask);\n}\n\nstatic INLINE void\nstm_wt_WaW(stm_tx_t *tx, volatile stm_word_t *addr, stm_word_t value, stm_word_t mask)\n{\n#ifndef NDEBUG\n  stm_word_t l;\n  w_entry_t *w;\n  l = ATOMIC_LOAD_ACQ(GET_LOCK(addr));\n  /* Does the lock owned? */\n  assert(LOCK_GET_WRITE(l));\n  /* Do we own the lock? */\n  w = (w_entry_t *)LOCK_GET_ADDR(l);\n  assert(tx->w_set.entries <= w && w < tx->w_set.entries + tx->w_set.nb_entries);\n  /* in WaW, mask can never be 0 */\n  assert(mask != 0);\n#endif /* ! NDEBUG */\n  if (mask != ~(stm_word_t)0) {\n    value = (ATOMIC_LOAD(addr) & ~mask) | (value & mask);\n  }\n  ATOMIC_STORE(addr, value);\n}\n\nstatic INLINE int\nstm_wt_commit(stm_tx_t *tx)\n{\n  w_entry_t *w;\n  stm_word_t t;\n  int i;\n\n  PRINT_DEBUG(\"==> stm_wt_commit(%p[%lu-%lu])\\n\", tx, (unsigned long)tx->start, (unsigned long)tx->end);\n\n  /* Update transaction */\n#ifdef IRREVOCABLE_ENABLED\n  /* Verify if there is an irrevocable transaction once all locks have been acquired */\n# ifdef IRREVOCABLE_IMPROVED\n  /* FIXME: it is bogus. the status should be changed to idle otherwise stm_quiesce will not progress */\n  if (unlikely(!tx->irrevocable)) {\n    do {\n      t = ATOMIC_LOAD(&_tinystm.irrevocable);\n      /* If the irrevocable transaction have encountered an acquired lock, abort */\n      if (t == 2) {\n        stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n        return 0;\n      }\n    } while (t);\n  }\n# else /* ! IRREVOCABLE_IMPROVED */\n  if (!tx->irrevocable && ATOMIC_LOAD(&_tinystm.irrevocable)) {\n    stm_rollback(tx, STM_ABORT_IRREVOCABLE);\n    return 0;\n  }\n# endif /* ! IRREVOCABLE_IMPROVED */\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Get commit timestamp (may exceed VERSION_MAX by up to MAX_THREADS) */\n  t = FETCH_INC_CLOCK + 1;\n\n#ifdef IRREVOCABLE_ENABLED\n  if (unlikely(tx->irrevocable))\n    goto release_locks;\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Try to validate (only if a concurrent transaction has committed since tx->start) */\n  if (unlikely(tx->start != t - 1 && !stm_wt_validate(tx))) {\n    /* Cannot commit */\n    stm_rollback(tx, STM_ABORT_VALIDATE);\n    return 0;\n  }\n\n#ifdef IRREVOCABLE_ENABLED\n  release_locks:\n#endif /* IRREVOCABLE_ENABLED */\n\n  /* Make sure that the updates become visible before releasing locks */\n  ATOMIC_MB_WRITE;\n  /* Drop locks and set new timestamp */\n  w = tx->w_set.entries;\n  for (i = tx->w_set.nb_entries; i > 0; i--, w++) {\n    if (w->next == NULL) {\n      /* No need for CAS (can only be modified by owner transaction) */\n      ATOMIC_STORE(w->lock, LOCK_SET_TIMESTAMP(t));\n    }\n  }\n  /* Make sure that all lock releases become visible */\n  /* TODO: is ATOMIC_MB_WRITE required? */\n  ATOMIC_MB_WRITE;\nend:\n  return 1;\n}\n\n#endif /* _STM_WT_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/src/tls.h",
    "content": "/*\n * File:\n *   tls.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM functions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n/* ################################################################### *\n * THREAD-LOCAL\n * ################################################################### *\n * Some notes about compiler thread local support\n *\n * __thread keyword supported by:\n *   * GCC\n *   * Intel C compiler (linux)\n *   * Sun CC (-xthreadvar must be specified)\n *   * IBM XL\n *\n * __declspec(thread) supported by:\n *   * Microsoft MSVC\n *   * Intel C compiler (windows)\n *   * Borland C\n *\n * __declspec(__thread) supported by:\n *   * HP compiler\n *\n * Another way to support thread locals is POSIX thread library (pthread).\n * Darwin (MacOS) has inline version for POSIX thread local.\n *\n * Finally, the GLIBC has some specific entries for TM in the thread task\n * control block (TCB).\n *\n */\n\n#ifndef _TLS_H_\n#define _TLS_H_\n\n#if !defined(TLS_COMPILER) && !defined(TLS_POSIX) && !defined(TLS_DARWIN) && !defined(TLS_GLIBC)\n# error \"TLS is not defined correctly (TLS_COMPILER, TLS_POSIX, TLS_DARWIN, TLS_GLIBC)\"\n#endif /* !defined(TLS_COMPILER) && !defined(TLS_POSIX) && !defined(TLS_DARWIN) && !defined(TLS_GLIBC) */\n\n#include \"utils.h\"\n\nstruct stm_tx;\n\n#if defined(TLS_GLIBC)\n\n/* TODO : this is x86 specific */\n# ifdef __LP64__\n#  define SEG_READ(OFS)    \"movq\\t%%fs:(\" #OFS \"*8),%0\"\n#  define SEG_WRITE(OFS)   \"movq\\t%0,%%fs:(\" #OFS \"*8)\"\n# else\n#  define SEG_READ(OFS)    \"movl\\t%%gs:(\" #OFS \"*4),%0\"\n#  define SEG_WRITE(OFS)   \"movl\\t%0,%%gs:(\" #OFS \"*4)\"\n# endif\n\nstatic INLINE void\ntls_init(void)\n{\n}\n\nstatic INLINE void\ntls_exit(void)\n{\n}\n\nstatic INLINE struct stm_tx *\ntls_get_tx(void)\n{\n  struct stm_tx *r;\n  asm volatile (SEG_READ(10) : \"=r\"(r));\n  return r;\n}\n\nstatic INLINE long\ntls_get_gc(void)\n{\n  long r;\n  asm volatile (SEG_READ(11) : \"=r\"(r));\n  return r;\n}\n\nstatic INLINE void\ntls_set_tx(struct stm_tx *tx)\n{\n  asm volatile (SEG_WRITE(10) : : \"r\"(tx));\n}\n\nstatic INLINE void\ntls_set_gc(long gc)\n{\n  asm volatile (SEG_WRITE(11) : : \"r\"(gc));\n}\n\n\n#elif defined(TLS_COMPILER)\nextern __thread struct stm_tx * thread_tx;\nextern __thread long thread_gc;\n\nstatic INLINE void\ntls_init(void)\n{\n  thread_tx = NULL;\n  thread_gc = 0;\n}\n\nstatic INLINE void\ntls_exit(void)\n{\n  thread_tx = NULL;\n  thread_gc = 0;\n}\n\nstatic INLINE struct stm_tx *\ntls_get_tx(void)\n{\n  return thread_tx;\n}\n\nstatic INLINE long\ntls_get_gc(void)\n{\n  return thread_gc;\n}\n\nstatic INLINE void\ntls_set_tx(struct stm_tx *tx)\n{\n  thread_tx = tx;\n}\n\nstatic INLINE void\ntls_set_gc(long gc)\n{\n  thread_gc = gc;\n}\n\n\n#elif defined(TLS_POSIX) || defined(TLS_DARWIN)\n\n#include <stdio.h>\n#include <stdlib.h>\n# if defined(TLS_DARWIN)\n/* Contains inline version for pthread_getspecific. */\n#  include <pthreads/pthread_machdep.h>\n# endif /* defined(TLS_DARWIN) */\n\nextern pthread_key_t thread_tx;\nextern pthread_key_t thread_gc;\n\nstatic INLINE void\ntls_init(void)\n{\n  if (pthread_key_create(&thread_tx, NULL) != 0\n      || pthread_key_create(&thread_gc, NULL) != 0) {\n    fprintf(stderr, \"Error creating thread local\\n\");\n    exit(1);\n  }\n}\n\nstatic INLINE void\ntls_exit(void)\n{\n  pthread_key_delete(thread_tx);\n  pthread_key_delete(thread_gc);\n}\n\n/*\n * Returns the transaction descriptor for the CURRENT thread.\n */\nstatic INLINE struct stm_tx*\ntls_get_tx(void)\n{\n# if defined(TLS_POSIX)\n  return (struct stm_tx *)pthread_getspecific(thread_tx);\n# elif defined(TLS_DARWIN)\n  return (struct stm_tx *)_pthread_getspecific_direct(thread_tx);\n# endif /* defined(TLS_DARWIN) */\n}\n\nstatic INLINE long\ntls_get_gc(void)\n{\n# if defined(TLS_POSIX)\n  return (long)pthread_getspecific(thread_gc);\n# elif defined(TLS_DARWIN)\n  return (long)_pthread_getspecific_direct(thread_gc);\n# endif /* defined(TLS_DARWIN) */\n}\n\n/*\n * Set the transaction descriptor for the CURRENT thread.\n */\nstatic INLINE void\ntls_set_tx(struct stm_tx *tx)\n{\n# if defined(TLS_POSIX)\n  pthread_setspecific(thread_tx, tx);\n# elif defined(TLS_DARWIN)\n  _pthread_setspecific_direct(thread_tx, tx);\n# endif /* defined(TLS_DARWIN) */\n}\n\nstatic INLINE void\ntls_set_gc(long gc)\n{\n# if defined(TLS_POSIX)\n  pthread_setspecific(thread_gc, (void *)gc);\n# elif defined(TLS_DARWIN)\n  _pthread_setspecific_direct(thread_gc, (void *)gc);\n# endif /* defined(TLS_DARWIN) */\n}\n#endif /* defined(TLS_POSIX) || defined(TLS_DARWIN) */\n\n#endif /* _TLS_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/src/utils.h",
    "content": "/*\n * File:\n *   utils.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Utilities functions.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifndef _UTILS_H_\n#define _UTILS_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#define COMPILE_TIME_ASSERT(pred)       switch (0) { case 0: case pred: ; }\n\n#ifdef DEBUG2\n# ifndef DEBUG\n#  define DEBUG\n# endif /* ! DEBUG */\n#endif /* DEBUG2 */\n\n#ifdef DEBUG\n/* Note: stdio is thread-safe */\n# define IO_FLUSH                       fflush(NULL)\n# define PRINT_DEBUG(...)               printf(__VA_ARGS__); fflush(NULL)\n#else /* ! DEBUG */\n# define IO_FLUSH\n# define PRINT_DEBUG(...)\n#endif /* ! DEBUG */\n\n#ifdef DEBUG2\n# define PRINT_DEBUG2(...)              PRINT_DEBUG(__VA_ARGS__)\n#else /* ! DEBUG2 */\n# define PRINT_DEBUG2(...)\n#endif /* ! DEBUG2 */\n\n#define XSTR(s)                         STR(s)\n#define STR(s)                          #s\n\n#ifndef CACHELINE_SIZE\n/* It ensures efficient usage of cache and avoids false sharing.\n * It could be defined in an architecture specific file. */\n# define CACHELINE_SIZE                 64\n#endif\n\n#if defined(__GNUC__) || defined(__INTEL_COMPILER)\n# define likely(x)                      __builtin_expect(!!(x), 1)\n# define unlikely(x)                    __builtin_expect(!!(x), 0)\n# define INLINE                         inline __attribute__((always_inline))\n# define NOINLINE                       __attribute__((noinline))\n# if defined(__INTEL_COMPILER)\n#  define ALIGNED                       /* Unknown */\n# else /* ! __INTEL_COMPILER */\n#  define ALIGNED                       __attribute__((aligned(CACHELINE_SIZE)))\n# endif /* ! __INTEL_COMPILER */\n#else /* ! (defined(__GNUC__) || defined(__INTEL_COMPILER)) */\n# define likely(x)                      (x)\n# define unlikely(x)                    (x)\n# define INLINE                         inline\n# define NOINLINE                       /* None in the C standard */\n# define ALIGNED                        /* None in the C standard */\n#endif /* ! (defined(__GNUC__) || defined(__INTEL_COMPILER)) */\n\n/*\n * malloc/free wrappers.\n */\nstatic INLINE void*\nxmalloc(size_t size)\n{\n  void *memptr = malloc(size);\n  if (unlikely(memptr == NULL)) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  return memptr;\n}\n\nstatic INLINE void*\nxcalloc(size_t count, size_t size)\n{\n  void *memptr = calloc(count, size);\n  if (unlikely(memptr == NULL)) {\n    perror(\"calloc\");\n    exit(1);\n  }\n  return memptr;\n}\n\nstatic INLINE void*\nxrealloc(void *addr, size_t size)\n{\n  addr = realloc(addr, size);\n  if (unlikely(addr == NULL)) {\n    perror(\"realloc\");\n    exit(1);\n  }\n  return addr;\n}\n\nstatic INLINE void\nxfree(void *mem)\n{\n  free(mem);\n}\n\nstatic INLINE void*\nxmalloc_aligned(size_t size)\n{\n  void *memptr;\n  /* TODO is posix_memalign is not available, provide malloc fallback. */\n  /* Make sure that the allocation is aligned with cacheline size. */\n#if defined(__CYGWIN__) || defined (__sun__)\n  memptr = memalign(CACHELINE_SIZE, size);\n#elif defined(__APPLE__)\n  memptr = valloc(size);\n#else\n  if (unlikely(posix_memalign(&memptr, CACHELINE_SIZE, size)))\n    memptr = NULL;\n#endif\n  if (unlikely(memptr == NULL)) {\n    fprintf(stderr, \"Error allocating aligned memory\\n\");\n    exit(1);\n  }\n  return memptr;\n}\n\n#endif /* !_UTILS_H_ */\n\n"
  },
  {
    "path": "stms/tinystm/src/wrappers.c",
    "content": "/*\n * File:\n *   wrappers.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   STM wrapper functions for different data types.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n\n#include \"utils.h\"\n#include \"stm_internal.h\"\n#include \"wrappers.h\"\n\n#define ALLOW_MISALIGNED_ACCESSES\n\n#define TM_LOAD(addr)                stm_load(addr)\n#define TM_STORE(addr, val)          stm_store(addr, val)\n#define TM_STORE2(addr, val, mask)   stm_store2(addr, val, mask)\n\ntypedef union convert_64 {\n  uint64_t u64;\n  uint32_t u32[2];\n  uint16_t u16[4];\n  uint8_t u8[8];\n  int64_t s64;\n  double d;\n} convert_64_t;\n\ntypedef union convert_32 {\n  uint32_t u32;\n  uint16_t u16[2];\n  uint8_t u8[4];\n  int32_t s32;\n  float f;\n} convert_32_t;\n\ntypedef union convert_16 {\n  uint16_t u16;\n  int16_t s16;\n} convert_16_t;\n\ntypedef union convert_8 {\n  uint8_t u8;\n  int8_t s8;\n} convert_8_t;\n\ntypedef union convert {\n  stm_word_t w;\n  uint8_t b[sizeof(stm_word_t)];\n} convert_t;\n\nstatic void sanity_checks(void)\n{\n  COMPILE_TIME_ASSERT(sizeof(convert_64_t) == 8);\n  COMPILE_TIME_ASSERT(sizeof(convert_32_t) == 4);\n  COMPILE_TIME_ASSERT(sizeof(stm_word_t) == 4 || sizeof(stm_word_t) == 8);\n  COMPILE_TIME_ASSERT(sizeof(char) == 1);\n  COMPILE_TIME_ASSERT(sizeof(short) == 2);\n  COMPILE_TIME_ASSERT(sizeof(int) == 4);\n  COMPILE_TIME_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);\n  COMPILE_TIME_ASSERT(sizeof(float) == 4);\n  COMPILE_TIME_ASSERT(sizeof(double) == 8);\n}\n\n/* ################################################################### *\n * INLINE LOADS\n * ################################################################### */\n\nstatic INLINE\nuint8_t int_stm_load_u8(volatile uint8_t *addr)\n{\n  if (sizeof(stm_word_t) == 4) {\n    convert_32_t val;\n    val.u32 = (uint32_t)TM_LOAD((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03));\n    return val.u8[(uintptr_t)addr & 0x03];\n  } else {\n    convert_64_t val;\n    val.u64 = (uint64_t)TM_LOAD((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07));\n    return val.u8[(uintptr_t)addr & 0x07];\n  }\n}\n\nstatic INLINE\nuint16_t int_stm_load_u16(volatile uint16_t *addr)\n{\n  if (unlikely(((uintptr_t)addr & 0x01) != 0)) {\n    uint16_t val;\n    stm_load_bytes((volatile uint8_t *)addr, (uint8_t *)&val, sizeof(uint16_t));\n    return val;\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_32_t val;\n    val.u32 = (uint32_t)TM_LOAD((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03));\n    return val.u16[((uintptr_t)addr & 0x03) >> 1];\n  } else {\n    convert_64_t val;\n    val.u64 = (uint64_t)TM_LOAD((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07));\n    return val.u16[((uintptr_t)addr & 0x07) >> 1];\n  }\n}\n\nstatic INLINE\nuint32_t int_stm_load_u32(volatile uint32_t *addr)\n{\n  if (unlikely(((uintptr_t)addr & 0x03) != 0)) {\n    uint32_t val;\n    stm_load_bytes((volatile uint8_t *)addr, (uint8_t *)&val, sizeof(uint32_t));\n    return val;\n  } else if (sizeof(stm_word_t) == 4) {\n    return (uint32_t)TM_LOAD((volatile stm_word_t *)addr);\n  } else {\n    convert_64_t val;\n    val.u64 = (uint64_t)TM_LOAD((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07));\n    return val.u32[((uintptr_t)addr & 0x07) >> 2];\n  }\n}\n\nstatic INLINE\nuint64_t int_stm_load_u64(volatile uint64_t *addr)\n{\n  if (unlikely(((uintptr_t)addr & 0x07) != 0)) {\n    uint64_t val;\n    stm_load_bytes((volatile uint8_t *)addr, (uint8_t *)&val, sizeof(uint64_t));\n    return val;\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_64_t val;\n    val.u32[0] = (uint32_t)TM_LOAD((volatile stm_word_t *)addr);\n    val.u32[1] = (uint32_t)TM_LOAD((volatile stm_word_t *)addr + 1);\n    return val.u64;\n  } else {\n    return (uint64_t)TM_LOAD((volatile stm_word_t *)addr);\n  }\n}\n\n/* ################################################################### *\n * LOADS\n * ################################################################### */\n\n_CALLCONV uint8_t stm_load_u8(volatile uint8_t *addr)\n{\n  return int_stm_load_u8(addr);\n}\n\n_CALLCONV uint16_t stm_load_u16(volatile uint16_t *addr)\n{\n  return int_stm_load_u16(addr);\n}\n\n_CALLCONV uint32_t stm_load_u32(volatile uint32_t *addr)\n{\n  return int_stm_load_u32(addr);\n}\n\n_CALLCONV uint64_t stm_load_u64(volatile uint64_t *addr)\n{\n  return int_stm_load_u64(addr);\n}\n\n_CALLCONV char stm_load_char(volatile char *addr)\n{\n  convert_8_t val;\n  val.u8 = int_stm_load_u8((volatile uint8_t *)addr);\n  return val.s8;\n}\n\n_CALLCONV unsigned char stm_load_uchar(volatile unsigned char *addr)\n{\n  return (unsigned char)int_stm_load_u8((volatile uint8_t *)addr);\n}\n\n_CALLCONV short stm_load_short(volatile short *addr)\n{\n  convert_16_t val;\n  val.u16 = int_stm_load_u16((volatile uint16_t *)addr);\n  return val.s16;\n}\n\n_CALLCONV unsigned short stm_load_ushort(volatile unsigned short *addr)\n{\n  return (unsigned short)int_stm_load_u16((volatile uint16_t *)addr);\n}\n\n_CALLCONV int stm_load_int(volatile int *addr)\n{\n  convert_32_t val;\n  val.u32 = int_stm_load_u32((volatile uint32_t *)addr);\n  return val.s32;\n}\n\n_CALLCONV unsigned int stm_load_uint(volatile unsigned int *addr)\n{\n  return (unsigned int)int_stm_load_u32((volatile uint32_t *)addr);\n}\n\n_CALLCONV long stm_load_long(volatile long *addr)\n{\n  if (sizeof(long) == 4) {\n    convert_32_t val;\n    val.u32 = int_stm_load_u32((volatile uint32_t *)addr);\n    return val.s32;\n  } else {\n    convert_64_t val;\n    val.u64 = int_stm_load_u64((volatile uint64_t *)addr);\n    return val.s64;\n  }\n}\n\n_CALLCONV unsigned long stm_load_ulong(volatile unsigned long *addr)\n{\n  if (sizeof(long) == 4) {\n    return (unsigned long)int_stm_load_u32((volatile uint32_t *)addr);\n  } else {\n    return (unsigned long)int_stm_load_u64((volatile uint64_t *)addr);\n  }\n}\n\n_CALLCONV float stm_load_float(volatile float *addr)\n{\n  convert_32_t val;\n  val.u32 = int_stm_load_u32((volatile uint32_t *)addr);\n  return val.f;\n}\n\n_CALLCONV double stm_load_double(volatile double *addr)\n{\n  convert_64_t val;\n  val.u64 = int_stm_load_u64((volatile uint64_t *)addr);\n  return val.d;\n}\n\n_CALLCONV void *stm_load_ptr(volatile void **addr)\n{\n  union { stm_word_t w; void *v; } convert;\n  convert.w = TM_LOAD((stm_word_t *)addr);\n  return convert.v;\n}\n\n_CALLCONV void stm_load_bytes(volatile uint8_t *addr, uint8_t *buf, size_t size)\n{\n  convert_t val;\n  unsigned int i;\n  stm_word_t *a;\n\n  if (size == 0)\n    return;\n  i = (uintptr_t)addr & (sizeof(stm_word_t) - 1);\n  if (i != 0) {\n    /* First bytes */\n    a = (stm_word_t *)((uintptr_t)addr & ~(uintptr_t)(sizeof(stm_word_t) - 1));\n    val.w = TM_LOAD(a++);\n    for (; i < sizeof(stm_word_t) && size > 0; i++, size--)\n      *buf++ = val.b[i];\n  } else\n    a = (stm_word_t *)addr;\n  /* Full words */\n  while (size >= sizeof(stm_word_t)) {\n#ifdef ALLOW_MISALIGNED_ACCESSES\n    *((stm_word_t *)buf) = TM_LOAD(a++);\n    buf += sizeof(stm_word_t);\n#else /* ! ALLOW_MISALIGNED_ACCESSES */\n    val.w = TM_LOAD(a++);\n    for (i = 0; i < sizeof(stm_word_t); i++)\n      *buf++ = val.b[i];\n#endif /* ! ALLOW_MISALIGNED_ACCESSES */\n    size -= sizeof(stm_word_t);\n  }\n  if (size > 0) {\n    /* Last bytes */\n    val.w = TM_LOAD(a);\n    i = 0;\n    for (i = 0; size > 0; i++, size--)\n      *buf++ = val.b[i];\n  }\n}\n\n/* ################################################################### *\n * INLINE STORES\n * ################################################################### */\n\nstatic INLINE\nvoid int_stm_store_u8(volatile uint8_t *addr, uint8_t value)\n{\n  if (sizeof(stm_word_t) == 4) {\n    convert_32_t val, mask;\n    val.u8[(uintptr_t)addr & 0x03] = value;\n    mask.u32 = 0;\n    mask.u8[(uintptr_t)addr & 0x03] = ~(uint8_t)0;\n    TM_STORE2((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03), (stm_word_t)val.u32, (stm_word_t)mask.u32);\n  } else {\n    convert_64_t val, mask;\n    val.u8[(uintptr_t)addr & 0x07] = value;\n    mask.u64 = 0;\n    mask.u8[(uintptr_t)addr & 0x07] = ~(uint8_t)0;\n    TM_STORE2((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07), (stm_word_t)val.u64, (stm_word_t)mask.u64);\n  }\n}\n\nstatic INLINE\nvoid int_stm_store_u16(volatile uint16_t *addr, uint16_t value)\n{\n  if (unlikely(((uintptr_t)addr & 0x01) != 0)) {\n    stm_store_bytes((volatile uint8_t *)addr, (uint8_t *)&value, sizeof(uint16_t));\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_32_t val, mask;\n    val.u16[((uintptr_t)addr & 0x03) >> 1] = value;\n    mask.u32 = 0;\n    mask.u16[((uintptr_t)addr & 0x03) >> 1] = ~(uint16_t)0;\n    TM_STORE2((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x03), (stm_word_t)val.u32, (stm_word_t)mask.u32);\n  } else {\n    convert_64_t val, mask;\n    val.u16[((uintptr_t)addr & 0x07) >> 1] = value;\n    mask.u64 = 0;\n    mask.u16[((uintptr_t)addr & 0x07) >> 1] = ~(uint16_t)0;\n    TM_STORE2((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07), (stm_word_t)val.u64, (stm_word_t)mask.u64);\n  }\n}\n\nstatic INLINE\nvoid int_stm_store_u32(volatile uint32_t *addr, uint32_t value)\n{\n  if (unlikely(((uintptr_t)addr & 0x03) != 0)) {\n    stm_store_bytes((volatile uint8_t *)addr, (uint8_t *)&value, sizeof(uint32_t));\n  } else if (sizeof(stm_word_t) == 4) {\n    TM_STORE((volatile stm_word_t *)addr, (stm_word_t)value);\n  } else {\n    convert_64_t val, mask;\n    val.u32[((uintptr_t)addr & 0x07) >> 2] = value;\n    mask.u64 = 0;\n    mask.u32[((uintptr_t)addr & 0x07) >> 2] = ~(uint32_t)0;\n    TM_STORE2((volatile stm_word_t *)((uintptr_t)addr & ~(uintptr_t)0x07), (stm_word_t)val.u64, (stm_word_t)mask.u64);\n  }\n}\n\nstatic INLINE\nvoid int_stm_store_u64(volatile uint64_t *addr, uint64_t value)\n{\n  if (unlikely(((uintptr_t)addr & 0x07) != 0)) {\n    stm_store_bytes((volatile uint8_t *)addr, (uint8_t *)&value, sizeof(uint64_t));\n  } else if (sizeof(stm_word_t) == 4) {\n    convert_64_t val;\n    val.u64 = value;\n    TM_STORE((volatile stm_word_t *)addr, (stm_word_t)val.u32[0]);\n    TM_STORE((volatile stm_word_t *)addr + 1, (stm_word_t)val.u32[1]);\n  } else {\n    return TM_STORE((volatile stm_word_t *)addr, (stm_word_t)value);\n  }\n}\n\n/* ################################################################### *\n * STORES\n * ################################################################### */\n\n_CALLCONV void stm_store_u8(volatile uint8_t *addr, uint8_t value)\n{\n  int_stm_store_u8(addr, value);\n}\n\n_CALLCONV void stm_store_u16(volatile uint16_t *addr, uint16_t value)\n{\n  int_stm_store_u16(addr, value);\n}\n\n_CALLCONV void stm_store_u32(volatile uint32_t *addr, uint32_t value)\n{\n  int_stm_store_u32(addr, value);\n}\n\n_CALLCONV void stm_store_u64(volatile uint64_t *addr, uint64_t value)\n{\n  int_stm_store_u64(addr, value);\n}\n\n_CALLCONV void stm_store_char(volatile char *addr, char value)\n{\n  convert_8_t val;\n  val.s8 = value;\n  int_stm_store_u8((volatile uint8_t *)addr, val.u8);\n}\n\n_CALLCONV void stm_store_uchar(volatile unsigned char *addr, unsigned char value)\n{\n  int_stm_store_u8((volatile uint8_t *)addr, (uint8_t)value);\n}\n\n_CALLCONV void stm_store_short(volatile short *addr, short value)\n{\n  convert_16_t val;\n  val.s16 = value;\n  int_stm_store_u16((volatile uint16_t *)addr, val.u16);\n}\n\n_CALLCONV void stm_store_ushort(volatile unsigned short *addr, unsigned short value)\n{\n  int_stm_store_u16((volatile uint16_t *)addr, (uint16_t)value);\n}\n\n_CALLCONV void stm_store_int(volatile int *addr, int value)\n{\n  convert_32_t val;\n  val.s32 = value;\n  int_stm_store_u32((volatile uint32_t *)addr, val.u32);\n}\n\n_CALLCONV void stm_store_uint(volatile unsigned int *addr, unsigned int value)\n{\n  int_stm_store_u32((volatile uint32_t *)addr, (uint32_t)value);\n}\n\n_CALLCONV void stm_store_long(volatile long *addr, long value)\n{\n  if (sizeof(long) == 4) {\n    convert_32_t val;\n    val.s32 = value;\n    int_stm_store_u32((volatile uint32_t *)addr, val.u32);\n  } else {\n    convert_64_t val;\n    val.s64 = value;\n    int_stm_store_u64((volatile uint64_t *)addr, val.u64);\n  }\n}\n\n_CALLCONV void stm_store_ulong(volatile unsigned long *addr, unsigned long value)\n{\n  if (sizeof(long) == 4) {\n    int_stm_store_u32((volatile uint32_t *)addr, (uint32_t)value);\n  } else {\n    int_stm_store_u64((volatile uint64_t *)addr, (uint64_t)value);\n  }\n}\n\n_CALLCONV void stm_store_float(volatile float *addr, float value)\n{\n  convert_32_t val;\n  val.f = value;\n  int_stm_store_u32((volatile uint32_t *)addr, val.u32);\n}\n\n_CALLCONV void stm_store_double(volatile double *addr, double value)\n{\n  convert_64_t val;\n  val.d = value;\n  int_stm_store_u64((volatile uint64_t *)addr, val.u64);\n}\n\n_CALLCONV void stm_store_ptr(volatile void **addr, void *value)\n{\n  union { stm_word_t w; void *v; } convert;\n  convert.v = value;\n  TM_STORE((stm_word_t *)addr, convert.w);\n}\n\n_CALLCONV void stm_store_bytes(volatile uint8_t *addr, uint8_t *buf, size_t size)\n{\n  convert_t val, mask;\n  unsigned int i;\n  stm_word_t *a;\n\n  if (size == 0)\n    return;\n  i = (uintptr_t)addr & (sizeof(stm_word_t) - 1);\n  if (i != 0) {\n    /* First bytes */\n    a = (stm_word_t *)((uintptr_t)addr & ~(uintptr_t)(sizeof(stm_word_t) - 1));\n    val.w = mask.w = 0;\n    for (; i < sizeof(stm_word_t) && size > 0; i++, size--) {\n      mask.b[i] = 0xFF;\n      val.b[i] = *buf++;\n    }\n    TM_STORE2(a++, val.w, mask.w);\n  } else\n    a = (stm_word_t *)addr;\n  /* Full words */\n  while (size >= sizeof(stm_word_t)) {\n#ifdef ALLOW_MISALIGNED_ACCESSES\n    TM_STORE(a++, *((stm_word_t *)buf));\n    buf += sizeof(stm_word_t);\n#else /* ! ALLOW_MISALIGNED_ACCESSES */\n    for (i = 0; i < sizeof(stm_word_t); i++)\n      val.b[i] = *buf++;\n    TM_STORE(a++, val.w);\n#endif /* ! ALLOW_MISALIGNED_ACCESSES */\n    size -= sizeof(stm_word_t);\n  }\n  if (size > 0) {\n    /* Last bytes */\n    val.w = mask.w = 0;\n    for (i = 0; size > 0; i++, size--) {\n      mask.b[i] = 0xFF;\n      val.b[i] = *buf++;\n    }\n    TM_STORE2(a, val.w, mask.w);\n  }\n}\n\n_CALLCONV void stm_set_bytes(volatile uint8_t *addr, uint8_t byte, size_t count)\n{\n  convert_t val, mask;\n  unsigned int i;\n  stm_word_t *a;\n\n  if (count == 0)\n    return;\n\n  for (i = 0; i < sizeof(stm_word_t); i++)\n    val.b[i] = byte;\n\n  i = (uintptr_t)addr & (sizeof(stm_word_t) - 1);\n  if (i != 0) {\n    /* First bytes */\n    a = (stm_word_t *)((uintptr_t)addr & ~(uintptr_t)(sizeof(stm_word_t) - 1));\n    mask.w = 0;\n    for (; i < sizeof(stm_word_t) && count > 0; i++, count--)\n      mask.b[i] = 0xFF;\n    TM_STORE2(a++, val.w, mask.w);\n  } else\n    a = (stm_word_t *)addr;\n  /* Full words */\n  while (count >= sizeof(stm_word_t)) {\n    TM_STORE(a++, val.w);\n    count -= sizeof(stm_word_t);\n  }\n  if (count > 0) {\n    /* Last bytes */\n    mask.w = 0;\n    for (i = 0; count > 0; i++, count--)\n      mask.b[i] = 0xFF;\n    TM_STORE2(a, val.w, mask.w);\n  }\n}\n\n#undef TM_LOAD\n#undef TM_STORE\n#undef TM_STORE2\n\n"
  },
  {
    "path": "stms/tinystm/test/Makefile",
    "content": ".PHONY:\tall\n\nTESTS = bank intset regression\n\n.PHONY:\tall $(TESTS)\n\nall:\t$(TESTS)\n\ncheck: \tall\n\t@echo Testing load/store \\(regression/types\\) \n\t@./regression/types 1>/dev/null 2>&1\n\t@echo Testing irrevocability \\(regression/irrevocability\\)\n\t@./regression/irrevocability 1>/dev/null 2>&1\n\t@echo Testing Linked List \\(intset/intset-ll\\)\n\t@./intset/intset-ll -d 2000 1>/dev/null 2>&1\n\t@echo Testing Linked List with concurrency \\(intset/intset-ll -n 4\\)\n\t@./intset/intset-ll -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo Testing Red Black Tree \\(intset/intset-rb\\)\n\t@./intset/intset-rb -d 2000 1>/dev/null 2>&1\n\t@echo Testing Red Black Tree with concurrency \\(intset/intset-rb -n 4\\)\n\t@./intset/intset-rb -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo Testing Skip List \\(intset/intset-sl\\)\n\t@./intset/intset-sl -d 2000 1>/dev/null 2>&1\n\t@echo Testing Skip List with concurrency \\(intset/intset-sl -n 4\\)\n\t@./intset/intset-sl -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo Testing Hash Set \\(intset/intset-hs\\)\n\t@./intset/intset-hs -d 2000 1>/dev/null 2>&1\n\t@echo Testing Hash Set with concurrency \\(intset/intset-hs -n 4\\)\n\t@./intset/intset-hs -d 2000 -n 4 1>/dev/null 2>&1\n\t@echo All tests passed\n\n$(TESTS):\n\t$(MAKE) -C $@ $(TARGET)\n"
  },
  {
    "path": "stms/tinystm/test/intset/.gitignore",
    "content": "intset-ll\nintset-hs\nintset-sl\nintset-rb\n"
  },
  {
    "path": "stms/tinystm/test/intset/Makefile",
    "content": "ROOT ?= ../..\n\ninclude $(ROOT)/Makefile.common\n\nBINS = intset-hs intset-ll intset-rb intset-sl\n\nUNAME := $(shell uname)\nifeq ($(UNAME), SunOS)\n# Solaris requires rt lib for nanosleep\nLDFLAGS += -lrt\nendif\n\n.PHONY:\tall clean\n\nall:\t$(BINS)\n\nintset-hs.o:\tintset.c\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -DUSE_HASHSET -c -o $@ $<\n\nintset-ll.o:\tintset.c\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -DUSE_LINKEDLIST -c -o $@ $<\n\nintset-rb.o:\tintset.c rbtree.c rbtree.h\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -DUSE_RBTREE -c -o $@ $<\n\nintset-sl.o:\tintset.c\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -DUSE_SKIPLIST -c -o $@ $<\n\n# FIXME in case of ABI $(TMLIB) must be replaced to abi/...\n$(BINS):\t%:\t%.o $(TMLIB)\n\t$(LD) -o $@ $< $(LDFLAGS)\n\nclean:\n\trm -f $(BINS) *.o\n"
  },
  {
    "path": "stms/tinystm/test/intset/README.rbtree",
    "content": "The red-black tree implementation (rbtree.c, rbtree.h, types.h) comes\nfrom the STAMP 0.9.10 distribution available from\n<http://stamp.stanford.edu>.  Files have not been modified in any way\nbesides enabling memory deallocation upon node release.\n"
  },
  {
    "path": "stms/tinystm/test/intset/intset.c",
    "content": "/*\n * File:\n *   intset.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Integer set stress test.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <assert.h>\n#include <getopt.h>\n#include <limits.h>\n#include <pthread.h>\n#include <signal.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <sys/time.h>\n#include <time.h>\n\n#define RO                              1\n#define RW                              0\n\n#if defined(TM_GCC) \n# include \"../../abi/gcc/tm_macros.h\"\n#elif defined(TM_DTMC) \n# include \"../../abi/dtmc/tm_macros.h\"\n/* Make erand48 pure for DTMC (transaction_pure should work too). */\nstatic double tanger_wrapperpure_erand48(unsigned short int __xsubi[3]) __attribute__ ((weakref(\"erand48\")));\n#elif defined(TM_INTEL)\n# include \"../../abi/intel/tm_macros.h\"\n#elif defined(TM_ABI)\n# include \"../../abi/tm_macros.h\"\n#endif /* defined(TM_ABI) */\n\n#if defined(TM_GCC) || defined(TM_DTMC) || defined(TM_INTEL) || defined(TM_ABI)\n# define TM_COMPILER\n/* Add some attributes to library function */\nTM_PURE \nvoid exit(int status);\nTM_PURE \nvoid perror(const char *s);\n#else /* Compile with explicit calls to tinySTM */\n\n# include \"stm.h\"\n# include \"mod_mem.h\"\n# include \"mod_ab.h\"\n\n/*\n * Useful macros to work with transactions. Note that, to use nested\n * transactions, one should check the environment returned by\n * stm_get_env() and only call sigsetjmp() if it is not null.\n */\n# define TM_START(tid, ro)                  { stm_tx_attr_t _a = {{.id = tid, .read_only = ro}}; \\\n                                              sigjmp_buf *_e = stm_start(_a); \\\n                                              if (_e != NULL) sigsetjmp(*_e, 0); \n# define TM_START_TS(ts, label)             { sigjmp_buf *_e = stm_start((stm_tx_attr_t)0); \\\n                                              if (_e != NULL && sigsetjmp(*_e, 0)) goto label; \\\n\t                                      stm_set_extension(0, &ts)\n# define TM_LOAD(addr)                      stm_load((stm_word_t *)addr)\n# define TM_UNIT_LOAD(addr, ts)             stm_unit_load((stm_word_t *)addr, ts)\n# define TM_STORE(addr, value)              stm_store((stm_word_t *)addr, (stm_word_t)value)\n# define TM_UNIT_STORE(addr, value, ts)     stm_unit_store((stm_word_t *)addr, (stm_word_t)value, ts)\n# define TM_COMMIT                          stm_commit(); }\n# define TM_MALLOC(size)                    stm_malloc(size)\n# define TM_FREE(addr)                      stm_free(addr, sizeof(*addr))\n# define TM_FREE2(addr, size)               stm_free(addr, size)\n\n# define TM_INIT                            stm_init(); mod_mem_init(0); mod_ab_init(0, NULL)\n# define TM_EXIT                            stm_exit()\n# define TM_INIT_THREAD                     stm_init_thread()\n# define TM_EXIT_THREAD                     stm_exit_thread()\n\n/* Annotations used in this benchmark */\n# define TM_SAFE\n# define TM_PURE\n\n#endif /* Compile with explicit calls to tinySTM */\n\n#ifdef DEBUG\n# define IO_FLUSH                       fflush(NULL)\n/* Note: stdio is thread-safe */\n#endif\n\n#if !(defined(USE_LINKEDLIST) || defined(USE_RBTREE) || defined(USE_SKIPLIST) || defined(USE_HASHSET))\n# error \"Must define USE_LINKEDLIST or USE_RBTREE or USE_SKIPLIST or USE_HASHSET\"\n#endif /* !(defined(USE_LINKEDLIST) || defined(USE_RBTREE) || defined(USE_SKIPLIST) || defined(USE_HASHSET)) */\n\n\n#define DEFAULT_DURATION                10000\n#define DEFAULT_INITIAL                 256\n#define DEFAULT_NB_THREADS              1\n#define DEFAULT_RANGE                   (DEFAULT_INITIAL * 2)\n#define DEFAULT_SEED                    0\n#define DEFAULT_UPDATE                  20\n\n#define XSTR(s)                         STR(s)\n#define STR(s)                          #s\n\n/* ################################################################### *\n * GLOBALS\n * ################################################################### */\nstatic volatile int stop;\nstatic unsigned short main_seed[3];\n\nstatic inline void rand_init(unsigned short *seed)\n{\n  seed[0] = (unsigned short)rand();\n  seed[1] = (unsigned short)rand();\n  seed[2] = (unsigned short)rand();\n}\n\nstatic inline int rand_range(int n, unsigned short *seed)\n{\n  /* Return a random number in range [0;n) */\n  int v = (int)(erand48(seed) * n);\n  assert (v >= 0 && v < n);\n  return v;\n}\n\ntypedef struct thread_data {\n  struct intset *set;\n  struct barrier *barrier;\n  unsigned long nb_add;\n  unsigned long nb_remove;\n  unsigned long nb_contains;\n  unsigned long nb_found;\n#ifndef TM_COMPILER\n  unsigned long nb_aborts;\n  unsigned long nb_aborts_1;\n  unsigned long nb_aborts_2;\n  unsigned long nb_aborts_locked_read;\n  unsigned long nb_aborts_locked_write;\n  unsigned long nb_aborts_validate_read;\n  unsigned long nb_aborts_validate_write;\n  unsigned long nb_aborts_validate_commit;\n  unsigned long nb_aborts_invalid_memory;\n  unsigned long nb_aborts_killed;\n  unsigned long locked_reads_ok;\n  unsigned long locked_reads_failed;\n  unsigned long max_retries;\n#endif /* ! TM_COMPILER */\n  unsigned short seed[3];\n  int diff;\n  int range;\n  int update;\n  int alternate;\n#ifdef USE_LINKEDLIST\n  int unit_tx;\n#endif /* LINKEDLIST */\n  char padding[64];\n} thread_data_t;\n\n#if defined(USE_LINKEDLIST)\n\n/* ################################################################### *\n * LINKEDLIST\n * ################################################################### */\n\n# define INIT_SET_PARAMETERS            /* Nothing */\n\ntypedef intptr_t val_t;\n# define VAL_MIN                        INT_MIN\n# define VAL_MAX                        INT_MAX\n\ntypedef struct node {\n  val_t val;\n  struct node *next;\n} node_t;\n\ntypedef struct intset {\n  node_t *head;\n} intset_t;\n\nTM_SAFE\nstatic node_t *new_node(val_t val, node_t *next, int transactional)\n{\n  node_t *node;\n\n  if (!transactional) {\n    node = (node_t *)malloc(sizeof(node_t));\n  } else {\n    node = (node_t *)TM_MALLOC(sizeof(node_t));\n  }\n  if (node == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n\n  node->val = val;\n  node->next = next;\n\n  return node;\n}\n\nstatic intset_t *set_new()\n{\n  intset_t *set;\n  node_t *min, *max;\n\n  if ((set = (intset_t *)malloc(sizeof(intset_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  max = new_node(VAL_MAX, NULL, 0);\n  min = new_node(VAL_MIN, max, 0);\n  set->head = min;\n\n  return set;\n}\n\nstatic void set_delete(intset_t *set)\n{\n  node_t *node, *next;\n\n  node = set->head;\n  while (node != NULL) {\n    next = node->next;\n    free(node);\n    node = next;\n  }\n  free(set);\n}\n\nstatic int set_size(intset_t *set)\n{\n  int size = 0;\n  node_t *node;\n\n  /* We have at least 2 elements */\n  node = set->head->next;\n  while (node->next != NULL) {\n    size++;\n    node = node->next;\n  }\n\n  return size;\n}\n\nstatic int set_contains(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result;\n  node_t *prev, *next;\n  val_t v;\n\n# ifdef DEBUG\n  printf(\"++> set_contains(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (td == NULL) {\n    prev = set->head;\n    next = prev->next;\n    while (next->val < val) {\n      prev = next;\n      next = prev->next;\n    }\n    result = (next->val == val);\n  } else if (td->unit_tx == 0) {\n    TM_START(0, RO);\n    prev = (node_t *)TM_LOAD(&set->head);\n    next = (node_t *)TM_LOAD(&prev->next);\n    while (1) {\n      v = TM_LOAD(&next->val);\n      if (v >= val)\n        break;\n      prev = next;\n      next = (node_t *)TM_LOAD(&prev->next);\n    }\n    result = (v == val);\n    TM_COMMIT;\n  } \n#ifndef TM_COMPILER\n  else {\n    /* Unit transactions */\n    stm_word_t ts, start_ts, val_ts;\n  restart:\n    start_ts = stm_get_clock();\n    /* Head node is never removed */\n    prev = (node_t *)TM_UNIT_LOAD(&set->head, &ts);\n    next = (node_t *)TM_UNIT_LOAD(&prev->next, &ts);\n    if (ts > start_ts)\n      start_ts = ts;\n    while (1) {\n      v = TM_UNIT_LOAD(&next->val, &val_ts);\n      if (val_ts > start_ts) {\n        /* Restart traversal (could also backtrack) */\n        goto restart;\n      }\n      if (v >= val)\n        break;\n      prev = next;\n      next = (node_t *)TM_UNIT_LOAD(&prev->next, &ts);\n      if (ts > start_ts) {\n        /* Verify that node has not been modified (value and pointer are updated together) */\n        TM_UNIT_LOAD(&prev->val, &val_ts);\n        if (val_ts > start_ts) {\n          /* Restart traversal (could also backtrack) */\n          goto restart;\n        }\n        start_ts = ts;\n      }\n    }\n    result = (v == val);\n  }\n#endif /* TM_COMPILER */\n\n  return result;\n}\n\nstatic int set_add(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result;\n  node_t *prev, *next;\n  val_t v;\n\n# ifdef DEBUG\n  printf(\"++> set_add(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (td == NULL) {\n    prev = set->head;\n    next = prev->next;\n    while (next->val < val) {\n      prev = next;\n      next = prev->next;\n    }\n    result = (next->val != val);\n    if (result) {\n      prev->next = new_node(val, next, 0);\n    }\n  } else if (td->unit_tx == 0) {\n    TM_START(1, RW);\n    prev = (node_t *)TM_LOAD(&set->head);\n    next = (node_t *)TM_LOAD(&prev->next);\n    while (1) {\n      v = TM_LOAD(&next->val);\n      if (v >= val)\n        break;\n      prev = next;\n      next = (node_t *)TM_LOAD(&prev->next);\n    }\n    result = (v != val);\n    if (result) {\n      TM_STORE(&prev->next, new_node(val, next, 1));\n    }\n    TM_COMMIT;\n  } \n#ifndef TM_COMPILER\n  else {\n    /* Unit transactions */\n    stm_word_t ts, start_ts, val_ts;\n  restart:\n    start_ts = stm_get_clock();\n    /* Head node is never removed */\n    prev = (node_t *)TM_UNIT_LOAD(&set->head, &ts);\n    next = (node_t *)TM_UNIT_LOAD(&prev->next, &ts);\n    if (ts > start_ts)\n      start_ts = ts;\n    while (1) {\n      v = TM_UNIT_LOAD(&next->val, &val_ts);\n      if (val_ts > start_ts) {\n        /* Restart traversal (could also backtrack) */\n        goto restart;\n      }\n      if (v >= val)\n        break;\n      prev = next;\n      next = (node_t *)TM_UNIT_LOAD(&prev->next, &ts);\n      if (ts > start_ts) {\n        /* Verify that node has not been modified (value and pointer are updated together) */\n        TM_UNIT_LOAD(&prev->val, &val_ts);\n        if (val_ts > start_ts) {\n          /* Restart traversal (could also backtrack) */\n          goto restart;\n        }\n        start_ts = ts;\n      }\n    }\n    result = (v != val);\n    if (result) {\n      node_t *n = new_node(val, next, 0);\n      /* Make sure that there are no concurrent updates to that memory location */\n      if (!TM_UNIT_STORE(&prev->next, n, &ts)) {\n        free(n);\n        goto restart;\n      }\n    }\n  }\n#endif /* ! TM_COMPILER */\n\n  return result;\n}\n\nstatic int set_remove(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result;\n  node_t *prev, *next;\n  val_t v;\n  node_t *n;\n\n# ifdef DEBUG\n  printf(\"++> set_remove(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (td == NULL) {\n    prev = set->head;\n    next = prev->next;\n    while (next->val < val) {\n      prev = next;\n      next = prev->next;\n    }\n    result = (next->val == val);\n    if (result) {\n      prev->next = next->next;\n      free(next);\n    }\n  } else if (td->unit_tx == 0) {\n    TM_START(2, RW);\n    prev = (node_t *)TM_LOAD(&set->head);\n    next = (node_t *)TM_LOAD(&prev->next);\n    while (1) {\n      v = TM_LOAD(&next->val);\n      if (v >= val)\n        break;\n      prev = next;\n      next = (node_t *)TM_LOAD(&prev->next);\n    }\n    result = (v == val);\n    if (result) {\n      n = (node_t *)TM_LOAD(&next->next);\n      TM_STORE(&prev->next, n);\n      /* Free memory (delayed until commit) */\n      TM_FREE2(next, sizeof(node_t));\n    }\n    TM_COMMIT;\n  } \n#ifndef TM_COMPILER\n  else {\n    /* Unit transactions */\n    stm_word_t ts, start_ts, val_ts;\n  restart:\n    start_ts = stm_get_clock();\n    /* Head node is never removed */\n    prev = (node_t *)TM_UNIT_LOAD(&set->head, &ts);\n    next = (node_t *)TM_UNIT_LOAD(&prev->next, &ts);\n    if (ts > start_ts)\n      start_ts = ts;\n    while (1) {\n      v = TM_UNIT_LOAD(&next->val, &val_ts);\n      if (val_ts > start_ts) {\n        /* Restart traversal (could also backtrack) */\n        goto restart;\n      }\n      if (v >= val)\n        break;\n      prev = next;\n      next = (node_t *)TM_UNIT_LOAD(&prev->next, &ts);\n      if (ts > start_ts) {\n        /* Verify that node has not been modified (value and pointer are updated together) */\n        TM_UNIT_LOAD(&prev->val, &val_ts);\n        if (val_ts > start_ts) {\n          /* Restart traversal (could also backtrack) */\n          goto restart;\n        }\n        start_ts = ts;\n      }\n    }\n    result = (v == val);\n    if (result) {\n      /* Make sure that the transaction does not access versions more recent than start_ts */\n      TM_START_TS(start_ts, restart);\n      n = (node_t *)TM_LOAD(&next->next);\n      TM_STORE(&prev->next, n);\n      /* Free memory (delayed until commit) */\n      TM_FREE2(next, sizeof(node_t));\n      TM_COMMIT;\n    }\n  }\n#endif /* ! TM_COMPILER */\n  return result;\n}\n\n#elif defined(USE_RBTREE)\n\n/* ################################################################### *\n * RBTREE\n * ################################################################### */\n/* TODO: comparison function as a pointer should be changed for TM compiler\n * (not supported or introduce a lot of overhead). */\n# define INIT_SET_PARAMETERS            /* Nothing */\n\n# define TM_ARGDECL_ALONE               /* Nothing */\n# define TM_ARGDECL                     /* Nothing */\n# define TM_ARG                         /* Nothing */\n# define TM_ARG_ALONE                   /* Nothing */\n# define TM_CALLABLE                    TM_SAFE\n\n# define TM_SHARED_READ(var)            TM_LOAD(&(var))\n# define TM_SHARED_READ_P(var)          TM_LOAD(&(var))\n\n# define TM_SHARED_WRITE(var, val)      TM_STORE(&(var), val)\n# define TM_SHARED_WRITE_P(var, val)    TM_STORE(&(var), val)\n\n# include \"rbtree.h\"\n\n# include \"rbtree.c\"\n\ntypedef struct intset intset_t;\ntypedef intptr_t val_t;\n\nstatic long compare(const void *a, const void *b)\n{\n  return ((val_t)a - (val_t)b);\n}\n\nstatic intset_t *set_new()\n{\n  return (intset_t *)rbtree_alloc(&compare);\n}\n\nstatic void set_delete(intset_t *set)\n{\n  rbtree_free((rbtree_t *)set);\n}\n\nstatic int set_size(intset_t *set)\n{\n  int size;\n  node_t *n;\n\n  if (!rbtree_verify((rbtree_t *)set, 0)) {\n    printf(\"Validation failed!\\n\");\n    exit(1);\n  }\n\n  size = 0;\n  for (n = firstEntry((rbtree_t *)set); n != NULL; n = successor(n))\n    size++;\n\n  return size;\n}\n\nstatic int set_contains(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result;\n\n# ifdef DEBUG\n  printf(\"++> set_contains(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    result = rbtree_contains((rbtree_t *)set, (void *)val);\n  } else {\n    TM_START(0, RO);\n    result = TMrbtree_contains((rbtree_t *)set, (void *)val);\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\nstatic int set_add(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result;\n\n# ifdef DEBUG\n  printf(\"++> set_add(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    result = rbtree_insert((rbtree_t *)set, (void *)val, (void *)val);\n  } else {\n    TM_START(1, RW);\n    result = TMrbtree_insert((rbtree_t *)set, (void *)val, (void *)val);\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\nstatic int set_remove(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result;\n\n# ifdef DEBUG\n  printf(\"++> set_remove(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    result = rbtree_delete((rbtree_t *)set, (void *)val);\n  } else {\n    TM_START(2, RW);\n    result = TMrbtree_delete((rbtree_t *)set, (void *)val);\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\n#elif defined(USE_SKIPLIST)\n\n/* ################################################################### *\n * SKIPLIST\n * ################################################################### */\n\n# define MAX_LEVEL                      64\n\n# define INIT_SET_PARAMETERS            32, 50\n\ntypedef intptr_t val_t;\ntypedef intptr_t level_t;\n# define VAL_MIN                        INT_MIN\n# define VAL_MAX                        INT_MAX\n\ntypedef struct node {\n  val_t val;\n  level_t level;\n  struct node *forward[1];\n} node_t;\n\ntypedef struct intset {\n  node_t *head;\n  node_t *tail;\n  level_t level;\n  int prob;\n  int max_level;\n} intset_t;\n\nTM_PURE\nstatic int random_level(intset_t *set, unsigned short *seed)\n{\n  int l = 0;\n  while (l < set->max_level && rand_range(100, seed) < set->prob)\n    l++;\n  return l;\n}\n\nTM_SAFE\nstatic node_t *new_node(val_t val, level_t level, int transactional)\n{\n  node_t *node;\n\n  if (!transactional) {\n    node = (node_t *)malloc(sizeof(node_t) + level * sizeof(node_t *));\n  } else {\n    node = (node_t *)TM_MALLOC(sizeof(node_t) + level * sizeof(node_t *));\n  }\n  if (node == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n\n  node->val = val;\n  node->level = level;\n\n  return node;\n}\n\nstatic intset_t *set_new(level_t max_level, int prob)\n{\n  intset_t *set;\n  int i;\n\n  assert(max_level <= MAX_LEVEL);\n  assert(prob >= 0 && prob <= 100);\n\n  if ((set = (intset_t *)malloc(sizeof(intset_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  set->max_level = max_level;\n  set->prob = prob;\n  set->level = 0;\n  /* Set head and tail are immutable */\n  set->tail = new_node(VAL_MAX, max_level, 0);\n  set->head = new_node(VAL_MIN, max_level, 0);\n  for (i = 0; i <= max_level; i++) {\n    set->head->forward[i] = set->tail;\n    set->tail->forward[i] = NULL;\n  }\n\n  return set;\n}\n\nstatic void set_delete(intset_t *set)\n{\n  node_t *node, *next;\n\n  node = set->head;\n  while (node != NULL) {\n    next = node->forward[0];\n    free(node);\n    node = next;\n  }\n  free(set);\n}\n\nstatic int set_size(intset_t *set)\n{\n  int size = 0;\n  node_t *node;\n\n  /* We have at least 2 elements */\n  node = set->head->forward[0];\n  while (node->forward[0] != NULL) {\n    size++;\n    node = node->forward[0];\n  }\n\n  return size;\n}\n\nstatic int set_contains(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result, i;\n  node_t *node, *next;\n  val_t v;\n\n# ifdef DEBUG\n  printf(\"++> set_contains(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    node = set->head;\n    for (i = set->level; i >= 0; i--) {\n      next = node->forward[i];\n      while (next->val < val) {\n        node = next;\n        next = node->forward[i];\n      }\n    }\n    node = node->forward[0];\n    result = (node->val == val);\n  } else {\n    TM_START(0, RO);\n    v = VAL_MIN; /* Avoid compiler warning (should not be necessary) */\n    node = set->head;\n    for (i = TM_LOAD(&set->level); i >= 0; i--) {\n      next = (node_t *)TM_LOAD(&node->forward[i]);\n      while (1) {\n        v = TM_LOAD(&next->val);\n        if (v >= val)\n          break;\n        node = next;\n        next = (node_t *)TM_LOAD(&node->forward[i]);\n      }\n    }\n    result = (v == val);\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\nstatic int set_add(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result, i;\n  node_t *update[MAX_LEVEL + 1];\n  node_t *node, *next;\n  level_t level, l;\n  val_t v;\n\n# ifdef DEBUG\n  printf(\"++> set_add(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    node = set->head;\n    for (i = set->level; i >= 0; i--) {\n      next = node->forward[i];\n      while (next->val < val) {\n        node = next;\n        next = node->forward[i];\n      }\n      update[i] = node;\n    }\n    node = node->forward[0];\n\n    if (node->val == val) {\n      result = 0;\n    } else {\n      l = random_level(set, main_seed);\n      if (l > set->level) {\n        for (i = set->level + 1; i <= l; i++)\n          update[i] = set->head;\n        set->level = l;\n      }\n      node = new_node(val, l, 0);\n      for (i = 0; i <= l; i++) {\n        node->forward[i] = update[i]->forward[i];\n        update[i]->forward[i] = node;\n      }\n      result = 1;\n    }\n  } else {\n    TM_START(1, RW);\n    v = VAL_MIN; /* Avoid compiler warning (should not be necessary) */\n    node = set->head;\n    level = TM_LOAD(&set->level);\n    for (i = level; i >= 0; i--) {\n      next = (node_t *)TM_LOAD(&node->forward[i]);\n      while (1) {\n        v = TM_LOAD(&next->val);\n        if (v >= val)\n          break;\n        node = next;\n        next = (node_t *)TM_LOAD(&node->forward[i]);\n      }\n      update[i] = node;\n    }\n\n    if (v == val) {\n      result = 0;\n    } else {\n      l = random_level(set, td->seed);\n      if (l > level) {\n        for (i = level + 1; i <= l; i++)\n          update[i] = set->head;\n        TM_STORE(&set->level, l);\n      }\n      node = new_node(val, l, 1);\n      for (i = 0; i <= l; i++) {\n        node->forward[i] = (node_t *)TM_LOAD(&update[i]->forward[i]);\n        TM_STORE(&update[i]->forward[i], node);\n      }\n      result = 1;\n    }\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\nstatic int set_remove(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result, i;\n  node_t *update[MAX_LEVEL + 1];\n  node_t *node, *next;\n  level_t level;\n  val_t v;\n\n# ifdef DEBUG\n  printf(\"++> set_remove(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    node = set->head;\n    for (i = set->level; i >= 0; i--) {\n      next = node->forward[i];\n      while (next->val < val) {\n        node = next;\n        next = node->forward[i];\n      }\n      update[i] = node;\n    }\n    node = node->forward[0];\n\n    if (node->val != val) {\n      result = 0;\n    } else {\n      for (i = 0; i <= set->level; i++) {\n        if (update[i]->forward[i] == node)\n          update[i]->forward[i] = node->forward[i];\n      }\n      while (set->level > 0 && set->head->forward[set->level]->forward[0] == NULL)\n        set->level--;\n      free(node);\n      result = 1;\n    }\n  } else {\n    TM_START(2, RW);\n    v = VAL_MIN; /* Avoid compiler warning (should not be necessary) */\n    node = set->head;\n    level = TM_LOAD(&set->level);\n    for (i = level; i >= 0; i--) {\n      next = (node_t *)TM_LOAD(&node->forward[i]);\n      while (1) {\n        v = TM_LOAD(&next->val);\n        if (v >= val)\n          break;\n        node = next;\n        next = (node_t *)TM_LOAD(&node->forward[i]);\n      }\n      update[i] = node;\n    }\n    node = (node_t *)TM_LOAD(&node->forward[0]);\n\n    if (v != val) {\n      result = 0;\n    } else {\n      for (i = 0; i <= level; i++) {\n        if ((node_t *)TM_LOAD(&update[i]->forward[i]) == node)\n          TM_STORE(&update[i]->forward[i], (node_t *)TM_LOAD(&node->forward[i]));\n      }\n      i = level;\n      while (i > 0 && (node_t *)TM_LOAD(&set->head->forward[i]) == set->tail)\n        i--;\n      if (i != level)\n        TM_STORE(&set->level, i);\n      /* Free memory (delayed until commit) */\n      TM_FREE2(node, sizeof(node_t) + node->level * sizeof(node_t *));\n      result = 1;\n    }\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\n#elif defined(USE_HASHSET)\n\n/* ################################################################### *\n * HASHSET\n * ################################################################### */\n\n# define INIT_SET_PARAMETERS            /* Nothing */\n\n# define NB_BUCKETS                     (1UL << 17)\n\n# define HASH(a)                        (hash((uint32_t)a) & (NB_BUCKETS - 1))\n\ntypedef intptr_t val_t;\n\ntypedef struct bucket {\n  val_t val;\n  struct bucket *next;\n} bucket_t;\n\ntypedef struct intset {\n  bucket_t **buckets;\n} intset_t;\n\nTM_PURE\nstatic uint32_t hash(uint32_t a)\n{\n  /* Knuth's multiplicative hash function */\n  a *= 2654435761UL;\n  return a;\n}\n\nTM_SAFE\nstatic bucket_t *new_entry(val_t val, bucket_t *next, int transactional)\n{\n  bucket_t *b;\n\n  if (!transactional) {\n    b = (bucket_t *)malloc(sizeof(bucket_t));\n  } else {\n    b = (bucket_t *)TM_MALLOC(sizeof(bucket_t));\n  }\n  if (b == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n\n  b->val = val;\n  b->next = next;\n\n  return b;\n}\n\nstatic intset_t *set_new()\n{\n  intset_t *set;\n\n  if ((set = (intset_t *)malloc(sizeof(intset_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  if ((set->buckets = (bucket_t **)calloc(NB_BUCKETS, sizeof(bucket_t *))) == NULL) {\n    perror(\"calloc\");\n    exit(1);\n  }\n\n  return set;\n}\n\nstatic void set_delete(intset_t *set)\n{\n  unsigned int i;\n  bucket_t *b, *next;\n\n  for (i = 0; i < NB_BUCKETS; i++) {\n    b = set->buckets[i];\n    while (b != NULL) {\n      next = b->next;\n      free(b);\n      b = next;\n    }\n  }\n  free(set->buckets);\n  free(set);\n}\n\nstatic int set_size(intset_t *set)\n{\n  int size = 0;\n  unsigned int i;\n  bucket_t *b;\n\n  for (i = 0; i < NB_BUCKETS; i++) {\n    b = set->buckets[i];\n    while (b != NULL) {\n      size++;\n      b = b->next;\n    }\n  }\n\n  return size;\n}\n\nstatic int set_contains(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result, i;\n  bucket_t *b;\n\n# ifdef DEBUG\n  printf(\"++> set_contains(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    i = HASH(val);\n    b = set->buckets[i];\n    result = 0;\n    while (b != NULL) {\n      if (b->val == val) {\n        result = 1;\n        break;\n      }\n      b = b->next;\n    }\n  } else {\n    TM_START(0, RO);\n    i = HASH(val);\n    b = (bucket_t *)TM_LOAD(&set->buckets[i]);\n    result = 0;\n    while (b != NULL) {\n      if (TM_LOAD(&b->val) == val) {\n        result = 1;\n        break;\n      }\n      b = (bucket_t *)TM_LOAD(&b->next);\n    }\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\nstatic int set_add(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result, i;\n  bucket_t *b, *first;\n\n# ifdef DEBUG\n  printf(\"++> set_add(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    i = HASH(val);\n    first = b = set->buckets[i];\n    result = 1;\n    while (b != NULL) {\n      if (b->val == val) {\n        result = 0;\n        break;\n      }\n      b = b->next;\n    }\n    if (result) {\n      set->buckets[i] = new_entry(val, first, 0);\n    }\n  } else {\n    TM_START(0, RW);\n    i = HASH(val);\n    first = b = (bucket_t *)TM_LOAD(&set->buckets[i]);\n    result = 1;\n    while (b != NULL) {\n      if (TM_LOAD(&b->val) == val) {\n        result = 0;\n        break;\n      }\n      b = (bucket_t *)TM_LOAD(&b->next);\n    }\n    if (result) {\n      TM_STORE(&set->buckets[i], new_entry(val, first, 1));\n    }\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\nstatic int set_remove(intset_t *set, val_t val, thread_data_t *td)\n{\n  int result, i;\n  bucket_t *b, *prev;\n\n# ifdef DEBUG\n  printf(\"++> set_remove(%d)\\n\", val);\n  IO_FLUSH;\n# endif\n\n  if (!td) {\n    i = HASH(val);\n    prev = b = set->buckets[i];\n    result = 0;\n    while (b != NULL) {\n      if (b->val == val) {\n        result = 1;\n        break;\n      }\n      prev = b;\n      b = b->next;\n    }\n    if (result) {\n      if (prev == b) {\n        /* First element of bucket */\n        set->buckets[i] = b->next;\n      } else {\n        prev->next = b->next;\n      }\n      free(b);\n    }\n  } else {\n    TM_START(0, RW);\n    i = HASH(val);\n    prev = b = (bucket_t *)TM_LOAD(&set->buckets[i]);\n    result = 0;\n    while (b != NULL) {\n      if (TM_LOAD(&b->val) == val) {\n        result = 1;\n        break;\n      }\n      prev = b;\n      b = (bucket_t *)TM_LOAD(&b->next);\n    }\n    if (result) {\n      if (prev == b) {\n        /* First element of bucket */\n        TM_STORE(&set->buckets[i], TM_LOAD(&b->next));\n      } else {\n        TM_STORE(&prev->next, TM_LOAD(&b->next));\n      }\n      /* Free memory (delayed until commit) */\n      TM_FREE2(b, sizeof(bucket_t));\n    }\n    TM_COMMIT;\n  }\n\n  return result;\n}\n\n#endif /* defined(USE_HASHSET) */\n\n/* ################################################################### *\n * BARRIER\n * ################################################################### */\n\ntypedef struct barrier {\n  pthread_cond_t complete;\n  pthread_mutex_t mutex;\n  int count;\n  int crossing;\n} barrier_t;\n\nstatic void barrier_init(barrier_t *b, int n)\n{\n  pthread_cond_init(&b->complete, NULL);\n  pthread_mutex_init(&b->mutex, NULL);\n  b->count = n;\n  b->crossing = 0;\n}\n\nstatic void barrier_cross(barrier_t *b)\n{\n  pthread_mutex_lock(&b->mutex);\n  /* One more thread through */\n  b->crossing++;\n  /* If not all here, wait */\n  if (b->crossing < b->count) {\n    pthread_cond_wait(&b->complete, &b->mutex);\n  } else {\n    pthread_cond_broadcast(&b->complete);\n    /* Reset for next time */\n    b->crossing = 0;\n  }\n  pthread_mutex_unlock(&b->mutex);\n}\n\n/* ################################################################### *\n * STRESS TEST\n * ################################################################### */\n\nstatic void *test(void *data)\n{\n  int op, val, last = -1;\n  thread_data_t *d = (thread_data_t *)data;\n\n  /* Create transaction */\n  TM_INIT_THREAD;\n  /* Wait on barrier */\n  barrier_cross(d->barrier);\n\n  while (stop == 0) {\n    op = rand_range(100, d->seed);\n    if (op < d->update) {\n      if (d->alternate) {\n        /* Alternate insertions and removals */\n        if (last < 0) {\n          /* Add random value */\n          val = rand_range(d->range, d->seed) + 1;\n          if (set_add(d->set, val, d)) {\n            d->diff++;\n            last = val;\n          }\n          d->nb_add++;\n        } else {\n          /* Remove last value */\n          if (set_remove(d->set, last, d))\n            d->diff--;\n          d->nb_remove++;\n          last = -1;\n        }\n      } else {\n        /* Randomly perform insertions and removals */\n        val = rand_range(d->range, d->seed) + 1;\n        if ((op & 0x01) == 0) {\n          /* Add random value */\n          if (set_add(d->set, val, d))\n            d->diff++;\n          d->nb_add++;\n        } else {\n          /* Remove random value */\n          if (set_remove(d->set, val, d))\n            d->diff--;\n          d->nb_remove++;\n        }\n      }\n    } else {\n      /* Look for random value */\n      val = rand_range(d->range, d->seed) + 1;\n      if (set_contains(d->set, val, d))\n        d->nb_found++;\n      d->nb_contains++;\n    }\n  }\n#ifndef TM_COMPILER\n  stm_get_stats(\"nb_aborts\", &d->nb_aborts);\n  stm_get_stats(\"nb_aborts_1\", &d->nb_aborts_1);\n  stm_get_stats(\"nb_aborts_2\", &d->nb_aborts_2);\n  stm_get_stats(\"nb_aborts_locked_read\", &d->nb_aborts_locked_read);\n  stm_get_stats(\"nb_aborts_locked_write\", &d->nb_aborts_locked_write);\n  stm_get_stats(\"nb_aborts_validate_read\", &d->nb_aborts_validate_read);\n  stm_get_stats(\"nb_aborts_validate_write\", &d->nb_aborts_validate_write);\n  stm_get_stats(\"nb_aborts_validate_commit\", &d->nb_aborts_validate_commit);\n  stm_get_stats(\"nb_aborts_invalid_memory\", &d->nb_aborts_invalid_memory);\n  stm_get_stats(\"nb_aborts_killed\", &d->nb_aborts_killed);\n  stm_get_stats(\"locked_reads_ok\", &d->locked_reads_ok);\n  stm_get_stats(\"locked_reads_failed\", &d->locked_reads_failed);\n  stm_get_stats(\"max_retries\", &d->max_retries);\n#endif /* ! TM_COMPILER */\n  /* Free transaction */\n  TM_EXIT_THREAD;\n\n  return NULL;\n}\n\nint main(int argc, char **argv)\n{\n  struct option long_options[] = {\n    // These options don't set a flag\n    {\"help\",                      no_argument,       NULL, 'h'},\n    {\"do-not-alternate\",          no_argument,       NULL, 'a'},\n#ifndef TM_COMPILER\n    {\"contention-manager\",        required_argument, NULL, 'c'},\n#endif /* ! TM_COMPILER */\n    {\"duration\",                  required_argument, NULL, 'd'},\n    {\"initial-size\",              required_argument, NULL, 'i'},\n    {\"num-threads\",               required_argument, NULL, 'n'},\n    {\"range\",                     required_argument, NULL, 'r'},\n    {\"seed\",                      required_argument, NULL, 's'},\n    {\"update-rate\",               required_argument, NULL, 'u'},\n#ifdef USE_LINKEDLIST\n    {\"unit-tx\",                   no_argument,       NULL, 'x'},\n#endif /* LINKEDLIST */\n    {NULL, 0, NULL, 0}\n  };\n\n  intset_t *set;\n  int i, c, val, size, ret;\n  unsigned long reads, updates;\n#ifndef TM_COMPILER\n  char *s;\n  unsigned long aborts, aborts_1, aborts_2,\n    aborts_locked_read, aborts_locked_write,\n    aborts_validate_read, aborts_validate_write, aborts_validate_commit,\n    aborts_invalid_memory, aborts_killed,\n    locked_reads_ok, locked_reads_failed, max_retries;\n  stm_ab_stats_t ab_stats;\n#endif /* ! TM_COMPILER */\n  thread_data_t *data;\n  pthread_t *threads;\n  pthread_attr_t attr;\n  barrier_t barrier;\n  struct timeval start, end;\n  struct timespec timeout;\n  int duration = DEFAULT_DURATION;\n  int initial = DEFAULT_INITIAL;\n  int nb_threads = DEFAULT_NB_THREADS;\n  int range = DEFAULT_RANGE;\n  int seed = DEFAULT_SEED;\n  int update = DEFAULT_UPDATE;\n  int alternate = 1;\n#ifndef TM_COMPILER\n  char *cm = NULL;\n#endif /* ! TM_COMPILER */\n#ifdef USE_LINKEDLIST\n  int unit_tx = 0;\n#endif /* LINKEDLIST */\n  sigset_t block_set;\n\n  while(1) {\n    i = 0;\n    c = getopt_long(argc, argv, \"ha\"\n#ifndef TM_COMPILER\n                    \"c:\"\n#endif /* ! TM_COMPILER */\n                    \"d:i:n:r:s:u:\"\n#ifdef USE_LINKEDLIST\n                    \"x\"\n#endif /* LINKEDLIST */\n                    , long_options, &i);\n\n    if(c == -1)\n      break;\n\n    if(c == 0 && long_options[i].flag == 0)\n      c = long_options[i].val;\n\n    switch(c) {\n     case 0:\n       /* Flag is automatically set */\n       break;\n     case 'h':\n       printf(\"intset -- STM stress test \"\n#if defined(USE_LINKEDLIST)\n              \"(linked list)\\n\"\n#elif defined(USE_RBTREE)\n              \"(red-black tree)\\n\"\n#elif defined(USE_SKIPLIST)\n              \"(skip list)\\n\"\n#elif defined(USE_HASHSET)\n              \"(hash set)\\n\"\n#endif /* defined(USE_HASHSET) */\n              \"\\n\"\n              \"Usage:\\n\"\n              \"  intset [options...]\\n\"\n              \"\\n\"\n              \"Options:\\n\"\n              \"  -h, --help\\n\"\n              \"        Print this message\\n\"\n              \"  -a, --do-not-alternate\\n\"\n              \"        Do not alternate insertions and removals\\n\"\n#ifndef TM_COMPILER\n\t      \"  -c, --contention-manager <string>\\n\"\n              \"        Contention manager for resolving conflicts (default=suicide)\\n\"\n#endif /* ! TM_COMPILER */\n\t      \"  -d, --duration <int>\\n\"\n              \"        Test duration in milliseconds (0=infinite, default=\" XSTR(DEFAULT_DURATION) \")\\n\"\n              \"  -i, --initial-size <int>\\n\"\n              \"        Number of elements to insert before test (default=\" XSTR(DEFAULT_INITIAL) \")\\n\"\n              \"  -n, --num-threads <int>\\n\"\n              \"        Number of threads (default=\" XSTR(DEFAULT_NB_THREADS) \")\\n\"\n              \"  -r, --range <int>\\n\"\n              \"        Range of integer values inserted in set (default=\" XSTR(DEFAULT_RANGE) \")\\n\"\n              \"  -s, --seed <int>\\n\"\n              \"        RNG seed (0=time-based, default=\" XSTR(DEFAULT_SEED) \")\\n\"\n              \"  -u, --update-rate <int>\\n\"\n              \"        Percentage of update transactions (default=\" XSTR(DEFAULT_UPDATE) \")\\n\"\n#ifdef USE_LINKEDLIST\n              \"  -x, --unit-tx\\n\"\n              \"        Use unit transactions\\n\"\n#endif /* LINKEDLIST */\n         );\n       exit(0);\n     case 'a':\n       alternate = 0;\n       break;\n#ifndef TM_COMPILER\n     case 'c':\n       cm = optarg;\n       break;\n#endif /* ! TM_COMPILER */\n     case 'd':\n       duration = atoi(optarg);\n       break;\n     case 'i':\n       initial = atoi(optarg);\n       break;\n     case 'n':\n       nb_threads = atoi(optarg);\n       break;\n     case 'r':\n       range = atoi(optarg);\n       break;\n     case 's':\n       seed = atoi(optarg);\n       break;\n     case 'u':\n       update = atoi(optarg);\n       break;\n#ifdef USE_LINKEDLIST\n     case 'x':\n       unit_tx++;\n       break;\n#endif /* LINKEDLIST */\n     case '?':\n       printf(\"Use -h or --help for help\\n\");\n       exit(0);\n     default:\n       exit(1);\n    }\n  }\n\n  assert(duration >= 0);\n  assert(initial >= 0);\n  assert(nb_threads > 0);\n  assert(range > 0 && range >= initial);\n  assert(update >= 0 && update <= 100);\n\n#if defined(USE_LINKEDLIST)\n  printf(\"Set type     : linked list\\n\");\n#elif defined(USE_RBTREE)\n  printf(\"Set type     : red-black tree\\n\");\n#elif defined(USE_SKIPLIST)\n  printf(\"Set type     : skip list\\n\");\n#elif defined(USE_HASHSET)\n  printf(\"Set type     : hash set\\n\");\n#endif /* defined(USE_HASHSET) */\n#ifndef TM_COMPILER\n  printf(\"CM           : %s\\n\", (cm == NULL ? \"DEFAULT\" : cm));\n#endif /* ! TM_COMPILER */\n  printf(\"Duration     : %d\\n\", duration);\n  printf(\"Initial size : %d\\n\", initial);\n  printf(\"Nb threads   : %d\\n\", nb_threads);\n  printf(\"Value range  : %d\\n\", range);\n  printf(\"Seed         : %d\\n\", seed);\n  printf(\"Update rate  : %d\\n\", update);\n  printf(\"Alternate    : %d\\n\", alternate);\n#ifdef USE_LINKEDLIST\n  printf(\"Unit tx      : %d\\n\", unit_tx);\n#endif /* LINKEDLIST */\n  printf(\"Type sizes   : int=%d/long=%d/ptr=%d/word=%d\\n\",\n         (int)sizeof(int),\n         (int)sizeof(long),\n         (int)sizeof(void *),\n         (int)sizeof(size_t));\n\n  timeout.tv_sec = duration / 1000;\n  timeout.tv_nsec = (duration % 1000) * 1000000;\n\n  if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n\n  if (seed == 0)\n    srand((int)time(NULL));\n  else\n    srand(seed);\n\n  set = set_new(INIT_SET_PARAMETERS);\n\n  stop = 0;\n\n  /* Thread-local seed for main thread */\n  rand_init(main_seed);\n\n  /* Init STM */\n  printf(\"Initializing STM\\n\");\n  TM_INIT;\n\n#ifndef TM_COMPILER\n  if (stm_get_parameter(\"compile_flags\", &s))\n    printf(\"STM flags    : %s\\n\", s);\n\n  if (cm != NULL) {\n    if (stm_set_parameter(\"cm_policy\", cm) == 0)\n      printf(\"WARNING: cannot set contention manager \\\"%s\\\"\\n\", cm);\n  }\n#endif /* ! TM_COMPILER */\n  if (alternate == 0 && range != initial * 2)\n    printf(\"WARNING: range is not twice the initial set size\\n\");\n\n  /* Populate set */\n  printf(\"Adding %d entries to set\\n\", initial);\n  i = 0;\n  while (i < initial) {\n    val = rand_range(range, main_seed) + 1;\n    if (set_add(set, val, 0))\n      i++;\n  }\n  size = set_size(set);\n  printf(\"Set size     : %d\\n\", size);\n\n  /* Access set from all threads */\n  barrier_init(&barrier, nb_threads + 1);\n  pthread_attr_init(&attr);\n  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);\n  for (i = 0; i < nb_threads; i++) {\n    printf(\"Creating thread %d\\n\", i);\n    data[i].range = range;\n    data[i].update = update;\n    data[i].alternate = alternate;\n#ifdef USE_LINKEDLIST\n    data[i].unit_tx = unit_tx;\n#endif /* LINKEDLIST */\n    data[i].nb_add = 0;\n    data[i].nb_remove = 0;\n    data[i].nb_contains = 0;\n    data[i].nb_found = 0;\n#ifndef TM_COMPILER\n    data[i].nb_aborts = 0;\n    data[i].nb_aborts_1 = 0;\n    data[i].nb_aborts_2 = 0;\n    data[i].nb_aborts_locked_read = 0;\n    data[i].nb_aborts_locked_write = 0;\n    data[i].nb_aborts_validate_read = 0;\n    data[i].nb_aborts_validate_write = 0;\n    data[i].nb_aborts_validate_commit = 0;\n    data[i].nb_aborts_invalid_memory = 0;\n    data[i].nb_aborts_killed = 0;\n    data[i].locked_reads_ok = 0;\n    data[i].locked_reads_failed = 0;\n    data[i].max_retries = 0;\n#endif /* ! TM_COMPILER */\n    data[i].diff = 0;\n    rand_init(data[i].seed);\n    data[i].set = set;\n    data[i].barrier = &barrier;\n    if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) {\n      fprintf(stderr, \"Error creating thread\\n\");\n      exit(1);\n    }\n  }\n  pthread_attr_destroy(&attr);\n\n  /* Start threads */\n  barrier_cross(&barrier);\n\n  printf(\"STARTING...\\n\");\n  gettimeofday(&start, NULL);\n  if (duration > 0) {\n    nanosleep(&timeout, NULL);\n  } else {\n    sigemptyset(&block_set);\n    sigsuspend(&block_set);\n  }\n  stop = 1;\n  gettimeofday(&end, NULL);\n  printf(\"STOPPING...\\n\");\n\n  /* Wait for thread completion */\n  for (i = 0; i < nb_threads; i++) {\n    if (pthread_join(threads[i], NULL) != 0) {\n      fprintf(stderr, \"Error waiting for thread completion\\n\");\n      exit(1);\n    }\n  }\n\n  duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);\n#ifndef TM_COMPILER\n  aborts = 0;\n  aborts_1 = 0;\n  aborts_2 = 0;\n  aborts_locked_read = 0;\n  aborts_locked_write = 0;\n  aborts_validate_read = 0;\n  aborts_validate_write = 0;\n  aborts_validate_commit = 0;\n  aborts_invalid_memory = 0;\n  aborts_killed = 0;\n  locked_reads_ok = 0;\n  locked_reads_failed = 0;\n  max_retries = 0;\n#endif /* ! TM_COMPILER */\n  reads = 0;\n  updates = 0;\n  for (i = 0; i < nb_threads; i++) {\n    printf(\"Thread %d\\n\", i);\n    printf(\"  #add        : %lu\\n\", data[i].nb_add);\n    printf(\"  #remove     : %lu\\n\", data[i].nb_remove);\n    printf(\"  #contains   : %lu\\n\", data[i].nb_contains);\n    printf(\"  #found      : %lu\\n\", data[i].nb_found);\n#ifndef TM_COMPILER\n    printf(\"  #aborts     : %lu\\n\", data[i].nb_aborts);\n    printf(\"    #lock-r   : %lu\\n\", data[i].nb_aborts_locked_read);\n    printf(\"    #lock-w   : %lu\\n\", data[i].nb_aborts_locked_write);\n    printf(\"    #val-r    : %lu\\n\", data[i].nb_aborts_validate_read);\n    printf(\"    #val-w    : %lu\\n\", data[i].nb_aborts_validate_write);\n    printf(\"    #val-c    : %lu\\n\", data[i].nb_aborts_validate_commit);\n    printf(\"    #inv-mem  : %lu\\n\", data[i].nb_aborts_invalid_memory);\n    printf(\"    #killed   : %lu\\n\", data[i].nb_aborts_killed);\n    printf(\"  #aborts>=1  : %lu\\n\", data[i].nb_aborts_1);\n    printf(\"  #aborts>=2  : %lu\\n\", data[i].nb_aborts_2);\n    printf(\"  #lr-ok      : %lu\\n\", data[i].locked_reads_ok);\n    printf(\"  #lr-failed  : %lu\\n\", data[i].locked_reads_failed);\n    printf(\"  Max retries : %lu\\n\", data[i].max_retries);\n    aborts += data[i].nb_aborts;\n    aborts_1 += data[i].nb_aborts_1;\n    aborts_2 += data[i].nb_aborts_2;\n    aborts_locked_read += data[i].nb_aborts_locked_read;\n    aborts_locked_write += data[i].nb_aborts_locked_write;\n    aborts_validate_read += data[i].nb_aborts_validate_read;\n    aborts_validate_write += data[i].nb_aborts_validate_write;\n    aborts_validate_commit += data[i].nb_aborts_validate_commit;\n    aborts_invalid_memory += data[i].nb_aborts_invalid_memory;\n    aborts_killed += data[i].nb_aborts_killed;\n    locked_reads_ok += data[i].locked_reads_ok;\n    locked_reads_failed += data[i].locked_reads_failed;\n    if (max_retries < data[i].max_retries)\n      max_retries = data[i].max_retries;\n#endif /* ! TM_COMPILER */\n    reads += data[i].nb_contains;\n    updates += (data[i].nb_add + data[i].nb_remove);\n    size += data[i].diff;\n  }\n  printf(\"Set size      : %d (expected: %d)\\n\", set_size(set), size);\n  ret = (set_size(set) != size);\n  printf(\"Duration      : %d (ms)\\n\", duration);\n  printf(\"#txs          : %lu (%f / s)\\n\", reads + updates, (reads + updates) * 1000.0 / duration);\n  printf(\"#read txs     : %lu (%f / s)\\n\", reads, reads * 1000.0 / duration);\n  printf(\"#update txs   : %lu (%f / s)\\n\", updates, updates * 1000.0 / duration);\n#ifndef TM_COMPILER\n  printf(\"#aborts       : %lu (%f / s)\\n\", aborts, aborts * 1000.0 / duration);\n  printf(\"  #lock-r     : %lu (%f / s)\\n\", aborts_locked_read, aborts_locked_read * 1000.0 / duration);\n  printf(\"  #lock-w     : %lu (%f / s)\\n\", aborts_locked_write, aborts_locked_write * 1000.0 / duration);\n  printf(\"  #val-r      : %lu (%f / s)\\n\", aborts_validate_read, aborts_validate_read * 1000.0 / duration);\n  printf(\"  #val-w      : %lu (%f / s)\\n\", aborts_validate_write, aborts_validate_write * 1000.0 / duration);\n  printf(\"  #val-c      : %lu (%f / s)\\n\", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration);\n  printf(\"  #inv-mem    : %lu (%f / s)\\n\", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration);\n  printf(\"  #killed     : %lu (%f / s)\\n\", aborts_killed, aborts_killed * 1000.0 / duration);\n  printf(\"#aborts>=1    : %lu (%f / s)\\n\", aborts_1, aborts_1 * 1000.0 / duration);\n  printf(\"#aborts>=2    : %lu (%f / s)\\n\", aborts_2, aborts_2 * 1000.0 / duration);\n  printf(\"#lr-ok        : %lu (%f / s)\\n\", locked_reads_ok, locked_reads_ok * 1000.0 / duration);\n  printf(\"#lr-failed    : %lu (%f / s)\\n\", locked_reads_failed, locked_reads_failed * 1000.0 / duration);\n  printf(\"Max retries   : %lu\\n\", max_retries);\n\n  for (i = 0; stm_get_ab_stats(i, &ab_stats) != 0; i++) {\n    printf(\"Atomic block  : %d\\n\", i);\n    printf(\"  #samples    : %lu\\n\", ab_stats.samples);\n    printf(\"  Mean        : %f\\n\", ab_stats.mean);\n    printf(\"  Variance    : %f\\n\", ab_stats.variance);\n    printf(\"  Min         : %f\\n\", ab_stats.min); \n    printf(\"  Max         : %f\\n\", ab_stats.max);\n    printf(\"  50th perc.  : %f\\n\", ab_stats.percentile_50);\n    printf(\"  90th perc.  : %f\\n\", ab_stats.percentile_90);\n    printf(\"  95th perc.  : %f\\n\", ab_stats.percentile_95);\n  }\n#endif /* ! TM_COMPILER */\n\n  /* Delete set */\n  set_delete(set);\n\n  /* Cleanup STM */\n  TM_EXIT;\n\n  free(threads);\n  free(data);\n\n  return ret;\n}\n"
  },
  {
    "path": "stms/tinystm/test/intset/rbtree.c",
    "content": "/* =============================================================================\n *\n * rbtree.c\n * -- Red-black balanced binary search tree\n *\n * =============================================================================\n *\n * Copyright (C) Sun Microsystems Inc., 2006.  All Rights Reserved.\n * Authors: Dave Dice, Nir Shavit, Ori Shalev.\n *\n * STM: Transactional Locking for Disjoint Access Parallelism\n *\n * Transactional Locking II,\n * Dave Dice, Ori Shalev, Nir Shavit\n * DISC 2006, Sept 2006, Stockholm, Sweden.\n *\n * =============================================================================\n *\n * Modified by Chi Cao Minh, Aug 2006\n *\n * =============================================================================\n *\n * For the license of bayes/sort.h and bayes/sort.c, please see the header\n * of the files.\n * \n * ------------------------------------------------------------------------\n * \n * For the license of kmeans, please see kmeans/LICENSE.kmeans\n * \n * ------------------------------------------------------------------------\n * \n * For the license of ssca2, please see ssca2/COPYRIGHT\n * \n * ------------------------------------------------------------------------\n * \n * For the license of lib/mt19937ar.c and lib/mt19937ar.h, please see the\n * header of the files.\n * \n * ------------------------------------------------------------------------\n * \n * For the license of lib/rbtree.h and lib/rbtree.c, please see\n * lib/LEGALNOTICE.rbtree and lib/LICENSE.rbtree\n * \n * ------------------------------------------------------------------------\n * \n * Unless otherwise noted, the following license applies to STAMP files:\n * \n * Copyright (c) 2007, Stanford University\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n * \n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n * \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in\n *       the documentation and/or other materials provided with the\n *       distribution.\n * \n *     * Neither the name of Stanford University nor the names of its\n *       contributors may be used to endorse or promote products derived\n *       from this software without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n *\n * =============================================================================\n */\n\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <inttypes.h>\n#include \"memory.h\"\n#include \"rbtree.h\"\n#include \"tm.h\"\n\n\ntypedef struct node {\n    void* k;\n    void* v;\n    struct node* p;\n    struct node* l;\n    struct node* r;\n    long c;\n} node_t;\n\n\nstruct rbtree {\n    node_t* root;\n    /* TODO Check if set TM_PURE or use directly the function */\n    TM_PURE\n    long (*compare)(const void*, const void*);   /* returns {-1,0,1}, 0 -> equal */\n};\n\n#define LDA(a)              *(a)\n#define STA(a,v)            *(a) = (v)\n#define LDV(a)              (a)\n#define STV(a,v)            (a) = (v)\n#define LDF(o,f)            ((o)->f)\n#define STF(o,f,v)          ((o)->f) = (v)\n#define LDNODE(o,f)         ((node_t*)(LDF((o),f)))\n\n#define TX_LDA(a)           TM_SHARED_READ(*(a))\n#define TX_STA(a,v)         TM_SHARED_WRITE(*(a), v)\n#define TX_LDV(a)           TM_SHARED_READ(a)\n#define TX_STV(a,v)         TM_SHARED_WRITE_P(a, v)\n#define TX_LDF(o,f)         ((long)TM_SHARED_READ((o)->f))\n#define TX_LDF_P(o,f)       ((void*)TM_SHARED_READ_P((o)->f))\n#define TX_STF(o,f,v)       TM_SHARED_WRITE((o)->f, v)\n#define TX_STF_P(o,f,v)     TM_SHARED_WRITE_P((o)->f, v)\n#define TX_LDNODE(o,f)      ((node_t*)(TX_LDF_P((o),f)))\n\n/* =============================================================================\n * DECLARATION OF TM_CALLABLE FUNCTIONS\n * =============================================================================\n */\n\nTM_CALLABLE\nstatic node_t*\nTMlookup (TM_ARGDECL  rbtree_t* s, void* k);\n\nTM_CALLABLE\nstatic void\nTMrotateLeft (TM_ARGDECL  rbtree_t* s, node_t* x);\n\nTM_CALLABLE\nstatic void\nTMrotateRight (TM_ARGDECL  rbtree_t* s, node_t* x);\n\nTM_CALLABLE\nstatic inline node_t*\nTMparentOf (TM_ARGDECL  node_t* n);\n\nTM_CALLABLE\nstatic inline node_t*\nTMleftOf (TM_ARGDECL  node_t* n);\n\nTM_CALLABLE\nstatic inline node_t*\nTMrightOf (TM_ARGDECL  node_t* n);\n\nTM_CALLABLE\nstatic inline long\nTMcolorOf (TM_ARGDECL  node_t* n);\n\nTM_CALLABLE\nstatic inline void\nTMsetColor (TM_ARGDECL  node_t* n, long c);\n\nTM_CALLABLE\nstatic void\nTMfixAfterInsertion (TM_ARGDECL  rbtree_t* s, node_t* x);\n\nTM_CALLABLE\nstatic node_t*\nTMsuccessor  (TM_ARGDECL  node_t* t);\n\nTM_CALLABLE\nstatic void\nTMfixAfterDeletion  (TM_ARGDECL  rbtree_t* s, node_t*  x);\n\nTM_CALLABLE\nstatic node_t*\nTMinsert (TM_ARGDECL  rbtree_t* s, void* k, void* v, node_t* n);\n\nTM_CALLABLE\nstatic node_t*\nTMgetNode (TM_ARGDECL_ALONE);\n\nTM_CALLABLE\nstatic node_t*\nTMdelete (TM_ARGDECL  rbtree_t* s, node_t* p);\n\nTM_CALLABLE\nstatic void\nTMreleaseNode (TM_ARGDECL  node_t* n);\n\nenum {\n    RED   = 0,\n    BLACK = 1\n};\n\n\n/*\n * See also:\n * - Doug Lea's j.u.TreeMap\n * - Keir Fraser's rb_stm.c and rb_lock_serialisedwriters.c in libLtx.\n *\n * Following Doug Lea's TreeMap example, we avoid the use of the magic\n * \"nil\" sentinel pointers.  The sentinel is simply a convenience and\n * is not fundamental to the algorithm.  We forgo the sentinel as\n * it is a source of false+ data conflicts in transactions.  Relatedly,\n * even with locks, use of a nil sentil can result in considerable\n * cache coherency traffic on traditional SMPs.\n */\n\n\n/* =============================================================================\n * lookup\n * =============================================================================\n */\nstatic node_t*\nlookup (rbtree_t* s, void* k)\n{\n    node_t* p = LDNODE(s, root);\n\n    while (p != NULL) {\n        long cmp = s->compare(k, LDF(p, k));\n        if (cmp == 0) {\n            return p;\n        }\n        p = ((cmp < 0) ? LDNODE(p, l) : LDNODE(p, r));\n    }\n\n    return NULL;\n}\n#define LOOKUP(set, key)  lookup(set, key)\n\n\n/* =============================================================================\n * TMlookup\n * =============================================================================\n */\nstatic node_t*\nTMlookup (TM_ARGDECL  rbtree_t* s, void* k)\n{\n    node_t* p = TX_LDNODE(s, root);\n\n    while (p != NULL) {\n        long cmp = s->compare(k, TX_LDF_P(p, k));\n        if (cmp == 0) {\n            return p;\n        }\n        p = ((cmp < 0) ? TX_LDNODE(p, l) : TX_LDNODE(p, r));\n    }\n\n    return NULL;\n}\n#define TX_LOOKUP(set, key)  TMlookup(TM_ARG  set, key)\n\n\n/*\n * Balancing operations.\n *\n * Implementations of rebalancings during insertion and deletion are\n * slightly different than the CLR version.  Rather than using dummy\n * nilnodes, we use a set of accessors that deal properly with null.  They\n * are used to avoid messiness surrounding nullness checks in the main\n * algorithms.\n *\n * From CLR\n */\n\n\n/* =============================================================================\n * rotateLeft\n * =============================================================================\n */\nstatic void\nrotateLeft (rbtree_t* s, node_t* x)\n{\n    node_t* r = LDNODE(x, r); /* AKA r, y */\n    node_t* rl = LDNODE(r, l);\n    STF(x, r, rl);\n    if (rl != NULL) {\n        STF(rl, p, x);\n    }\n    /* TODO: compute p = xp = x->p.  Use xp for R-Values in following */\n    node_t* xp = LDNODE(x, p);\n    STF(r, p, xp);\n    if (xp == NULL) {\n        STF(s, root, r);\n    } else if (LDNODE(xp, l) == x) {\n        STF(xp, l, r);\n    } else {\n        STF(xp, r, r);\n    }\n    STF(r, l, x);\n    STF(x, p, r);\n}\n#define ROTATE_LEFT(set, node)  rotateLeft(set, node)\n\n\n/* =============================================================================\n * TMrotateLeft\n * =============================================================================\n */\nstatic void\nTMrotateLeft (TM_ARGDECL  rbtree_t* s, node_t* x)\n{\n    node_t* r = TX_LDNODE(x, r); /* AKA r, y */\n    node_t* rl = TX_LDNODE(r, l);\n    TX_STF_P(x, r, rl);\n    if (rl != NULL) {\n        TX_STF_P(rl, p, x);\n    }\n    /* TODO: compute p = xp = x->p.  Use xp for R-Values in following */\n    node_t* xp = TX_LDNODE(x, p);\n    TX_STF_P(r, p, xp);\n    if (xp == NULL) {\n        TX_STF_P(s, root, r);\n    } else if (TX_LDNODE(xp, l) == x) {\n        TX_STF_P(xp, l, r);\n    } else {\n        TX_STF_P(xp, r, r);\n    }\n    TX_STF_P(r, l, x);\n    TX_STF_P(x, p, r);\n}\n#define TX_ROTATE_LEFT(set, node)  TMrotateLeft(TM_ARG  set, node)\n\n\n/* =============================================================================\n * rotateRight\n * =============================================================================\n */\nstatic void\nrotateRight (rbtree_t* s, node_t* x)\n{\n    node_t* l = LDNODE(x, l); /* AKA l,y */\n    node_t* lr = LDNODE(l, r);\n    STF(x, l, lr);\n    if (lr != NULL) {\n        STF(lr, p, x);\n    }\n    node_t* xp = LDNODE(x, p);\n    STF(l, p, xp);\n    if (xp == NULL) {\n        STF(s, root, l);\n    } else if (LDNODE(xp, r) == x) {\n        STF(xp, r, l);\n    } else {\n        STF(xp, l, l);\n    }\n    STF(l, r, x);\n    STF(x, p, l);\n}\n#define ROTATE_RIGHT(set, node)  rotateRight(set, node)\n\n\n/* =============================================================================\n * TMrotateRight\n * =============================================================================\n */\nstatic void\nTMrotateRight (TM_ARGDECL  rbtree_t* s, node_t* x)\n{\n    node_t* l = TX_LDNODE(x, l); /* AKA l,y */\n    node_t* lr = TX_LDNODE(l, r);\n    TX_STF_P(x, l, lr);\n    if (lr != NULL) {\n        TX_STF_P(lr, p, x);\n    }\n    node_t* xp = TX_LDNODE(x, p);\n    TX_STF_P(l, p, xp);\n    if (xp == NULL) {\n        TX_STF_P(s, root, l);\n    } else if (TX_LDNODE(xp, r) == x) {\n        TX_STF_P(xp, r, l);\n    } else {\n        TX_STF_P(xp, l, l);\n    }\n    TX_STF_P(l, r, x);\n    TX_STF_P(x, p, l);\n}\n#define TX_ROTATE_RIGHT(set, node)  TMrotateRight(TM_ARG  set, node)\n\n\n/* =============================================================================\n * parentOf\n * =============================================================================\n */\nstatic inline node_t*\nparentOf (node_t* n)\n{\n   return (n ? LDNODE(n,p) : NULL);\n}\n#define PARENT_OF(n) parentOf(n)\n\n\n/* =============================================================================\n * TMparentOf\n * =============================================================================\n */\nstatic inline node_t*\nTMparentOf (TM_ARGDECL  node_t* n)\n{\n   return (n ? TX_LDNODE(n,p) : NULL);\n}\n#define TX_PARENT_OF(n)  TMparentOf(TM_ARG  n)\n\n\n/* =============================================================================\n * leftOf\n * =============================================================================\n */\nstatic inline node_t*\nleftOf (node_t* n)\n{\n   return (n ? LDNODE(n, l) : NULL);\n}\n#define LEFT_OF(n)  leftOf(n)\n\n\n/* =============================================================================\n * TMleftOf\n * =============================================================================\n */\nstatic inline node_t*\nTMleftOf (TM_ARGDECL  node_t* n)\n{\n   return (n ? TX_LDNODE(n, l) : NULL);\n}\n#define TX_LEFT_OF(n)  TMleftOf(TM_ARG  n)\n\n\n/* =============================================================================\n * rightOf\n * =============================================================================\n */\nstatic inline node_t*\nrightOf (node_t* n)\n{\n    return (n ? LDNODE(n, r) : NULL);\n}\n#define RIGHT_OF(n)  rightOf(n)\n\n\n/* =============================================================================\n * TMrightOf\n * =============================================================================\n */\nstatic inline node_t*\nTMrightOf (TM_ARGDECL  node_t* n)\n{\n    return (n ? TX_LDNODE(n, r) : NULL);\n}\n#define TX_RIGHT_OF(n)  TMrightOf(TM_ARG  n)\n\n\n/* =============================================================================\n * colorOf\n * =============================================================================\n */\nstatic inline long\ncolorOf (node_t* n)\n{\n    return (n ? (long)LDNODE(n, c) : BLACK);\n}\n#define COLOR_OF(n)  colorOf(n)\n\n\n/* =============================================================================\n * TMcolorOf\n * =============================================================================\n */\nstatic inline long\nTMcolorOf (TM_ARGDECL  node_t* n)\n{\n    return (n ? (long)TX_LDF(n, c) : BLACK);\n}\n#define TX_COLOR_OF(n)  TMcolorOf(TM_ARG  n)\n\n\n/* =============================================================================\n * setColor\n * =============================================================================\n */\nstatic inline void\nsetColor (node_t* n, long c)\n{\n    if (n != NULL) {\n        STF(n, c, c);\n    }\n}\n#define SET_COLOR(n, c)  setColor(n, c)\n\n\n/* =============================================================================\n * TMsetColor\n * =============================================================================\n */\nstatic inline void\nTMsetColor (TM_ARGDECL  node_t* n, long c)\n{\n    if (n != NULL) {\n        TX_STF(n, c, c);\n    }\n}\n#define TX_SET_COLOR(n, c)  TMsetColor(TM_ARG  n, c)\n\n\n/* =============================================================================\n * fixAfterInsertion\n * =============================================================================\n */\nstatic void\nfixAfterInsertion (rbtree_t* s, node_t* x)\n{\n    STF(x, c, RED);\n    while (x != NULL && x != LDNODE(s, root)) {\n        node_t* xp = LDNODE(x, p);\n        if (LDF(xp, c) != RED) {\n            break;\n        }\n        /* TODO: cache g = ppx = PARENT_OF(PARENT_OF(x)) */\n        if (PARENT_OF(x) == LEFT_OF(PARENT_OF(PARENT_OF(x)))) {\n            node_t*  y = RIGHT_OF(PARENT_OF(PARENT_OF(x)));\n            if (COLOR_OF(y) == RED) {\n                SET_COLOR(PARENT_OF(x), BLACK);\n                SET_COLOR(y, BLACK);\n                SET_COLOR(PARENT_OF(PARENT_OF(x)), RED);\n                x = PARENT_OF(PARENT_OF(x));\n            } else {\n                if (x == RIGHT_OF(PARENT_OF(x))) {\n                    x = PARENT_OF(x);\n                    ROTATE_LEFT(s, x);\n                }\n                SET_COLOR(PARENT_OF(x), BLACK);\n                SET_COLOR(PARENT_OF(PARENT_OF(x)), RED);\n                if (PARENT_OF(PARENT_OF(x)) != NULL) {\n                    ROTATE_RIGHT(s, PARENT_OF(PARENT_OF(x)));\n                }\n            }\n        } else {\n            node_t* y = LEFT_OF(PARENT_OF(PARENT_OF(x)));\n            if (COLOR_OF(y) == RED) {\n                SET_COLOR(PARENT_OF(x), BLACK);\n                SET_COLOR(y, BLACK);\n                SET_COLOR(PARENT_OF(PARENT_OF(x)), RED);\n                x = PARENT_OF(PARENT_OF(x));\n            } else {\n                if (x == LEFT_OF(PARENT_OF(x))) {\n                    x = PARENT_OF(x);\n                    ROTATE_RIGHT(s, x);\n                }\n                SET_COLOR(PARENT_OF(x),  BLACK);\n                SET_COLOR(PARENT_OF(PARENT_OF(x)), RED);\n                if (PARENT_OF(PARENT_OF(x)) != NULL) {\n                    ROTATE_LEFT(s, PARENT_OF(PARENT_OF(x)));\n                }\n            }\n        }\n    }\n    node_t* ro = LDNODE(s, root);\n    if (LDF(ro, c) != BLACK) {\n        STF(ro, c, BLACK);\n    }\n}\n#define FIX_AFTER_INSERTION(s, x)  fixAfterInsertion(s, x)\n\n\n/* =============================================================================\n * TMfixAfterInsertion\n * =============================================================================\n */\nstatic void\nTMfixAfterInsertion (TM_ARGDECL  rbtree_t* s, node_t* x)\n{\n    TX_STF(x, c, RED);\n    while (x != NULL && x != TX_LDNODE(s, root)) {\n        node_t* xp = TX_LDNODE(x, p);\n        if (TX_LDF(xp, c) != RED) {\n            break;\n        }\n        /* TODO: cache g = ppx = TX_PARENT_OF(TX_PARENT_OF(x)) */\n        if (TX_PARENT_OF(x) == TX_LEFT_OF(TX_PARENT_OF(TX_PARENT_OF(x)))) {\n            node_t*  y = TX_RIGHT_OF(TX_PARENT_OF(TX_PARENT_OF(x)));\n            if (TX_COLOR_OF(y) == RED) {\n                TX_SET_COLOR(TX_PARENT_OF(x), BLACK);\n                TX_SET_COLOR(y, BLACK);\n                TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED);\n                x = TX_PARENT_OF(TX_PARENT_OF(x));\n            } else {\n                if (x == TX_RIGHT_OF(TX_PARENT_OF(x))) {\n                    x = TX_PARENT_OF(x);\n                    TX_ROTATE_LEFT(s, x);\n                }\n                TX_SET_COLOR(TX_PARENT_OF(x), BLACK);\n                TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED);\n                if (TX_PARENT_OF(TX_PARENT_OF(x)) != NULL) {\n                    TX_ROTATE_RIGHT(s, TX_PARENT_OF(TX_PARENT_OF(x)));\n                }\n            }\n        } else {\n            node_t* y = TX_LEFT_OF(TX_PARENT_OF(TX_PARENT_OF(x)));\n            if (TX_COLOR_OF(y) == RED) {\n                TX_SET_COLOR(TX_PARENT_OF(x), BLACK);\n                TX_SET_COLOR(y, BLACK);\n                TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED);\n                x = TX_PARENT_OF(TX_PARENT_OF(x));\n            } else {\n                if (x == TX_LEFT_OF(TX_PARENT_OF(x))) {\n                    x = TX_PARENT_OF(x);\n                    TX_ROTATE_RIGHT(s, x);\n                }\n                TX_SET_COLOR(TX_PARENT_OF(x),  BLACK);\n                TX_SET_COLOR(TX_PARENT_OF(TX_PARENT_OF(x)), RED);\n                if (TX_PARENT_OF(TX_PARENT_OF(x)) != NULL) {\n                    TX_ROTATE_LEFT(s, TX_PARENT_OF(TX_PARENT_OF(x)));\n                }\n            }\n        }\n    }\n    node_t* ro = TX_LDNODE(s, root);\n    if (TX_LDF(ro, c) != BLACK) {\n        TX_STF(ro, c, BLACK);\n    }\n}\n#define TX_FIX_AFTER_INSERTION(s, x)  TMfixAfterInsertion(TM_ARG  s, x)\n\n\n/* =============================================================================\n * insert\n * =============================================================================\n */\nstatic node_t*\ninsert (rbtree_t* s, void* k, void* v, node_t* n)\n{\n    node_t* t  = LDNODE(s, root);\n    if (t == NULL) {\n        if (n == NULL) {\n            return NULL;\n        }\n        /* Note: the following STs don't really need to be transactional */\n        STF(n, l, NULL);\n        STF(n, r, NULL);\n        STF(n, p, NULL);\n        STF(n, k, k);\n        STF(n, v, v);\n        STF(n, c, BLACK);\n        STF(s, root, n);\n        return NULL;\n    }\n\n    for (;;) {\n        long cmp = s->compare(k, LDF(t, k));\n        if (cmp == 0) {\n            return t;\n        } else if (cmp < 0) {\n            node_t* tl = LDNODE(t, l);\n            if (tl != NULL) {\n                t = tl;\n            } else {\n                STF(n, l, NULL);\n                STF(n, r, NULL);\n                STF(n, k, k);\n                STF(n, v, v);\n                STF(n, p, t);\n                STF(t, l, n);\n                FIX_AFTER_INSERTION(s, n);\n                return NULL;\n            }\n        } else { /* cmp > 0 */\n            node_t* tr = LDNODE(t, r);\n            if (tr != NULL) {\n                t = tr;\n            } else {\n                STF(n, l, NULL);\n                STF(n, r, NULL);\n                STF(n, k, k);\n                STF(n, v, v);\n                STF(n, p, t);\n                STF(t, r, n);\n                FIX_AFTER_INSERTION(s, n);\n                return NULL;\n            }\n        }\n    }\n}\n#define INSERT(s, k, v, n)  insert(s, k, v, n)\n\n\n/* =============================================================================\n * TMinsert\n * =============================================================================\n */\nstatic node_t*\nTMinsert (TM_ARGDECL  rbtree_t* s, void* k, void* v, node_t* n)\n{\n    node_t* t  = TX_LDNODE(s, root);\n    if (t == NULL) {\n        if (n == NULL) {\n            return NULL;\n        }\n        /* Note: the following STs don't really need to be transactional */\n        TX_STF_P(n, l, (node_t*)NULL);\n        TX_STF_P(n, r, (node_t*)NULL);\n        TX_STF_P(n, p, (node_t*)NULL);\n        TX_STF(n, k, k);\n        TX_STF(n, v, v);\n        TX_STF(n, c, BLACK);\n        TX_STF_P(s, root, n);\n        return NULL;\n    }\n\n    for (;;) {\n        long cmp = s->compare(k, TX_LDF_P(t, k));\n        if (cmp == 0) {\n            return t;\n        } else if (cmp < 0) {\n            node_t* tl = TX_LDNODE(t, l);\n            if (tl != NULL) {\n                t = tl;\n            } else {\n                TX_STF_P(n, l, (node_t*)NULL);\n                TX_STF_P(n, r, (node_t*)NULL);\n                TX_STF(n, k, k);\n                TX_STF(n, v, v);\n                TX_STF_P(n, p, t);\n                TX_STF_P(t, l, n);\n                TX_FIX_AFTER_INSERTION(s, n);\n                return NULL;\n            }\n        } else { /* cmp > 0 */\n            node_t* tr = TX_LDNODE(t, r);\n            if (tr != NULL) {\n                t = tr;\n            } else {\n                TX_STF_P(n, l, (node_t*)NULL);\n                TX_STF_P(n, r, (node_t*)NULL);\n                TX_STF(n, k, k);\n                TX_STF(n, v, v);\n                TX_STF_P(n, p, t);\n                TX_STF_P(t, r, n);\n                TX_FIX_AFTER_INSERTION(s, n);\n                return NULL;\n            }\n        }\n    }\n}\n#define TX_INSERT(s, k, v, n)  TMinsert(TM_ARG  s, k, v, n)\n\n\n/*\n * Return the given node's successor node---the node which has the\n * next key in the the left to right ordering. If the node has\n * no successor, a null pointer is returned rather than a pointer to\n * the nil node\n */\n\n\n/* =============================================================================\n * successor\n * =============================================================================\n */\nstatic node_t*\nsuccessor (node_t* t)\n{\n    if (t == NULL) {\n        return NULL;\n    } else if (LDNODE(t, r) != NULL) {\n        node_t* p = LDNODE(t, r);\n        while (LDNODE(p, l) != NULL) {\n            p = LDNODE(p, l);\n        }\n        return p;\n    } else {\n        node_t* p = LDNODE(t, p);\n        node_t* ch = t;\n        while (p != NULL && ch == LDNODE(p, r)) {\n            ch = p;\n            p = LDNODE(p, p);\n        }\n        return p;\n    }\n}\n#define SUCCESSOR(n)  successor(n)\n\n\n/* =============================================================================\n * TMsuccessor\n * =============================================================================\n */\nstatic node_t*\nTMsuccessor  (TM_ARGDECL  node_t* t)\n{\n    if (t == NULL) {\n        return NULL;\n    } else if (TX_LDNODE(t, r) != NULL) {\n        node_t* p = TX_LDNODE(t,r);\n        while (TX_LDNODE(p, l) != NULL) {\n            p = TX_LDNODE(p, l);\n        }\n        return p;\n    } else {\n        node_t* p = TX_LDNODE(t, p);\n        node_t* ch = t;\n        while (p != NULL && ch == TX_LDNODE(p, r)) {\n            ch = p;\n            p = TX_LDNODE(p, p);\n        }\n        return p;\n    }\n}\n#define TX_SUCCESSOR(n)  TMsuccessor(TM_ARG  n)\n\n\n/* =============================================================================\n * fixAfterDeletion\n * =============================================================================\n */\nstatic void\nfixAfterDeletion (rbtree_t* s, node_t* x)\n{\n    while (x != LDNODE(s,root) && COLOR_OF(x) == BLACK) {\n        if (x == LEFT_OF(PARENT_OF(x))) {\n            node_t* sib = RIGHT_OF(PARENT_OF(x));\n            if (COLOR_OF(sib) == RED) {\n                SET_COLOR(sib, BLACK);\n                SET_COLOR(PARENT_OF(x), RED);\n                ROTATE_LEFT(s, PARENT_OF(x));\n                sib = RIGHT_OF(PARENT_OF(x));\n            }\n            if (COLOR_OF(LEFT_OF(sib)) == BLACK &&\n                COLOR_OF(RIGHT_OF(sib)) == BLACK) {\n                SET_COLOR(sib, RED);\n                x = PARENT_OF(x);\n            } else {\n                if (COLOR_OF(RIGHT_OF(sib)) == BLACK) {\n                    SET_COLOR(LEFT_OF(sib), BLACK);\n                    SET_COLOR(sib, RED);\n                    ROTATE_RIGHT(s, sib);\n                    sib = RIGHT_OF(PARENT_OF(x));\n                }\n                SET_COLOR(sib, COLOR_OF(PARENT_OF(x)));\n                SET_COLOR(PARENT_OF(x), BLACK);\n                SET_COLOR(RIGHT_OF(sib), BLACK);\n                ROTATE_LEFT(s, PARENT_OF(x));\n                /* TODO: consider break ... */\n                x = LDNODE(s,root);\n            }\n        } else { /* symmetric */\n            node_t* sib = LEFT_OF(PARENT_OF(x));\n            if (COLOR_OF(sib) == RED) {\n                SET_COLOR(sib, BLACK);\n                SET_COLOR(PARENT_OF(x), RED);\n                ROTATE_RIGHT(s, PARENT_OF(x));\n                sib = LEFT_OF(PARENT_OF(x));\n            }\n            if (COLOR_OF(RIGHT_OF(sib)) == BLACK &&\n                COLOR_OF(LEFT_OF(sib)) == BLACK) {\n                SET_COLOR(sib,  RED);\n                x = PARENT_OF(x);\n            } else {\n                if (COLOR_OF(LEFT_OF(sib)) == BLACK) {\n                    SET_COLOR(RIGHT_OF(sib), BLACK);\n                    SET_COLOR(sib, RED);\n                    ROTATE_LEFT(s, sib);\n                    sib = LEFT_OF(PARENT_OF(x));\n                }\n                SET_COLOR(sib, COLOR_OF(PARENT_OF(x)));\n                SET_COLOR(PARENT_OF(x), BLACK);\n                SET_COLOR(LEFT_OF(sib), BLACK);\n                ROTATE_RIGHT(s, PARENT_OF(x));\n                /* TODO: consider break ... */\n                x = LDNODE(s, root);\n            }\n        }\n    }\n\n    if (x != NULL && LDF(x,c) != BLACK) {\n       STF(x, c, BLACK);\n    }\n}\n#define FIX_AFTER_DELETION(s, n)  fixAfterDeletion(s, n)\n\n\n/* =============================================================================\n * TMfixAfterDeletion\n * =============================================================================\n */\nstatic void\nTMfixAfterDeletion  (TM_ARGDECL  rbtree_t* s, node_t* x)\n{\n    while (x != TX_LDNODE(s,root) && TX_COLOR_OF(x) == BLACK) {\n        if (x == TX_LEFT_OF(TX_PARENT_OF(x))) {\n            node_t* sib = TX_RIGHT_OF(TX_PARENT_OF(x));\n            if (TX_COLOR_OF(sib) == RED) {\n                TX_SET_COLOR(sib, BLACK);\n                TX_SET_COLOR(TX_PARENT_OF(x), RED);\n                TX_ROTATE_LEFT(s, TX_PARENT_OF(x));\n                sib = TX_RIGHT_OF(TX_PARENT_OF(x));\n            }\n            if (TX_COLOR_OF(TX_LEFT_OF(sib)) == BLACK &&\n                TX_COLOR_OF(TX_RIGHT_OF(sib)) == BLACK) {\n                TX_SET_COLOR(sib, RED);\n                x = TX_PARENT_OF(x);\n            } else {\n                if (TX_COLOR_OF(TX_RIGHT_OF(sib)) == BLACK) {\n                    TX_SET_COLOR(TX_LEFT_OF(sib), BLACK);\n                    TX_SET_COLOR(sib, RED);\n                    TX_ROTATE_RIGHT(s, sib);\n                    sib = TX_RIGHT_OF(TX_PARENT_OF(x));\n                }\n                TX_SET_COLOR(sib, TX_COLOR_OF(TX_PARENT_OF(x)));\n                TX_SET_COLOR(TX_PARENT_OF(x), BLACK);\n                TX_SET_COLOR(TX_RIGHT_OF(sib), BLACK);\n                TX_ROTATE_LEFT(s, TX_PARENT_OF(x));\n                /* TODO: consider break ... */\n                x = TX_LDNODE(s,root);\n            }\n        } else { /* symmetric */\n            node_t* sib = TX_LEFT_OF(TX_PARENT_OF(x));\n\n            if (TX_COLOR_OF(sib) == RED) {\n                TX_SET_COLOR(sib, BLACK);\n                TX_SET_COLOR(TX_PARENT_OF(x), RED);\n                TX_ROTATE_RIGHT(s, TX_PARENT_OF(x));\n                sib = TX_LEFT_OF(TX_PARENT_OF(x));\n            }\n            if (TX_COLOR_OF(TX_RIGHT_OF(sib)) == BLACK &&\n                TX_COLOR_OF(TX_LEFT_OF(sib)) == BLACK) {\n                TX_SET_COLOR(sib,  RED);\n                x = TX_PARENT_OF(x);\n            } else {\n                if (TX_COLOR_OF(TX_LEFT_OF(sib)) == BLACK) {\n                    TX_SET_COLOR(TX_RIGHT_OF(sib), BLACK);\n                    TX_SET_COLOR(sib, RED);\n                    TX_ROTATE_LEFT(s, sib);\n                    sib = TX_LEFT_OF(TX_PARENT_OF(x));\n                }\n                TX_SET_COLOR(sib, TX_COLOR_OF(TX_PARENT_OF(x)));\n                TX_SET_COLOR(TX_PARENT_OF(x), BLACK);\n                TX_SET_COLOR(TX_LEFT_OF(sib), BLACK);\n                TX_ROTATE_RIGHT(s, TX_PARENT_OF(x));\n                /* TODO: consider break ... */\n                x = TX_LDNODE(s, root);\n            }\n        }\n    }\n\n    if (x != NULL && TX_LDF(x,c) != BLACK) {\n       TX_STF(x, c, BLACK);\n    }\n}\n#define TX_FIX_AFTER_DELETION(s, n)  TMfixAfterDeletion(TM_ARG  s, n )\n\n\n/* =============================================================================\n * delete_node\n * =============================================================================\n */\nstatic node_t*\ndelete_node (rbtree_t* s, node_t* p)\n{\n    /*\n     * If strictly internal, copy successor's element to p and then make p\n     * point to successor\n     */\n    if (LDNODE(p, l) != NULL && LDNODE(p, r) != NULL) {\n        node_t* s = SUCCESSOR(p);\n        STF(p, k, LDNODE(s, k));\n        STF(p, v, LDNODE(s, v));\n        p = s;\n    } /* p has 2 children */\n\n    /* Start fixup at replacement node, if it exists */\n    node_t* replacement =\n        ((LDNODE(p, l) != NULL) ? LDNODE(p, l) : LDNODE(p, r));\n\n    if (replacement != NULL) {\n        /* Link replacement to parent */\n        /* TODO: precompute pp = p->p and substitute below ... */\n        STF (replacement, p, LDNODE(p, p));\n        node_t* pp = LDNODE(p, p);\n        if (pp == NULL) {\n            STF(s, root, replacement);\n        } else if (p == LDNODE(pp, l)) {\n            STF(pp, l, replacement);\n        } else {\n            STF(pp, r, replacement);\n        }\n\n        /* Null out links so they are OK to use by fixAfterDeletion */\n        STF(p, l, NULL);\n        STF(p, r, NULL);\n        STF(p, p, NULL);\n\n        /* Fix replacement */\n        if (LDF(p,c) == BLACK) {\n            FIX_AFTER_DELETION(s, replacement);\n        }\n    } else if (LDNODE(p, p) == NULL) { /* return if we are the only node */\n        STF(s, root, NULL);\n    } else { /* No children. Use self as phantom replacement and unlink */\n        if (LDF(p, c) == BLACK) {\n            FIX_AFTER_DELETION(s, p);\n        }\n        node_t* pp = LDNODE(p, p);\n        if (pp != NULL) {\n            if (p == LDNODE(pp, l)) {\n                STF(pp,l, NULL);\n            } else if (p == LDNODE(pp, r)) {\n                STF(pp, r, NULL);\n            }\n            STF(p, p, NULL);\n        }\n    }\n    return p;\n}\n#define DELETE(s, n)  delete_node(s, n)\n\n\n/* =============================================================================\n * TMdelete\n * =============================================================================\n */\nstatic node_t*\nTMdelete (TM_ARGDECL  rbtree_t* s, node_t* p)\n{\n    /*\n     * If strictly internal, copy successor's element to p and then make p\n     * point to successor\n     */\n    if (TX_LDNODE(p, l) != NULL && TX_LDNODE(p, r) != NULL) {\n        node_t* s = TX_SUCCESSOR(p);\n        TX_STF(p,k, TX_LDF_P(s, k));\n        TX_STF(p,v, TX_LDF_P(s, v));\n        p = s;\n    } /* p has 2 children */\n\n    /* Start fixup at replacement node, if it exists */\n    node_t* replacement =\n        ((TX_LDNODE(p, l) != NULL) ? TX_LDNODE(p, l) : TX_LDNODE(p, r));\n\n    if (replacement != NULL) {\n        /* Link replacement to parent */\n        /* TODO: precompute pp = p->p and substitute below ... */\n        TX_STF_P(replacement, p, TX_LDNODE(p, p));\n        node_t* pp = TX_LDNODE(p, p);\n        if (pp == NULL) {\n            TX_STF_P(s, root, replacement);\n        } else if (p == TX_LDNODE(pp, l)) {\n            TX_STF_P(pp, l, replacement);\n        } else {\n            TX_STF_P(pp, r, replacement);\n        }\n\n        /* Null out links so they are OK to use by fixAfterDeletion */\n        TX_STF_P(p, l, (node_t*)NULL);\n        TX_STF_P(p, r, (node_t*)NULL);\n        TX_STF_P(p, p, (node_t*)NULL);\n\n        /* Fix replacement */\n        if (TX_LDF(p,c) == BLACK) {\n            TX_FIX_AFTER_DELETION(s, replacement);\n        }\n    } else if (TX_LDNODE(p,p) == NULL) { /* return if we are the only node */\n        TX_STF_P(s, root, (node_t*)NULL);\n    } else { /* No children. Use self as phantom replacement and unlink */\n        if (TX_LDF(p,c) == BLACK) {\n            TX_FIX_AFTER_DELETION(s, p);\n        }\n        node_t* pp = TX_LDNODE(p, p);\n        if (pp != NULL) {\n            if (p == TX_LDNODE(pp, l)) {\n                TX_STF_P(pp,l, (node_t*)NULL);\n            } else if (p == TX_LDNODE(pp, r)) {\n                TX_STF_P(pp, r, (node_t*)NULL);\n            }\n            TX_STF_P(p, p, (node_t*)NULL);\n        }\n    }\n    return p;\n}\n#define TX_DELETE(s, n)  TMdelete(TM_ARG  s, n)\n\n\n/*\n * Diagnostic section\n */\n\n\n/* =============================================================================\n * firstEntry\n * =============================================================================\n */\nstatic node_t*\nfirstEntry (rbtree_t* s)\n{\n    node_t* p = s->root;\n    if (p != NULL) {\n        while (p->l != NULL) {\n            p = p->l;\n        }\n    }\n    return p;\n}\n\n\n#if 0\n/* =============================================================================\n * predecessor\n * =============================================================================\n */\nstatic node_t*\npredecessor (node_t* t)\n{\n    if (t == NULL)\n        return NULL;\n    else if (t->l != NULL) {\n        node_t* p = t->l;\n        while (p->r != NULL) {\n            p = p->r;\n        }\n        return p;\n    } else {\n        node_t* p = t->p;\n        node_t* ch = t;\n        while (p != NULL && ch == p->l) {\n            ch = p;\n            p = p->p;\n        }\n        return p;\n    }\n}\n#endif\n\n\n/*\n * Compute the BH (BlackHeight) and validate the tree.\n *\n * This function recursively verifies that the given binary subtree satisfies\n * three of the red black properties. It checks that every red node has only\n * black children. It makes sure that each node is either red or black. And it\n * checks that every path has the same count of black nodes from root to leaf.\n * It returns the blackheight of the given subtree; this allows blackheights to\n * be computed recursively and compared for left and right siblings for\n * mismatches. It does not check for every nil node being black, because there\n * is only one sentinel nil node. The return value of this function is the\n * black height of the subtree rooted at the node ``root'', or zero if the\n * subtree is not red-black.\n *\n */\n\n\n/* =============================================================================\n * verifyRedBlack\n * =============================================================================\n */\nstatic long\nverifyRedBlack (node_t* root, long depth)\n{\n    long height_left;\n    long height_right;\n\n    if (root == NULL) {\n        return 1;\n    }\n\n    height_left  = verifyRedBlack(root->l, depth+1);\n    height_right = verifyRedBlack(root->r, depth+1);\n    if (height_left == 0 || height_right == 0) {\n        return 0;\n    }\n    if (height_left != height_right) {\n        printf(\" Imbalance @depth=%ld : %ld %ld\\n\", depth, height_left, height_right);\n    }\n\n    if (root->l != NULL && root->l->p != root) {\n       printf(\" lineage\\n\");\n    }\n    if (root->r != NULL && root->r->p != root) {\n       printf(\" lineage\\n\");\n    }\n\n    /* Red-Black alternation */\n    if (root->c == RED) {\n        if (root->l != NULL && root->l->c != BLACK) {\n          printf(\"VERIFY %d\\n\", __LINE__);\n          return 0;\n        }\n        if (root->r != NULL && root->r->c != BLACK) {\n          printf(\"VERIFY %d\\n\", __LINE__);\n          return 0;\n        }\n        return height_left;\n    }\n    if (root->c != BLACK) {\n        printf(\"VERIFY %d\\n\", __LINE__);\n        return 0;\n    }\n\n    return (height_left + 1);\n}\n\n\n/* =============================================================================\n * rbtree_verify\n * =============================================================================\n */\nlong\nrbtree_verify (rbtree_t* s, long verbose)\n{\n    node_t* root = s->root;\n    if (root == NULL) {\n        return 1;\n    }\n    if (verbose) {\n       printf(\"Integrity check: \");\n    }\n\n    if (root->p != NULL) {\n        printf(\"  (WARNING) root %lX parent=%lX\\n\",\n               (unsigned long)root, (unsigned long)root->p);\n        return -1;\n    }\n    if (root->c != BLACK) {\n        printf(\"  (WARNING) root %lX color=%lX\\n\",\n               (unsigned long)root, (unsigned long)root->c);\n    }\n\n    /* Weak check of binary-tree property */\n    long ctr = 0;\n    node_t* its = firstEntry(s);\n    while (its != NULL) {\n        ctr++;\n        node_t* child = its->l;\n        if (child != NULL && child->p != its) {\n            printf(\"Bad parent\\n\");\n        }\n        child = its->r;\n        if (child != NULL && child->p != its) {\n            printf(\"Bad parent\\n\");\n        }\n        node_t* nxt = successor(its);\n        if (nxt == NULL) {\n            break;\n        }\n        if (s->compare(its->k, nxt->k) >= 0) {\n            printf(\"Key order %lX (%ld %ld) %lX (%ld %ld)\\n\",\n                   (unsigned long)its, (long)its->k, (long)its->v,\n                   (unsigned long)nxt, (long)nxt->k, (long)nxt->v);\n            return -3;\n        }\n        its = nxt;\n    }\n\n    long vfy = verifyRedBlack(root, 0);\n    if (verbose) {\n        printf(\" Nodes=%ld Depth=%ld\\n\", ctr, vfy);\n    }\n\n    return vfy;\n}\n\n\n/* =============================================================================\n * compareKeysDefault\n * =============================================================================\n */\nstatic long\ncompareKeysDefault (const void* a, const void* b)\n{\n    return ((long)a - (long)b);\n}\n\n\n/* =============================================================================\n * rbtree_alloc\n * =============================================================================\n */\nrbtree_t*\nrbtree_alloc (long (*compare)(const void*, const void*))\n{\n    rbtree_t* n = (rbtree_t* )malloc(sizeof(*n));\n    if (n) {\n        n->compare = (compare ? compare : &compareKeysDefault);\n        n->root = NULL;\n    }\n    return n;\n}\n\n\n/* =============================================================================\n * TMrbtree_alloc\n * =============================================================================\n */\nrbtree_t*\nTMrbtree_alloc (TM_ARGDECL  long (*compare)(const void*, const void*))\n{\n    rbtree_t* n = (rbtree_t* )TM_MALLOC(sizeof(*n));\n    if (n){\n        n->compare = (compare ? compare : &compareKeysDefault);\n        n->root = NULL;\n    }\n    return n;\n}\n\n\n/* =============================================================================\n * releaseNode\n * =============================================================================\n */\nstatic void\nreleaseNode (node_t* n)\n{\n#ifndef SIMULATOR\n    free(n);\n#endif    \n}\n\n\n/* =============================================================================\n * TMreleaseNode\n * =============================================================================\n */\nstatic void\nTMreleaseNode  (TM_ARGDECL  node_t* n)\n{\n    TM_FREE(n);\n}\n\n\n/* =============================================================================\n * freeNode\n * =============================================================================\n */\nstatic void\nfreeNode (node_t* n)\n{\n    if (n) {\n        freeNode(n->l);\n        freeNode(n->r);\n        releaseNode(n);\n    }\n}\n\n\n/* =============================================================================\n * TMfreeNode\n * =============================================================================\n */\nstatic void\nTMfreeNode (TM_ARGDECL  node_t* n)\n{\n    if (n) {\n        TMfreeNode(TM_ARG  n->l);\n        TMfreeNode(TM_ARG  n->r);\n        TMreleaseNode(TM_ARG  n);\n    }\n}\n\n\n/* =============================================================================\n * rbtree_free\n * =============================================================================\n */\nvoid\nrbtree_free (rbtree_t* r)\n{\n    freeNode(r->root);\n    free(r);\n}\n\n\n/* =============================================================================\n * TMrbtree_free\n * =============================================================================\n */\nvoid\nTMrbtree_free (TM_ARGDECL  rbtree_t* r)\n{\n    TMfreeNode(TM_ARG  r->root);\n    TM_FREE(r);\n}\n\n\n/* =============================================================================\n * getNode\n * =============================================================================\n */\nstatic node_t*\ngetNode ()\n{\n    node_t* n = (node_t*)malloc(sizeof(*n));\n    return n;\n}\n\n\n/* =============================================================================\n * TMgetNode\n * =============================================================================\n */\nstatic node_t*\nTMgetNode (TM_ARGDECL_ALONE)\n{\n    node_t* n = (node_t*)TM_MALLOC(sizeof(*n));\n    return n;\n}\n\n\n/* =============================================================================\n * rbtree_insert\n * -- Returns TRUE on success\n * =============================================================================\n */\nbool_t\nrbtree_insert (rbtree_t* r, void* key, void* val)\n{\n    node_t* node = getNode();\n    node_t* ex = INSERT(r, key, val, node);\n    if (ex != NULL) {\n        releaseNode(node);\n    }\n    return ((ex == NULL) ? TRUE : FALSE);\n}\n\n\n/* =============================================================================\n * TMrbtree_insert\n * -- Returns TRUE on success\n * =============================================================================\n */\nbool_t\nTMrbtree_insert (TM_ARGDECL  rbtree_t* r, void* key, void* val)\n{\n    node_t* node = TMgetNode(TM_ARG_ALONE);\n    node_t* ex = TX_INSERT(r, key, val, node);\n    if (ex != NULL) {\n        TMreleaseNode(TM_ARG  node);\n    }\n    return ((ex == NULL) ? TRUE : FALSE);\n}\n\n\n/* =============================================================================\n * rbtree_delete\n * -- Returns TRUE if key exists\n * =============================================================================\n */\nbool_t\nrbtree_delete (rbtree_t* r, void* key)\n{\n    node_t* node = NULL;\n    node = LOOKUP(r, key);\n    if (node != NULL) {\n        node = DELETE(r, node);\n    }\n    if (node != NULL) {\n        releaseNode(node);\n    }\n    return ((node != NULL) ? TRUE : FALSE);\n}\n\n\n/* =============================================================================\n * TMrbtree_delete\n * -- Returns TRUE if key exists\n * =============================================================================\n */\nbool_t\nTMrbtree_delete (TM_ARGDECL  rbtree_t* r, void* key)\n{\n    node_t* node = NULL;\n    node = TX_LOOKUP(r, key);\n    if (node != NULL) {\n        node = TX_DELETE(r, node);\n    }\n    if (node != NULL) {\n        TMreleaseNode(TM_ARG  node);\n    }\n    return ((node != NULL) ? TRUE : FALSE);\n}\n\n\n/* =============================================================================\n * rbtree_update\n * -- Return FALSE if had to insert node first\n * =============================================================================\n */\nbool_t\nrbtree_update (rbtree_t* r, void* key, void* val)\n{\n    node_t* nn = getNode();\n    node_t* ex = INSERT(r, key, val, nn);\n    if (ex != NULL) {\n        STF(ex, v, val);\n        releaseNode(nn);\n        return TRUE;\n    }\n    return FALSE;\n}\n\n\n/* =============================================================================\n * TMrbtree_update\n * -- Return FALSE if had to insert node first\n * =============================================================================\n */\nbool_t\nTMrbtree_update (TM_ARGDECL  rbtree_t* r, void* key, void* val)\n{\n    node_t* nn = TMgetNode(TM_ARG_ALONE);\n    node_t* ex = TX_INSERT(r, key, val, nn);\n    if (ex != NULL) {\n        TX_STF(ex, v, val);\n        TMreleaseNode(TM_ARG  nn);\n        return TRUE;\n    }\n    return FALSE;\n}\n\n\n/* =============================================================================\n * rbtree_get\n * =============================================================================\n */\nvoid*\nrbtree_get (rbtree_t* r, void* key) {\n    node_t* n = LOOKUP(r, key);\n    if (n != NULL) {\n        void* val = LDF(n, v);\n        return val;\n    }\n    return NULL;\n}\n\n\n/* =============================================================================\n * TMrbtree_get\n * =============================================================================\n */\nvoid*\nTMrbtree_get (TM_ARGDECL  rbtree_t* r, void* key) {\n    node_t* n = TX_LOOKUP(r, key);\n    if (n != NULL) {\n        void* val = TX_LDF_P(n, v);\n        return val;\n    }\n    return NULL;\n}\n\n\n/* =============================================================================\n * rbtree_contains\n * =============================================================================\n */\nlong\nrbtree_contains (rbtree_t* r, void* key)\n{\n    node_t* n = LOOKUP(r, key);\n    return (n != NULL);\n}\n\n\n/* =============================================================================\n * TMrbtree_contains\n * =============================================================================\n */\nlong\nTMrbtree_contains (TM_ARGDECL  rbtree_t* r, void* key)\n{\n    node_t* n = TX_LOOKUP(r, key);\n    return (n != NULL);\n}\n\n\n/* /////////////////////////////////////////////////////////////////////////////\n * TEST_RBTREE\n * /////////////////////////////////////////////////////////////////////////////\n */\n#ifdef TEST_RBTREE\n\n\n#include <assert.h>\n#include <stdio.h>\n\n\nstatic long\ncompare (const void* a, const void* b)\n{\n    return (*((const long*)a) - *((const long*)b));\n}\n\n\nstatic void\ninsertInt (rbtree_t* rbtreePtr, long* data)\n{\n    printf(\"Inserting: %li\\n\", *data);\n    rbtree_insert(rbtreePtr, (void*)data, (void*)data);\n    assert(*(long*)rbtree_get(rbtreePtr, (void*)data) == *data);\n    assert(rbtree_verify(rbtreePtr, 0) > 0);\n}\n\n\nstatic void\nremoveInt (rbtree_t* rbtreePtr, long* data)\n{\n    printf(\"Removing: %li\\n\", *data);\n    rbtree_delete(rbtreePtr, (void*)data);\n    assert(rbtree_get(rbtreePtr, (void*)data) == NULL);\n    assert(rbtree_verify(rbtreePtr, 0) > 0);\n}\n\n\nint\nmain ()\n{\n    long data[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7};\n    long numData = sizeof(data) / sizeof(data[0]);\n    long i;\n\n    puts(\"Starting...\");\n\n    rbtree_t* rbtreePtr = rbtree_alloc(&compare);\n    assert(rbtreePtr);\n\n    for (i = 0; i < numData; i++) {\n        insertInt(rbtreePtr, &data[i]);\n    }\n\n    for (i = 0; i < numData; i++) {\n        removeInt(rbtreePtr, &data[i]);\n    }\n\n    rbtree_free(rbtreePtr);\n\n    puts(\"Done.\");\n\n    return 0;\n}\n\n\n#endif /* TEST_RBTREE */\n\n\n/* =============================================================================\n *\n * End of rbtree.c\n *\n * =============================================================================\n */\n"
  },
  {
    "path": "stms/tinystm/test/intset/rbtree.h",
    "content": "/* =============================================================================\n *\n * rbtree.h\n * -- Red-black balanced binary search tree\n *\n * =============================================================================\n *\n * Copyright (C) Sun Microsystems Inc., 2006.  All Rights Reserved.\n * Authors: Dave Dice, Nir Shavit, Ori Shalev.\n *\n * STM: Transactional Locking for Disjoint Access Parallelism\n *\n * Transactional Locking II,\n * Dave Dice, Ori Shalev, Nir Shavit\n * DISC 2006, Sept 2006, Stockholm, Sweden.\n *\n * =============================================================================\n *\n * Modified by Chi Cao Minh\n *\n * =============================================================================\n *\n * For the license of bayes/sort.h and bayes/sort.c, please see the header\n * of the files.\n * \n * ------------------------------------------------------------------------\n * \n * For the license of kmeans, please see kmeans/LICENSE.kmeans\n * \n * ------------------------------------------------------------------------\n * \n * For the license of ssca2, please see ssca2/COPYRIGHT\n * \n * ------------------------------------------------------------------------\n * \n * For the license of lib/mt19937ar.c and lib/mt19937ar.h, please see the\n * header of the files.\n * \n * ------------------------------------------------------------------------\n * \n * For the license of lib/rbtree.h and lib/rbtree.c, please see\n * lib/LEGALNOTICE.rbtree and lib/LICENSE.rbtree\n * \n * ------------------------------------------------------------------------\n * \n * Unless otherwise noted, the following license applies to STAMP files:\n * \n * Copyright (c) 2007, Stanford University\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n * \n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n * \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in\n *       the documentation and/or other materials provided with the\n *       distribution.\n * \n *     * Neither the name of Stanford University nor the names of its\n *       contributors may be used to endorse or promote products derived\n *       from this software without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n *\n * =============================================================================\n */\n\n\n#ifndef RBTREE_H\n#define RBTREE_H 1\n\n\n#include \"tm.h\"\n#include \"types.h\"\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\ntypedef struct rbtree rbtree_t;\n\n\n/* =============================================================================\n * rbtree_verify\n * =============================================================================\n */\nlong\nrbtree_verify (rbtree_t* s, long verbose);\n\n\n/* =============================================================================\n * rbtree_alloc\n * =============================================================================\n */\nrbtree_t*\nrbtree_alloc (long (*compare)(const void*, const void*));\n\n\n/* =============================================================================\n * TMrbtree_alloc\n * =============================================================================\n */\nrbtree_t*\nTMrbtree_alloc (TM_ARGDECL  long (*compare)(const void*, const void*));\n\n\n/* =============================================================================\n * rbtree_free\n * =============================================================================\n */\nvoid\nrbtree_free (rbtree_t* r);\n\n\n/* =============================================================================\n * TMrbtree_free\n * =============================================================================\n */\nvoid\nTMrbtree_free (TM_ARGDECL  rbtree_t* r);\n\n\n/* =============================================================================\n * rbtree_insert\n * -- Returns TRUE on success\n * =============================================================================\n */\nbool_t\nrbtree_insert (rbtree_t* r, void* key, void* val);\n\n\n/* =============================================================================\n * TMrbtree_insert\n * -- Returns TRUE on success\n * =============================================================================\n */\nTM_CALLABLE\nbool_t\nTMrbtree_insert (TM_ARGDECL  rbtree_t* r, void* key, void* val);\n\n\n/* =============================================================================\n * rbtree_delete\n * =============================================================================\n */\nbool_t\nrbtree_delete (rbtree_t* r, void* key);\n\n\n/* =============================================================================\n * TMrbtree_delete\n * =============================================================================\n */\nTM_CALLABLE\nbool_t\nTMrbtree_delete (TM_ARGDECL  rbtree_t* r, void* key);\n\n\n/* =============================================================================\n * rbtree_update\n * -- Return FALSE if had to insert node first\n * =============================================================================\n */\nbool_t\nrbtree_update (rbtree_t* r, void* key, void* val);\n\n\n/* =============================================================================\n * TMrbtree_update\n * -- Return FALSE if had to insert node first\n * =============================================================================\n */\nTM_CALLABLE\nbool_t\nTMrbtree_update (TM_ARGDECL  rbtree_t* r, void* key, void* val);\n\n\n/* =============================================================================\n * rbtree_get\n * =============================================================================\n */\nvoid*\nrbtree_get (rbtree_t* r, void* key);\n\n\n/* =============================================================================\n * TMrbtree_get\n * =============================================================================\n */\nTM_CALLABLE\nvoid*\nTMrbtree_get (TM_ARGDECL  rbtree_t* r, void* key);\n\n\n/* =============================================================================\n * rbtree_contains\n * =============================================================================\n */\nbool_t\nrbtree_contains (rbtree_t* r, void* key);\n\n\n/* =============================================================================\n * TMrbtree_contains\n * =============================================================================\n */\nTM_CALLABLE\nbool_t\nTMrbtree_contains (TM_ARGDECL  rbtree_t* r, void* key);\n\n\n#define TMRBTREE_ALLOC()          TMrbtree_alloc(TM_ARG_ALONE)\n#define TMRBTREE_FREE(r)          TMrbtree_free(TM_ARG  r)\n#define TMRBTREE_INSERT(r, k, v)  TMrbtree_insert(TM_ARG  r, (void*)(k), (void*)(v))\n#define TMRBTREE_DELETE(r, k)     TMrbtree_delete(TM_ARG  r, (void*)(k))\n#define TMRBTREE_UPDATE(r, k, v)  TMrbtree_update(TM_ARG  r, (void*)(k), (void*)(v))\n#define TMRBTREE_GET(r, k)        TMrbtree_get(TM_ARG  r, (void*)(k))\n#define TMRBTREE_CONTAINS(r, k)   TMrbtree_contains(TM_ARG  r, (void*)(k))\n\n\n#ifdef __cplusplus\n}\n#endif\n\n\n\n#endif /* RBTREE_H */\n\n\n\n/* =============================================================================\n *\n * End of rbtree.h\n *\n * =============================================================================\n */\n"
  },
  {
    "path": "stms/tinystm/test/intset/tm.h",
    "content": "/*\n * File:\n *   tm.h\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Empty file (to avoid source modifications red-black tree).\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n"
  },
  {
    "path": "stms/tinystm/test/intset/types.h",
    "content": "/* =============================================================================\n *\n * types.h\n * -- definitions of some types\n *\n * =============================================================================\n *\n * Copyright (C) Stanford University, 2006.  All Rights Reserved.\n * Author: Chi Cao Minh\n *\n * =============================================================================\n *\n * For the license of bayes/sort.h and bayes/sort.c, please see the header\n * of the files.\n * \n * ------------------------------------------------------------------------\n * \n * For the license of kmeans, please see kmeans/LICENSE.kmeans\n * \n * ------------------------------------------------------------------------\n * \n * For the license of ssca2, please see ssca2/COPYRIGHT\n * \n * ------------------------------------------------------------------------\n * \n * For the license of lib/mt19937ar.c and lib/mt19937ar.h, please see the\n * header of the files.\n * \n * ------------------------------------------------------------------------\n * \n * For the license of lib/rbtree.h and lib/rbtree.c, please see\n * lib/LEGALNOTICE.rbtree and lib/LICENSE.rbtree\n * \n * ------------------------------------------------------------------------\n * \n * Unless otherwise noted, the following license applies to STAMP files:\n * \n * Copyright (c) 2007, Stanford University\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n * \n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n * \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in\n *       the documentation and/or other materials provided with the\n *       distribution.\n * \n *     * Neither the name of Stanford University nor the names of its\n *       contributors may be used to endorse or promote products derived\n *       from this software without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n *\n * =============================================================================\n */\n\n\n#ifndef TYPES_H\n#define TYPES_H 1\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n#ifdef SIMULATOR\n#  undef TRUE\n#  undef FALSE\n#  undef bool\n#endif\n\n\ntypedef unsigned long ulong_t;\n\nenum {\n    FALSE = 0,\n    TRUE  = 1\n};\n\ntypedef long bool_t;\n\n\n#ifdef __cplusplus\n}\n#endif\n\n\n#endif /* TYPES_H */\n\n\n/* =============================================================================\n *\n * End of types.h\n *\n * =============================================================================\n */\n"
  },
  {
    "path": "stms/tinystm/test/regression/.gitignore",
    "content": "irrevocability\ntypes\n"
  },
  {
    "path": "stms/tinystm/test/regression/Makefile",
    "content": "ROOT = ../..\n\ninclude $(ROOT)/Makefile.common\n\nBINS = types irrevocability\n\n.PHONY:\tall clean\n\nall:\t$(BINS)\n\n%.o:\t%.c\n\t$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c -o $@ $<\n\n$(BINS):\t%:\t%.o $(TMLIB)\n\t$(CC) -o $@ $< $(LDFLAGS)\n\nclean:\n\trm -f $(BINS) *.o\n"
  },
  {
    "path": "stms/tinystm/test/regression/irrevocability.c",
    "content": "/*\n * File:\n *   irrevocability.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Regression test for irrevocability.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifdef NDEBUG\n# undef NDEBUG\n#endif\n\n#include <assert.h>\n#include <getopt.h>\n#include <pthread.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"stm.h\"\n#include \"wrappers.h\"\n\n#define DEFAULT_DURATION                5000\n#define DEFAULT_IRREVOCABLE_PERCENT     25\n#define DEFAULT_NB_THREADS              4\n\n#define NB_ELEMENTS                     64\n#define NB_SHUFFLES                     16\n\n#define XSTR(s)                         STR(s)\n#define STR(s)                          #s\n\nstatic volatile int stop;\n\nlong data[64];\n\nvolatile long nb_irrevocable_serial = 0;\nvolatile long nb_irrevocable_parallel = 0;\n\ntypedef struct thread_data {\n  unsigned long nb_aborts;\n  unsigned long nb_aborts_1;\n  unsigned long nb_aborts_2;\n  unsigned long nb_aborts_locked_read;\n  unsigned long nb_aborts_locked_write;\n  unsigned long nb_aborts_validate_read;\n  unsigned long nb_aborts_validate_write;\n  unsigned long nb_aborts_validate_commit;\n  unsigned long nb_aborts_invalid_memory;\n  unsigned long nb_aborts_killed;\n  unsigned long locked_reads_ok;\n  unsigned long locked_reads_failed;\n  unsigned long max_retries;\n  unsigned short seed[3];\n  int irrevocable_percent;\n  char padding[64];\n} thread_data_t;\n\nstatic void *test(void *v)\n{\n  unsigned int seed;\n  int i, n, irrevocable, serial, path;\n  long l;\n  sigjmp_buf *e;\n  thread_data_t *d = (thread_data_t *)v;\n\n  seed = (unsigned int)time(NULL);\n  stm_init_thread();\n  while (stop == 0) {\n    irrevocable = (rand_r(&seed) < RAND_MAX / 100 * d->irrevocable_percent ? 1 : 0);\n    serial = (rand_r(&seed) < RAND_MAX / 2 ? 1 : 0);\n//    irrevocable = 1;\n//    serial = 1;\n    e = stm_start((stm_tx_attr_t)0);\n    path = sigsetjmp(*e, 0);\n    if (irrevocable == 4) {\n      /* Aborted while in irrevocable mode => error */\n      fprintf(stderr, \"ERROR: aborted while in irrevocable mode\\n\");\n      exit(1);\n    }\n    if (path & STM_PATH_UNINSTRUMENTED) {\n      for (n = rand_r(&seed) % NB_SHUFFLES; n > 0; n--) {\n        i = rand_r(&seed) % NB_ELEMENTS;\n        data[i] = data[i] + 1;\n        i = rand_r(&seed) % NB_ELEMENTS;\n        data[i] = data[i] - 1;\n      }\n    } else {\n      for (n = rand_r(&seed) % NB_SHUFFLES; n > 0; n--) {\n        i = rand_r(&seed) % NB_ELEMENTS;\n        stm_store_long(&data[i], stm_load_long(&data[i]) + 1);\n        i = rand_r(&seed) % NB_ELEMENTS;\n        stm_store_long(&data[i], stm_load_long(&data[i]) - 1);\n      }\n    }\n    if (irrevocable) {\n      if (irrevocable == 3) {\n        /* Already tried entering irrevocable mode once => error */\n        fprintf(stderr, \"ERROR: failed entering irrevocable mode upon retry\\n\");\n        exit(1);\n      }\n      irrevocable++;\n      if (!stm_set_irrevocable(serial)) {\n        fprintf(stderr, \"ERROR: cannot enter irrevocable mode\\n\");\n        exit(1);\n      }\n      irrevocable = 4;\n      /* Once in irrevocable mode, we cannot abort */\n      if (path & STM_PATH_UNINSTRUMENTED) {\n        /* No other transaction can execute concurrently */\n        for (i = 0, l = 0; i < NB_ELEMENTS; i++)\n          l += data[i];\n        assert(l == 0);\n        for (i = 0; i < NB_ELEMENTS; i++)\n          data[i] = 0;\n        nb_irrevocable_serial++;\n      } else {\n        /* Non-conflicting transactions can execute concurrently */\n        for (i = 0, l = 0; i < NB_ELEMENTS; i++)\n          l += stm_load_long(&data[i]);\n        assert(l == 0);\n        for (i = 0; i < NB_ELEMENTS; i++)\n          stm_store_long(&data[i], 0);\n        nb_irrevocable_parallel++;\n      }\n    }\n    if (path & STM_PATH_UNINSTRUMENTED) {\n      for (i = 0, l = 0; i < NB_ELEMENTS; i++)\n        l += data[i];\n    } else {\n      for (i = 0, l = 0; i < NB_ELEMENTS; i++)\n        l += stm_load_long(&data[i]);\n    }\n    assert(l == 0);\n    stm_commit();\n  }\n\n  stm_get_stats(\"nb_aborts\", &d->nb_aborts);\n  stm_get_stats(\"nb_aborts_1\", &d->nb_aborts_1);\n  stm_get_stats(\"nb_aborts_2\", &d->nb_aborts_2);\n  stm_get_stats(\"nb_aborts_locked_read\", &d->nb_aborts_locked_read);\n  stm_get_stats(\"nb_aborts_locked_write\", &d->nb_aborts_locked_write);\n  stm_get_stats(\"nb_aborts_validate_read\", &d->nb_aborts_validate_read);\n  stm_get_stats(\"nb_aborts_validate_write\", &d->nb_aborts_validate_write);\n  stm_get_stats(\"nb_aborts_validate_commit\", &d->nb_aborts_validate_commit);\n  stm_get_stats(\"nb_aborts_invalid_memory\", &d->nb_aborts_invalid_memory);\n  stm_get_stats(\"nb_aborts_killed\", &d->nb_aborts_killed);\n  stm_get_stats(\"locked_reads_ok\", &d->locked_reads_ok);\n  stm_get_stats(\"locked_reads_failed\", &d->locked_reads_failed);\n  stm_get_stats(\"max_retries\", &d->max_retries);\n\n  stm_exit_thread();\n\n  return NULL;\n}\n\nint main(int argc, char **argv)\n{\n  struct option long_options[] = {\n    // These options don't set a flag\n    {\"help\",                      no_argument,       NULL, 'h'},\n    {\"contention-manager\",        required_argument, NULL, 'c'},\n    {\"duration\",                  required_argument, NULL, 'd'},\n    {\"irrevocable-percent\",       required_argument, NULL, 'i'},\n    {\"num-threads\",               required_argument, NULL, 'n'},\n    {NULL, 0, NULL, 0}\n  };\n\n  int i, c;\n  unsigned long aborts, aborts_1, aborts_2,\n    aborts_locked_read, aborts_locked_write,\n    aborts_validate_read, aborts_validate_write, aborts_validate_commit,\n    aborts_invalid_memory, aborts_killed,\n    locked_reads_ok, locked_reads_failed, max_retries;\n  thread_data_t *td;\n  pthread_t *threads;\n  pthread_attr_t attr;\n  struct timespec timeout;\n  int duration = DEFAULT_DURATION;\n  int irrevocable_percent = DEFAULT_IRREVOCABLE_PERCENT;\n  int nb_threads = DEFAULT_NB_THREADS;\n  char *cm = NULL;\n\n  while(1) {\n    i = 0;\n    c = getopt_long(argc, argv, \"hc:d:i:n:\", long_options, &i);\n\n    if(c == -1)\n      break;\n\n    if(c == 0 && long_options[i].flag == 0)\n      c = long_options[i].val;\n\n    switch(c) {\n     case 0:\n       /* Flag is automatically set */\n       break;\n     case 'h':\n       printf(\"irrevocability -- STM stress test \"\n              \"\\n\"\n              \"Usage:\\n\"\n              \"  irrevocability [options...]\\n\"\n              \"\\n\"\n              \"Options:\\n\"\n              \"  -h, --help\\n\"\n              \"        Print this message\\n\"\n              \"  -c, --contention-manager <string>\\n\"\n              \"        Contention manager for resolving conflicts (default=suicide)\\n\"\n              \"  -d, --duration <int>\\n\"\n              \"        Test duration in milliseconds (0=infinite, default=\" XSTR(DEFAULT_DURATION) \")\\n\"\n              \"  -i, --irrevocable-percent <int>\\n\"\n              \"         (default=\" XSTR(DEFAULT_IRREVOCABLE_PERCENT) \")\\n\"\n              \"  -n, --num-threads <int>\\n\"\n              \"        Number of threads (default=\" XSTR(DEFAULT_NB_THREADS) \")\\n\"\n         );\n       exit(0);\n     case 'c':\n       cm = optarg;\n       break;\n     case 'd':\n       duration = atoi(optarg);\n       break;\n     case 'n':\n       nb_threads = atoi(optarg);\n       break;\n     case 'i':\n       irrevocable_percent = atoi(optarg);\n       break;\n     case '?':\n       printf(\"Use -h or --help for help\\n\");\n       exit(0);\n     default:\n       exit(1);\n    }\n  }\n\n  assert(duration >= 0);\n  assert(nb_threads > 0);\n  assert(irrevocable_percent >= 0 && irrevocable_percent <= 100);\n\n  printf(\"CM           : %s\\n\", (cm == NULL ? \"DEFAULT\" : cm));\n  printf(\"Duration     : %d\\n\", duration);\n  printf(\"Irrevocable  : %d%%\\n\", irrevocable_percent);\n  printf(\"Nb threads   : %d\\n\", nb_threads);\n\n  for (i = 0; i < NB_ELEMENTS; i++)\n    data[i] = 0;\n\n  /* Init STM */\n  printf(\"Initializing STM\\n\");\n  stm_init();\n\n  /* Set contention manager */\n  if (cm != NULL) {\n    if (stm_set_parameter(\"cm_policy\", cm) == 0)\n      printf(\"WARNING: cannot set contention manager \\\"%s\\\"\\n\", cm);\n  }\n\n  printf(\"int/long/ptr/word size: %d/%d/%d/%d\\n\",\n         (int)sizeof(int),\n         (int)sizeof(long),\n         (int)sizeof(void *),\n         (int)sizeof(stm_word_t));\n\n  stop = 0;\n\n  printf(\"TESTING CONCURRENT UPDATES...\\n\");\n\n  timeout.tv_sec = duration / 1000;\n  timeout.tv_nsec = (duration % 1000) * 1000000;\n\n  if ((td = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  pthread_attr_init(&attr);\n  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);\n  for (i = 0; i < nb_threads; i++) {\n    td[i].nb_aborts = 0;\n    td[i].nb_aborts_1 = 0;\n    td[i].nb_aborts_2 = 0;\n    td[i].nb_aborts_locked_read = 0;\n    td[i].nb_aborts_locked_write = 0;\n    td[i].nb_aborts_validate_read = 0;\n    td[i].nb_aborts_validate_write = 0;\n    td[i].nb_aborts_validate_commit = 0;\n    td[i].nb_aborts_invalid_memory = 0;\n    td[i].nb_aborts_killed = 0;\n    td[i].locked_reads_ok = 0;\n    td[i].locked_reads_failed = 0;\n    td[i].max_retries = 0;\n    td[i].irrevocable_percent = irrevocable_percent;\n    if (pthread_create(&threads[i], &attr, test, (void *)(&td[i])) != 0) {\n      fprintf(stderr, \"Error creating thread\\n\");\n      exit(1);\n    }\n  }\n  pthread_attr_destroy(&attr);\n  nanosleep(&timeout, NULL);\n  printf(\"STOPPING...\\n\");\n  stop = 1;\n  for (i = 0; i < nb_threads; i++) {\n    if (pthread_join(threads[i], NULL) != 0) {\n      fprintf(stderr, \"Error waiting for thread completion\\n\");\n      exit(1);\n    }\n  }\n\n  printf(\"PASSED\\n\");\n  printf(\"Number of successful irrevocable-serial executions   : %ld\\n\", nb_irrevocable_serial);\n  printf(\"Number of successful irrevocable-parallel executions : %ld\\n\", nb_irrevocable_parallel);\n\n  aborts = 0;\n  aborts_1 = 0;\n  aborts_2 = 0;\n  aborts_locked_read = 0;\n  aborts_locked_write = 0;\n  aborts_validate_read = 0;\n  aborts_validate_write = 0;\n  aborts_validate_commit = 0;\n  aborts_invalid_memory = 0;\n  aborts_killed = 0;\n  locked_reads_ok = 0;\n  locked_reads_failed = 0;\n  max_retries = 0;\n  for (i = 0; i < nb_threads; i++) {\n    printf(\"Thread %d\\n\", i);\n    printf(\"  #aborts     : %lu\\n\", td[i].nb_aborts);\n    printf(\"    #lock-r   : %lu\\n\", td[i].nb_aborts_locked_read);\n    printf(\"    #lock-w   : %lu\\n\", td[i].nb_aborts_locked_write);\n    printf(\"    #val-r    : %lu\\n\", td[i].nb_aborts_validate_read);\n    printf(\"    #val-w    : %lu\\n\", td[i].nb_aborts_validate_write);\n    printf(\"    #val-c    : %lu\\n\", td[i].nb_aborts_validate_commit);\n    printf(\"    #inv-mem  : %lu\\n\", td[i].nb_aborts_invalid_memory);\n    printf(\"    #killed   : %lu\\n\", td[i].nb_aborts_killed);\n    printf(\"  #aborts>=1  : %lu\\n\", td[i].nb_aborts_1);\n    printf(\"  #aborts>=2  : %lu\\n\", td[i].nb_aborts_2);\n    printf(\"  #lr-ok      : %lu\\n\", td[i].locked_reads_ok);\n    printf(\"  #lr-failed  : %lu\\n\", td[i].locked_reads_failed);\n    printf(\"  Max retries : %lu\\n\", td[i].max_retries);\n    aborts += td[i].nb_aborts;\n    aborts_1 += td[i].nb_aborts_1;\n    aborts_2 += td[i].nb_aborts_2;\n    aborts_locked_read += td[i].nb_aborts_locked_read;\n    aborts_locked_write += td[i].nb_aborts_locked_write;\n    aborts_validate_read += td[i].nb_aborts_validate_read;\n    aborts_validate_write += td[i].nb_aborts_validate_write;\n    aborts_validate_commit += td[i].nb_aborts_validate_commit;\n    aborts_invalid_memory += td[i].nb_aborts_invalid_memory;\n    aborts_killed += td[i].nb_aborts_killed;\n    locked_reads_ok += td[i].locked_reads_ok;\n    locked_reads_failed += td[i].locked_reads_failed;\n    if (max_retries < td[i].max_retries)\n      max_retries = td[i].max_retries;\n  }\n  printf(\"Duration      : %d (ms)\\n\", duration);\n  printf(\"#aborts       : %lu (%f / s)\\n\", aborts, aborts * 1000.0 / duration);\n  printf(\"  #lock-r     : %lu (%f / s)\\n\", aborts_locked_read, aborts_locked_read * 1000.0 / duration);\n  printf(\"  #lock-w     : %lu (%f / s)\\n\", aborts_locked_write, aborts_locked_write * 1000.0 / duration);\n  printf(\"  #val-r      : %lu (%f / s)\\n\", aborts_validate_read, aborts_validate_read * 1000.0 / duration);\n  printf(\"  #val-w      : %lu (%f / s)\\n\", aborts_validate_write, aborts_validate_write * 1000.0 / duration);\n  printf(\"  #val-c      : %lu (%f / s)\\n\", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration);\n  printf(\"  #inv-mem    : %lu (%f / s)\\n\", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration);\n  printf(\"  #killed     : %lu (%f / s)\\n\", aborts_killed, aborts_killed * 1000.0 / duration);\n  printf(\"#aborts>=1    : %lu (%f / s)\\n\", aborts_1, aborts_1 * 1000.0 / duration);\n  printf(\"#aborts>=2    : %lu (%f / s)\\n\", aborts_2, aborts_2 * 1000.0 / duration);\n  printf(\"#lr-ok        : %lu (%f / s)\\n\", locked_reads_ok, locked_reads_ok * 1000.0 / duration);\n  printf(\"#lr-failed    : %lu (%f / s)\\n\", locked_reads_failed, locked_reads_failed * 1000.0 / duration);\n  printf(\"Max retries   : %lu\\n\", max_retries);\n\n  /* Cleanup STM */\n  stm_exit();\n\n  return 0;\n}\n"
  },
  {
    "path": "stms/tinystm/test/regression/perf.c",
    "content": "/*\n * File:\n *   perf.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Performance regression test.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n\n#include \"stm.h\"\n#include \"mod_mem.h\"\n\n/* Increment the value of the global clock (used for timestamps).\n * Hidden to tinySTM users. */\nvoid stm_inc_clock(void);\n\n__attribute__((aligned(64)))\nstm_word_t global_ctr[1000] = {0};\n\n#define MEASURE_NB 1000\n\nstatic inline uint64_t\nrdtsc(void)\n{\n  uint32_t a, d;\n  asm volatile( \"rdtsc\\n\\t\" : \"=a\" (a), \"=d\" (d));\n  return (((uint64_t)d) << 32) | (((uint64_t)a) & 0xffffffff);\n}\n\nstatic int compar(const void *a, const void *b)\n{\n  return *((uint64_t *)a) - *((uint64_t *)b);\n}\n\nstatic void remove_cst_cost(uint64_t *m, size_t size, uint64_t cost)\n{\n  size_t i;\n  for (i = 0; i < size; i++) {\n    m[i] -= cost;\n  }\n}\n\nstatic void stats(uint64_t *m, size_t size, uint64_t *min, double *avg, uint64_t *median)\n{\n  size_t i;\n  /* Find median value */\n  qsort(m, size, sizeof(uint64_t), compar);\n  *median = m[(size/2)-1];\n  /* Find minimal and calculate average */\n  *min = ~0UL;\n  *avg = 0.0;\n  for (i = 0; i < size; i++) {\n    *avg += m[i];\n    if (m[i] < *min)\n      *min = m[i];\n  }\n  *avg = *avg / size;\n}\n\nstatic void test1load(int ro)\n{\n  uint64_t m_s[MEASURE_NB];\n  uint64_t m_r[MEASURE_NB];\n  uint64_t m_c[MEASURE_NB];\n  uint64_t m_rdtsc;\n  uint64_t start;\n  uint64_t min;\n  double avg;\n  uint64_t med;\n  unsigned long i;\n  stm_tx_attr_t _a = {{.read_only = ro}};\n\n  m_rdtsc = ~0UL;\n  for (i = 0; i < MEASURE_NB; i++) {\n    start = rdtsc();\n    start = rdtsc() - start;\n    if (start < m_rdtsc)\n      m_rdtsc = start;\n  } \n\n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e;\n    start = rdtsc();\n    _e = stm_start(_a);\n    m_s[i] = rdtsc() - start;\n    sigsetjmp(*_e, 0); \n    stm_load(&global_ctr[0]);\n    stm_inc_clock();\n    stm_commit();\n  }\n\n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    start = rdtsc();\n    stm_load(&global_ctr[0]);\n    m_r[i] = rdtsc() - start;\n    stm_inc_clock();\n    stm_commit();\n  }\n  \n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    stm_load(&global_ctr[0]);\n    stm_inc_clock();\n    start = rdtsc();\n    stm_commit();\n    m_c[i] = rdtsc() - start;\n  }\n \n  remove_cst_cost(m_s, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_r, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_c, MEASURE_NB, m_rdtsc);\n\n  if (ro) \n    printf(\"RO transaction - 1 load\\n\");\n  else\n    printf(\"RW transaction - 1 load\\n\");\n\n  printf(\"%12s %12s %12s %12s\\n\", \"\", \"min\", \"avg\", \"med\");\n  stats(m_s, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"start\", (unsigned long)min, avg, (unsigned long)med);\n  stats(m_r, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"load\", (unsigned long)min, avg, (unsigned long)med);\n  stats(m_c, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"commit\", (unsigned long)min, avg, (unsigned long)med);\n}\n\nstatic void testnload(int ro, size_t load_nb)\n{\n  uint64_t m_s[MEASURE_NB];\n  uint64_t m_r[MEASURE_NB];\n  uint64_t m_c[MEASURE_NB];\n  uint64_t m_rdtsc;\n  uint64_t start;\n  uint64_t min;\n  double avg;\n  uint64_t med;\n  unsigned long i;\n  size_t j;\n  stm_tx_attr_t _a = {{.read_only = ro}};\n\n  m_rdtsc = ~0UL;\n  for (i = 0; i < MEASURE_NB; i++) {\n    start = rdtsc();\n    start = rdtsc() - start;\n    if (start < m_rdtsc)\n      m_rdtsc = start;\n  } \n\n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e;\n    start = rdtsc();\n    _e = stm_start(_a);\n    m_s[i] = rdtsc() - start;\n    sigsetjmp(*_e, 0); \n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    stm_inc_clock();\n    stm_commit();\n  }\n\n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    start = rdtsc();\n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    m_r[i] = rdtsc() - start;\n    stm_inc_clock();\n    stm_commit();\n  }\n  \n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    stm_inc_clock();\n    start = rdtsc();\n    stm_commit();\n    m_c[i] = rdtsc() - start;\n  }\n \n  remove_cst_cost(m_s, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_r, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_c, MEASURE_NB, m_rdtsc);\n\n  if (ro) \n    printf(\"RO transaction - %lu load\\n\", (unsigned long)load_nb);\n  else\n    printf(\"RW transaction - %lu load\\n\", (unsigned long)load_nb);\n\n  printf(\"%12s %12s %12s %12s\\n\", \"\", \"min\", \"avg\", \"med\");\n  stats(m_s, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"start\", (unsigned long)min, avg, (unsigned long)med);\n  stats(m_r, MEASURE_NB, &min, &avg, &med); \n  if (load_nb)\n    printf(\"%12s %12lu %12.2f %12lu\\n\", \"load\", (unsigned long)min/load_nb, avg/load_nb, (unsigned long)med/load_nb);\n  stats(m_c, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"commit\", (unsigned long)min, avg, (unsigned long)med);\n}\n\nstatic void testnloadnstore(size_t load_nb, size_t store_nb)\n{\n  uint64_t m_s[MEASURE_NB];\n  uint64_t m_r[MEASURE_NB];\n  uint64_t m_w[MEASURE_NB];\n  uint64_t m_c[MEASURE_NB];\n  uint64_t m_rdtsc;\n  uint64_t start;\n  uint64_t min;\n  double avg;\n  uint64_t med;\n  unsigned long i;\n  size_t j;\n  stm_tx_attr_t _a = {{.read_only = 0}};\n\n  m_rdtsc = ~0UL;\n  for (i = 0; i < MEASURE_NB; i++) {\n    start = rdtsc();\n    start = rdtsc() - start;\n    if (start < m_rdtsc)\n      m_rdtsc = start;\n  } \n\n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e;\n    start = rdtsc();\n    _e = stm_start(_a);\n    m_s[i] = rdtsc() - start;\n    sigsetjmp(*_e, 0); \n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    for (j = 0; j < store_nb; j++)\n      stm_store(&global_ctr[j], (stm_word_t)0);\n    stm_inc_clock();\n    stm_commit();\n  }\n\n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    start = rdtsc();\n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    m_r[i] = rdtsc() - start;\n    for (j = 0; j < store_nb; j++)\n      stm_store(&global_ctr[j], (stm_word_t)0);\n    stm_inc_clock();\n    stm_commit();\n  }\n  \n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    start = rdtsc();\n    for (j = 0; j < store_nb; j++)\n      stm_store(&global_ctr[j], (stm_word_t)0);\n    m_w[i] = rdtsc() - start;\n    stm_inc_clock();\n    stm_commit();\n  }\n  \n  for (i = 0; i < MEASURE_NB; i++) {\n    sigjmp_buf *_e = stm_start(_a);\n    sigsetjmp(*_e, 0); \n    for (j = 0; j < load_nb; j++)\n      stm_load(&global_ctr[j]);\n    for (j = 0; j < store_nb; j++)\n      stm_store(&global_ctr[j], (stm_word_t)0);\n    stm_inc_clock();\n    start = rdtsc();\n    stm_commit();\n    m_c[i] = rdtsc() - start;\n  }\n \n  remove_cst_cost(m_s, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_r, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_w, MEASURE_NB, m_rdtsc);\n  remove_cst_cost(m_c, MEASURE_NB, m_rdtsc);\n\n  printf(\"RW transaction - %lu load - %lu store\\n\", (unsigned long)load_nb, (unsigned long)store_nb);\n\n  printf(\"%12s %12s %12s %12s\\n\", \"\", \"min\", \"avg\", \"med\");\n  stats(m_s, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"start\", (unsigned long)min, avg, (unsigned long)med);\n  stats(m_r, MEASURE_NB, &min, &avg, &med); \n  if (load_nb)\n    printf(\"%12s %12lu %12.2f %12lu\\n\", \"load\", (unsigned long)min/load_nb, avg/load_nb, (unsigned long)med/load_nb);\n  stats(m_w, MEASURE_NB, &min, &avg, &med); \n  if (store_nb)\n    printf(\"%12s %12lu %12.2f %12lu\\n\", \"store\", (unsigned long)min/store_nb, avg/store_nb, (unsigned long)med/store_nb);\n  stats(m_c, MEASURE_NB, &min, &avg, &med); \n  printf(\"%12s %12lu %12.2f %12lu\\n\", \"commit\", (unsigned long)min, avg, (unsigned long)med);\n}\n\n/* TODO\n *  Add clock perturbation to avoid fast commit\n *  Add write after write / load after write measurements\n *  Add stm_malloc/stm_free measurements\n */\n\nint main(int argc, char **argv)\n{\n  /* Init STM */\n  stm_init();\n  mod_mem_init(0);\n  /* Create transaction */\n  stm_init_thread();\n\n  /* Testing */\n  test1load(1);\n  test1load(0);\n  testnload(1, 100);\n  testnload(0, 100);\n  testnloadnstore(100, 20);\n  testnloadnstore(100, 20);\n\n  /* Free transaction */\n  stm_exit_thread();\n  /* Cleanup STM */\n  stm_exit();\n  return 0;\n}\n"
  },
  {
    "path": "stms/tinystm/test/regression/types.c",
    "content": "/*\n * File:\n *   types.c\n * Author(s):\n *   Pascal Felber <pascal.felber@unine.ch>\n *   Patrick Marlier <patrick.marlier@unine.ch>\n * Description:\n *   Regression test for various data types.\n *\n * Copyright (c) 2007-2014.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation, version 2\n * of the License.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * This program has a dual license and can also be distributed\n * under the terms of the MIT license.\n */\n\n#ifdef NDEBUG\n# undef NDEBUG\n#endif\n\n#include <assert.h>\n#include <math.h>\n#include <pthread.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"stm.h\"\n#include \"wrappers.h\"\n\nunion {\n  uint8_t u8[256];\n  uint16_t u16[128];\n  uint32_t u32[64];\n  uint64_t u64[32];\n  int8_t s8[256];\n  int16_t s16[128];\n  int32_t s32[64];\n  int64_t s64[32];\n  float f[64];\n  double d[32];\n} tab, tab_ro;\n\ntypedef union {\n  uint8_t u8;\n  uint16_t u16;\n  uint32_t u32;\n  uint64_t u64;\n  int8_t s8;\n  int16_t s16;\n  int32_t s32;\n  int64_t s64;\n  float f;\n  double d;\n  void *p;\n} val_t;\n\nenum {\n  TYPE_UINT8,\n  TYPE_UINT16,\n  TYPE_UINT32,\n  TYPE_UINT64,\n  TYPE_CHAR,\n  TYPE_UCHAR,\n  TYPE_SHORT,\n  TYPE_USHORT,\n  TYPE_INT,\n  TYPE_UINT,\n  TYPE_LONG,\n  TYPE_ULONG,\n  TYPE_FLOAT,\n  TYPE_DOUBLE,\n  TYPE_BYTES\n};\n\n#define NB_THREADS                      4\n#define DURATION                        5000\n\nvolatile int verbose;\nvolatile int stop;\n\nstatic void compare(int idx, val_t val, int type, int size)\n{\n  int i;\n  val_t v;\n\n  switch(type) {\n   case TYPE_UINT8:\n     for (i = 0; i < 256 / sizeof(uint8_t); i++) {\n       v.u8 = stm_load_u8(&tab.u8[i]);\n       assert(i == idx ? v.u8 == val.u8 : v.u8 == tab_ro.u8[i]);\n     }\n     break;\n   case TYPE_UINT16:\n     for (i = 0; i < 256 / sizeof(uint16_t); i++) {\n       v.u16 = stm_load_u16(&tab.u16[i]);\n       assert(i == idx ? v.u16 == val.u16 : v.u16 == tab_ro.u16[i]);\n     }\n     break;\n   case TYPE_UINT32:\n     for (i = 0; i < 256 / sizeof(uint32_t); i++) {\n       v.u32 = stm_load_u32(&tab.u32[i]);\n       assert(i == idx ? v.u32 == val.u32 : v.u32 == tab_ro.u32[i]);\n     }\n     break;\n   case TYPE_UINT64:\n     for (i = 0; i < 256 / sizeof(uint64_t); i++) {\n       v.u64 = stm_load_u64(&tab.u64[i]);\n       assert(i == idx ? v.u64 == val.u64 : v.u64 == tab_ro.u64[i]);\n     }\n     break;\n   case TYPE_CHAR:\n     for (i = 0; i < 256 / sizeof(unsigned char); i++) {\n       v.s8 = (int8_t)stm_load_char((char *)&tab.s8[i]);\n       assert(i == idx ? v.s8 == val.s8 : v.s8 == tab_ro.s8[i]);\n     }\n     break;\n   case TYPE_UCHAR:\n     for (i = 0; i < 256 / sizeof(char); i++) {\n       v.u8 = (uint8_t)stm_load_uchar((unsigned char *)&tab.u8[i]);\n       assert(i == idx ? v.u8 == val.u8 : v.u8 == tab_ro.u8[i]);\n     }\n     break;\n   case TYPE_SHORT:\n     for (i = 0; i < 256 / sizeof(short); i++) {\n       v.s16 = (int16_t)stm_load_short((short *)&tab.s16[i]);\n       assert(i == idx ? v.s16 == val.s16 : v.s16 == tab_ro.s16[i]);\n     }\n     break;\n   case TYPE_USHORT:\n     for (i = 0; i < 256 / sizeof(unsigned short); i++) {\n       v.u16 = (uint16_t)stm_load_ushort((unsigned short *)&tab.u16[i]);\n       assert(i == idx ? v.u16 == val.u16 : v.u16 == tab_ro.u16[i]);\n     }\n     break;\n   case TYPE_INT:\n     for (i = 0; i < 256 / sizeof(int); i++) {\n       v.s32 = (int32_t)stm_load_int((int *)&tab.s32[i]);\n       assert(i == idx ? v.s32 == val.s32 : v.s32 == tab_ro.s32[i]);\n     }\n     break;\n   case TYPE_UINT:\n     for (i = 0; i < 256 / sizeof(unsigned int); i++) {\n       v.u32 = (uint32_t)stm_load_uint((unsigned int *)&tab.u32[i]);\n       assert(i == idx ? v.u32 == val.u32 : v.u32 == tab_ro.u32[i]);\n     }\n     break;\n   case TYPE_LONG:\n     for (i = 0; i < 256 / sizeof(long); i++) {\n       if (sizeof(long) == 4) {\n         v.s32 = (int32_t)stm_load_long((long *)&tab.s32[i]);\n         assert(i == idx ? v.s32 == val.s32 : v.s32 == tab_ro.s32[i]);\n       } else {\n         v.s64 = (int64_t)stm_load_long((long *)&tab.s64[i]);\n         assert(i == idx ? v.s64 == val.s64 : v.s64 == tab_ro.s64[i]);\n       }\n     }\n     break;\n   case TYPE_ULONG:\n     for (i = 0; i < 256 / sizeof(unsigned long); i++) {\n       if (sizeof(long) == 4) {\n         v.u32 = (uint32_t)stm_load_ulong((unsigned long *)&tab.u32[i]);\n         assert(i == idx ? v.u32 == val.u32 : v.u32 == tab_ro.u32[i]);\n       } else {\n         v.u64 = (uint64_t)stm_load_ulong((unsigned long *)&tab.u64[i]);\n         assert(i == idx ? v.u64 == val.u64 : v.u64 == tab_ro.u64[i]);\n       }\n     }\n     break;\n   case TYPE_FLOAT:\n     for (i = 0; i < 256 / sizeof(float); i++) {\n       v.f = stm_load_float(&tab.f[i]);\n       assert(i == idx ? (isnan(v.f) && isnan(val.f)) || v.f == val.f : (isnan(v.f) && isnan(tab_ro.f[i])) || v.f == tab_ro.f[i]);\n     }\n     break;\n   case TYPE_DOUBLE:\n     for (i = 0; i < 256 / sizeof(double); i++) {\n       v.d = stm_load_double(&tab.d[i]);\n       assert(i == idx ? (isnan(v.d) && isnan(val.d)) || v.d == val.d : (isnan(v.d) && isnan(tab_ro.d[i])) || v.d == tab_ro.d[i]);\n     }\n     break;\n   case TYPE_BYTES:\n     for (i = 0; i < 256 / sizeof(uint8_t); i++) {\n       v.u8 = stm_load_u8(&tab.u8[i]);\n       assert(i >= idx && i < idx + size ? v.u8 == ((uint8_t *)val.p)[i - idx] : v.u8 == tab_ro.u8[i]);\n     }\n     break;\n  }\n}\n\nstatic void test_loads()\n{\n  int i, j;\n  val_t val;\n  sigjmp_buf *e;\n\n  e = stm_start((stm_tx_attr_t)0);\n  if (e != NULL)\n    sigsetjmp(*e, 0);\n\n  if (verbose)\n    printf(\"- Testing uint8_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint8_t); i++) {\n    val.u8 = stm_load_u8(&tab.u8[i]);\n    assert(val.u8 == tab_ro.u8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing uint16_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint16_t); i++) {\n    val.u16 = stm_load_u16(&tab.u16[i]);\n    assert(val.u16 == tab_ro.u16[i]);\n  }\n  if (verbose)\n    printf(\"- Testing misaligned uint16_t\\n\");\n  for (i = 1; i < 256 - sizeof(uint16_t); i += sizeof(uint16_t)) {\n    val.u16 = stm_load_u16((uint16_t *)&tab.u8[i]);\n    assert(val.u16 == *(uint16_t *)&tab_ro.u8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing uint32_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint32_t); i++) {\n    val.u32 = stm_load_u32(&tab.u32[i]);\n    assert(val.u32 == tab_ro.u32[i]);\n  }\n  if (verbose)\n    printf(\"- Testing misaligned uint32_t\\n\");\n  for (j = 1; j < sizeof(uint32_t); j++) {\n    for (i = j; i < 256 - sizeof(uint32_t); i += sizeof(uint32_t)) {\n      val.u32 = stm_load_u32((uint32_t *)&tab.u8[i]);\n      assert(val.u32 == *(uint32_t *)&tab_ro.u8[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing uint64_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint64_t); i++) {\n    val.u64 = stm_load_u64(&tab.u64[i]);\n    assert(val.u64 == tab_ro.u64[i]);\n  }\n  if (verbose)\n    printf(\"- Testing misaligned uint64_t\\n\");\n  for (j = 1; j < sizeof(uint64_t); j++) {\n    for (i = j; i < 256 - sizeof(uint64_t); i += sizeof(uint64_t)) {\n      val.u64 = stm_load_u64((uint64_t *)&tab.u8[i]);\n      assert(val.u64 == *(uint64_t *)&tab_ro.u8[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing char\\n\");\n  for (i = 0; i < 256 / sizeof(char); i++) {\n    val.s8 = (int8_t)stm_load_char((volatile char *)&tab.s8[i]);\n    assert(val.s8 == tab_ro.s8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing unsigned char\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned char); i++) {\n    val.u8 = (uint8_t)stm_load_uchar((volatile unsigned char *)&tab.u8[i]);\n    assert(val.u8 == tab_ro.u8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing short\\n\");\n  for (i = 0; i < 256 / sizeof(short); i++) {\n    val.s16 = (int16_t)stm_load_short((volatile short *)&tab.s16[i]);\n    assert(val.s16 == tab_ro.s16[i]);\n  }\n  if (verbose)\n    printf(\"- Testing unsigned short\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned short); i++) {\n    val.u16 = (uint16_t)stm_load_ushort((volatile unsigned short *)&tab.u16[i]);\n    assert(val.u16 == tab_ro.u16[i]);\n  }\n  if (verbose)\n    printf(\"- Testing int\\n\");\n  for (i = 0; i < 256 / sizeof(int); i++) {\n    val.s32 = (int32_t)stm_load_int((volatile int *)&tab.s32[i]);\n    assert(val.s32 == tab_ro.s32[i]);\n  }\n  if (verbose)\n    printf(\"- Testing unsigned int\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned int); i++) {\n    val.u32 = (uint32_t)stm_load_uint((volatile unsigned int *)&tab.u32[i]);\n    assert(val.u32 == tab_ro.u32[i]);\n  }\n  if (verbose)\n    printf(\"- Testing long\\n\");\n  for (i = 0; i < 256 / sizeof(long); i++) {\n    if (sizeof(long) == 4) {\n      val.s32 = (int32_t)stm_load_long((volatile long *)&tab.s32[i]);\n      assert(val.s32 == tab_ro.s32[i]);\n    } else {\n      val.s64 = (int64_t)stm_load_long((volatile long *)&tab.s64[i]);\n      assert(val.s64 == tab_ro.s64[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing unsigned long\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned long); i++) {\n    if (sizeof(long) == 4) {\n      val.u32 = (uint32_t)stm_load_ulong((volatile unsigned long *)&tab.u32[i]);\n      assert(val.u32 == tab_ro.u32[i]);\n    } else {\n      val.u64 = (uint64_t)stm_load_ulong((volatile unsigned long *)&tab.u64[i]);\n      assert(val.u64 == tab_ro.u64[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing float\\n\");\n  for (i = 0; i < 256 / sizeof(float); i++) {\n    val.f = stm_load_float(&tab.f[i]);\n    assert((isnan(val.f) && isnan(tab_ro.f[i])) || val.f == tab_ro.f[i]);\n  }\n  if (verbose)\n    printf(\"- Testing double\\n\");\n  for (i = 0; i < 256 / sizeof(double); i++) {\n    val.d = stm_load_double(&tab.d[i]);\n    assert((isnan(val.d) && isnan(tab_ro.d[i])) || val.d == tab_ro.d[i]);\n  }\n\n  stm_commit();\n}\n\nstatic void test_stores()\n{\n  int i, j;\n  val_t val, bytes;\n  sigjmp_buf *e;\n\n  e = stm_start((stm_tx_attr_t)0);\n  if (e != NULL)\n    sigsetjmp(*e, 0);\n\n  if (verbose)\n    printf(\"- Testing uint8_t\\n\");\n  for (i = 0; i < 256; i++) {\n    val.u8 = ~tab_ro.u8[i];\n    stm_store_u8(&tab.u8[i], val.u8);\n    compare(i, val, TYPE_UINT8, 0);\n    stm_store_u8(&tab.u8[i], tab_ro.u8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing uint16_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint16_t); i++) {\n    val.u16 = ~tab_ro.u16[i];\n    stm_store_u16(&tab.u16[i], val.u16);\n    compare(i, val, TYPE_UINT16, 0);\n    stm_store_u16(&tab.u16[i], tab_ro.u16[i]);\n  }\n  if (verbose)\n    printf(\"- Testing misaligned uint16_t\\n\");\n  for (i = 1; i < 256 - sizeof(uint16_t); i += sizeof(uint16_t)) {\n    val.u16 = ~*(uint16_t *)&tab_ro.u8[i];\n    stm_store_u16((uint16_t *)&tab.u8[i], val.u16);\n    bytes.p = &val.u16;\n    compare(i, bytes, TYPE_BYTES, sizeof(uint16_t));\n    stm_store_u16((uint16_t *)&tab.u8[i], *(uint16_t *)&tab_ro.u8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing uint32_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint32_t); i++) {\n    val.u32 = ~tab_ro.u32[i];\n    stm_store_u32(&tab.u32[i], val.u32);\n    compare(i, val, TYPE_UINT32, 0);\n    stm_store_u32(&tab.u32[i], tab_ro.u32[i]);\n  }\n  if (verbose)\n    printf(\"- Testing misaligned uint32_t\\n\");\n  for (j = 1; j < sizeof(uint32_t); j++) {\n    for (i = j; i < 256 - sizeof(uint32_t); i += sizeof(uint32_t)) {\n      val.u32 = ~*(uint32_t *)&tab_ro.u8[i];\n      stm_store_u32((uint32_t *)&tab.u8[i], val.u32);\n      bytes.p = &val.u32;\n      compare(i, bytes, TYPE_BYTES, sizeof(uint32_t));\n      stm_store_u32((uint32_t *)&tab.u8[i], *(uint32_t *)&tab_ro.u8[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing uint64_t\\n\");\n  for (i = 0; i < 256 / sizeof(uint64_t); i++) {\n    val.u64 = ~tab_ro.u64[i];\n    stm_store_u64(&tab.u64[i], val.u64);\n    compare(i, val, TYPE_UINT64, 0);\n    stm_store_u64(&tab.u64[i], tab_ro.u64[i]);\n  }\n  if (verbose)\n    printf(\"- Testing misaligned uint64_t\\n\");\n  for (j = 1; j < sizeof(uint64_t); j++) {\n    for (i = j; i < 256 - sizeof(uint32_t); i += sizeof(uint32_t)) {\n      val.u32 = ~*(uint32_t *)&tab_ro.u8[i];\n      stm_store_u32((uint32_t *)&tab.u8[i], val.u32);\n      bytes.p = &val.u32;\n      compare(i, bytes, TYPE_BYTES, sizeof(uint32_t));\n      stm_store_u32((uint32_t *)&tab.u8[i], *(uint32_t *)&tab_ro.u8[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing char\\n\");\n  for (i = 0; i < 256 / sizeof(char); i++) {\n    val.s8 = ~tab_ro.s8[i];\n    stm_store_char((volatile char *)&tab.s8[i], (char)val.s8);\n    compare(i, val, TYPE_CHAR, 0);\n    stm_store_char((volatile char *)&tab.s8[i], (char)tab_ro.s8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing unsigned char\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned char); i++) {\n    val.u8 = ~tab_ro.u8[i];\n    stm_store_uchar((volatile unsigned char *)&tab.u8[i], (unsigned char)val.u8);\n    compare(i, val, TYPE_UCHAR, 0);\n    stm_store_uchar((volatile unsigned char *)&tab.u8[i], (unsigned char)tab_ro.u8[i]);\n  }\n  if (verbose)\n    printf(\"- Testing short\\n\");\n  for (i = 0; i < 256 / sizeof(short); i++) {\n    val.s16 = ~tab_ro.s16[i];\n    stm_store_short((volatile short *)&tab.s16[i], (short)val.s16);\n    compare(i, val, TYPE_SHORT, 0);\n    stm_store_short((volatile short *)&tab.s16[i], (short)tab_ro.s16[i]);\n  }\n  if (verbose)\n    printf(\"- Testing unsigned short\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned short); i++) {\n    val.u16 = ~tab_ro.u16[i];\n    stm_store_ushort((volatile unsigned short *)&tab.u16[i], (unsigned short)val.u16);\n    compare(i, val, TYPE_USHORT, 0);\n    stm_store_ushort((volatile unsigned short *)&tab.u16[i], (unsigned short)tab_ro.u16[i]);\n  }\n  if (verbose)\n    printf(\"- Testing int\\n\");\n  for (i = 0; i < 256 / sizeof(int); i++) {\n    val.s32 = ~tab_ro.s32[i];\n    stm_store_int((volatile int *)&tab.s32[i], (int)val.s32);\n    compare(i, val, TYPE_INT, 0);\n    stm_store_int((volatile int *)&tab.s32[i], (int)tab_ro.s32[i]);\n  }\n  if (verbose)\n    printf(\"- Testing unsigned int\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned int); i++) {\n    val.u32 = ~tab_ro.u32[i];\n    stm_store_uint((volatile unsigned int *)&tab.u32[i], (unsigned int)val.u32);\n    compare(i, val, TYPE_UINT, 0);\n    stm_store_uint((volatile unsigned int *)&tab.u32[i], (unsigned int)tab_ro.u32[i]);\n  }\n  if (verbose)\n    printf(\"- Testing long\\n\");\n  for (i = 0; i < 256 / sizeof(long); i++) {\n    if (sizeof(long) == 4) {\n      val.s32 = ~tab_ro.s32[i];\n      stm_store_long((volatile long *)&tab.s32[i], (long)val.s32);\n      compare(i, val, TYPE_LONG, 0);\n      stm_store_long((volatile long *)&tab.s32[i], (long)tab_ro.s32[i]);\n    } else {\n      val.s64 = ~tab_ro.s64[i];\n      stm_store_long((volatile long *)&tab.s64[i], (long)val.s64);\n      compare(i, val, TYPE_LONG, 0);\n      stm_store_long((volatile long *)&tab.s64[i], (long)tab_ro.s64[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing unsigned long\\n\");\n  for (i = 0; i < 256 / sizeof(unsigned long); i++) {\n    if (sizeof(long) == 4) {\n      val.u32 = ~tab_ro.u32[i];\n      stm_store_ulong((volatile unsigned long *)&tab.u32[i], (unsigned long)val.u32);\n      compare(i, val, TYPE_ULONG, 0);\n      stm_store_ulong((volatile unsigned long *)&tab.u32[i], (unsigned long)tab_ro.u32[i]);\n    } else {\n      val.s64 = ~tab_ro.s64[i];\n      stm_store_long((volatile long *)&tab.s64[i], (long)val.s64);\n      compare(i, val, TYPE_LONG, 0);\n      stm_store_long((volatile long *)&tab.s64[i], (long)tab_ro.s64[i]);\n    }\n  }\n  if (verbose)\n    printf(\"- Testing float\\n\");\n  for (i = 0; i < 256 / sizeof(float); i++) {\n    val.u32 = ~tab_ro.u32[i];\n    stm_store_float(&tab.f[i], val.f);\n    compare(i, val, TYPE_FLOAT, 0);\n    stm_store_float(&tab.f[i], tab_ro.f[i]);\n  }\n  if (verbose)\n    printf(\"- Testing double\\n\");\n  for (i = 0; i < 256 / sizeof(double); i++) {\n    val.u64 = ~tab_ro.u64[i];\n    stm_store_double(&tab.d[i], val.d);\n    compare(i, val, TYPE_DOUBLE, 0);\n    stm_store_double(&tab.d[i], tab_ro.d[i]);\n  }\n\n  stm_commit();\n}\n\nstatic void *test(void *v)\n{\n  unsigned int seed;\n  int nested, store;\n  sigjmp_buf *e;\n\n  seed = (unsigned int)time(NULL);\n  stm_init_thread();\n  while (stop == 0) {\n    nested = (rand_r(&seed) < RAND_MAX / 3);\n    store = (rand_r(&seed) < RAND_MAX / 3);\n    if (nested) {\n      e = stm_start((stm_tx_attr_t)0);\n      if (e != NULL)\n        sigsetjmp(*e, 0);\n    }\n    if (store)\n      test_stores();\n    else\n      test_loads();\n    if (nested) {\n      stm_commit();\n    }\n  }\n  stm_exit_thread();\n\n  return NULL;\n}\n\nint main(int argc, char **argv)\n{\n  int i;\n  pthread_t *threads;\n  pthread_attr_t attr;\n  struct timespec timeout;\n\n  for (i = 0; i < 256; i++)\n    tab_ro.u8[i] = tab.u8[i] = i;\n\n  /* Init STM */\n  printf(\"Initializing STM\\n\");\n  stm_init();\n\n  printf(\"int/long/ptr/word size: %d/%d/%d/%d\\n\",\n         (int)sizeof(int),\n         (int)sizeof(long),\n         (int)sizeof(void *),\n         (int)sizeof(stm_word_t));\n\n  verbose = 1;\n  stop = 0;\n\n  stm_init_thread();\n\n  printf(\"TESTING LOADS...\\n\");\n  test_loads();\n  printf(\"PASSED\\n\");\n\n  printf(\"TESTING STORES...\\n\");\n  test_stores();\n  printf(\"PASSED\\n\");\n\n  stm_exit_thread();\n\n  printf(\"TESTING CONCURRENT LOADS AND STORES...\\n\");\n  verbose = 0;\n  timeout.tv_sec = DURATION / 1000;\n  timeout.tv_nsec = (DURATION % 1000) * 1000000;\n  if ((threads = (pthread_t *)malloc(NB_THREADS * sizeof(pthread_t))) == NULL) {\n    perror(\"malloc\");\n    exit(1);\n  }\n  pthread_attr_init(&attr);\n  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);\n  for (i = 0; i < NB_THREADS; i++) {\n    if (pthread_create(&threads[i], &attr, test, NULL) != 0) {\n      fprintf(stderr, \"Error creating thread\\n\");\n      exit(1);\n    }\n  }\n  pthread_attr_destroy(&attr);\n  nanosleep(&timeout, NULL);\n  printf(\"STOPPING...\\n\");\n  stop = 1;\n  for (i = 0; i < NB_THREADS; i++) {\n    if (pthread_join(threads[i], NULL) != 0) {\n      fprintf(stderr, \"Error waiting for thread completion\\n\");\n      exit(1);\n    }\n  }\n  printf(\"PASSED\\n\");\n\n  /* Cleanup STM */\n  stm_exit();\n\n  return 0;\n}\n"
  }
]