From aa219dba7ab74072b9658c8774382f58c707cde4 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Thu, 19 Dec 2019 12:53:03 +0000 Subject: [PATCH] sim-se: split futex_map.cc into header and source files To speed up development when modifying the implementation. Change-Id: I1b3c67c86f8faa38ed81a538521b08e256d21a5a Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/29775 Reviewed-by: Brandon Potter Maintainer: Brandon Potter Tested-by: kokoro --- src/sim/SConscript | 1 + src/sim/futex_map.cc | 205 +++++++++++++++++++++++++++++++++++++++++++ src/sim/futex_map.hh | 186 +++------------------------------------ 3 files changed, 218 insertions(+), 174 deletions(-) create mode 100644 src/sim/futex_map.cc diff --git a/src/sim/SConscript b/src/sim/SConscript index 961d89ec8..307c45b27 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -51,6 +51,7 @@ Source('cxx_config_ini.cc') Source('debug.cc') Source('py_interact.cc', add_tags='python') Source('eventq.cc') +Source('futex_map.cc') Source('global_event.cc') Source('init.cc', add_tags='python') Source('init_signals.cc') diff --git a/src/sim/futex_map.cc b/src/sim/futex_map.cc new file mode 100644 index 000000000..e2880aaeb --- /dev/null +++ b/src/sim/futex_map.cc @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2017 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +FutexKey::FutexKey(uint64_t addr_in, uint64_t tgid_in) + : addr(addr_in), tgid(tgid_in) {} + +bool +FutexKey::operator==(const FutexKey &in) const +{ + return addr == in.addr && tgid == in.tgid; +} + +namespace std { + size_t hash::operator()(const FutexKey& in) const + { + size_t hash = 65521; + for (int i = 0; i < sizeof(uint64_t) / sizeof(size_t); i++) { + hash ^= (size_t)(in.addr >> sizeof(size_t) * i) ^ + (size_t)(in.tgid >> sizeof(size_t) * i); + } + return hash; + } +} + +WaiterState::WaiterState(ThreadContext* _tc, int _bitmask) + : tc(_tc), bitmask(_bitmask) { } + +WaiterState::WaiterState(ThreadContext* _tc) + : tc(_tc), bitmask(0xffffffff) { } + +bool +WaiterState::checkMask(int wakeup_bitmask) const +{ + return bitmask & wakeup_bitmask; +} + +void +FutexMap::suspend(Addr addr, uint64_t tgid, ThreadContext *tc) +{ + FutexKey key(addr, tgid); + auto it = find(key); + + if (it == end()) { + WaiterList waiterList {WaiterState(tc)}; + insert({key, waiterList}); + } else { + it->second.push_back(WaiterState(tc)); + } + + /** Suspend the thread context */ + tc->suspend(); +} + +int +FutexMap::wakeup(Addr addr, uint64_t tgid, int count) +{ + FutexKey key(addr, tgid); + auto it = find(key); + + if (it == end()) + return 0; + + int woken_up = 0; + auto &waiterList = it->second; + + while (!waiterList.empty() && woken_up < count) { + // Threads may be woken up by access to locked + // memory addresses outside of syscalls, so we + // must only count threads that were actually + // woken up by this syscall. + auto& tc = waiterList.front().tc; + if (tc->status() == ThreadContext::Suspended) { + tc->activate(); + woken_up++; + } + waiterList.pop_front(); + } + + if (waiterList.empty()) + erase(it); + + return woken_up; +} + +void +FutexMap::suspend_bitset(Addr addr, uint64_t tgid, ThreadContext *tc, + int bitmask) +{ + FutexKey key(addr, tgid); + auto it = find(key); + + if (it == end()) { + WaiterList waiterList {WaiterState(tc, bitmask)}; + insert({key, waiterList}); + } else { + it->second.push_back(WaiterState(tc, bitmask)); + } + + /** Suspend the thread context */ + tc->suspend(); +} + +int +FutexMap::wakeup_bitset(Addr addr, uint64_t tgid, int bitmask) +{ + FutexKey key(addr, tgid); + auto it = find(key); + + if (it == end()) + return 0; + + int woken_up = 0; + + auto &waiterList = it->second; + auto iter = waiterList.begin(); + + while (iter != waiterList.end()) { + WaiterState& waiter = *iter; + + if (waiter.checkMask(bitmask)) { + waiter.tc->activate(); + iter = waiterList.erase(iter); + woken_up++; + } else { + ++iter; + } + } + + if (waiterList.empty()) + erase(it); + + return woken_up; +} + +int +FutexMap::requeue(Addr addr1, uint64_t tgid, int count, int count2, Addr addr2) +{ + FutexKey key1(addr1, tgid); + auto it1 = find(key1); + + if (it1 == end()) + return 0; + + int woken_up = 0; + auto &waiterList1 = it1->second; + + while (!waiterList1.empty() && woken_up < count) { + waiterList1.front().tc->activate(); + waiterList1.pop_front(); + woken_up++; + } + + WaiterList tmpList; + int requeued = 0; + + while (!waiterList1.empty() && requeued < count2) { + auto w = waiterList1.front(); + waiterList1.pop_front(); + tmpList.push_back(w); + requeued++; + } + + FutexKey key2(addr2, tgid); + auto it2 = find(key2); + + if (it2 == end() && requeued > 0) { + insert({key2, tmpList}); + } else { + it2->second.insert(it2->second.end(), + tmpList.begin(), tmpList.end()); + } + + if (waiterList1.empty()) + erase(it1); + + return woken_up + requeued; +} diff --git a/src/sim/futex_map.hh b/src/sim/futex_map.hh index 2d0deacc8..025d32429 100644 --- a/src/sim/futex_map.hh +++ b/src/sim/futex_map.hh @@ -42,16 +42,9 @@ class FutexKey { uint64_t addr; uint64_t tgid; - FutexKey(uint64_t addr_in, uint64_t tgid_in) - : addr(addr_in), tgid(tgid_in) - { - } + FutexKey(uint64_t addr_in, uint64_t tgid_in); - bool - operator==(const FutexKey &in) const - { - return addr == in.addr && tgid == in.tgid; - } + bool operator==(const FutexKey &in) const; }; namespace std { @@ -63,15 +56,7 @@ namespace std { template <> struct hash { - size_t operator()(const FutexKey& in) const - { - size_t hash = 65521; - for (int i = 0; i < sizeof(uint64_t) / sizeof(size_t); i++) { - hash ^= (size_t)(in.addr >> sizeof(size_t) * i) ^ - (size_t)(in.tgid >> sizeof(size_t) * i); - } - return hash; - } + size_t operator()(const FutexKey& in) const; }; } @@ -87,26 +72,18 @@ class WaiterState { /** * this constructor is used if futex ops with bitset are used */ - WaiterState(ThreadContext* _tc, int _bitmask) - : tc(_tc), bitmask(_bitmask) - { } + WaiterState(ThreadContext* _tc, int _bitmask); /** * if bitset is not defined, just set bitmask to 0xffffffff */ - WaiterState(ThreadContext* _tc) - : tc(_tc), bitmask(0xffffffff) - { } + WaiterState(ThreadContext* _tc); /** * return true if the bit-wise AND of the wakeup_bitmask given by * a waking thread and this thread's internal bitmask is non-zero */ - bool - checkMask(int wakeup_bitmask) const - { - return bitmask & wakeup_bitmask; - } + bool checkMask(int wakeup_bitmask) const; }; typedef std::list WaiterList; @@ -118,112 +95,15 @@ class FutexMap : public std::unordered_map { public: /** Inserts a futex into the map with one waiting TC */ - void - suspend(Addr addr, uint64_t tgid, ThreadContext *tc) - { - FutexKey key(addr, tgid); - auto it = find(key); - - if (it == end()) { - WaiterList waiterList {WaiterState(tc)}; - insert({key, waiterList}); - } else { - it->second.push_back(WaiterState(tc)); - } - - /** Suspend the thread context */ - tc->suspend(); - } + void suspend(Addr addr, uint64_t tgid, ThreadContext *tc); /** Wakes up at most count waiting threads on a futex */ - int - wakeup(Addr addr, uint64_t tgid, int count) - { - FutexKey key(addr, tgid); - auto it = find(key); - - if (it == end()) - return 0; - - int woken_up = 0; - auto &waiterList = it->second; - - while (!waiterList.empty() && woken_up < count) { - // Threads may be woken up by access to locked - // memory addresses outside of syscalls, so we - // must only count threads that were actually - // woken up by this syscall. - auto& tc = waiterList.front().tc; - if (tc->status() == ThreadContext::Suspended) { - tc->activate(); - woken_up++; - } - waiterList.pop_front(); - } + int wakeup(Addr addr, uint64_t tgid, int count); - if (waiterList.empty()) - erase(it); + void suspend_bitset(Addr addr, uint64_t tgid, ThreadContext *tc, + int bitmask); - return woken_up; - } - - /** - * inserts a futex into the map with one waiting TC - * associates the waiter with a given bitmask - */ - void - suspend_bitset(Addr addr, uint64_t tgid, ThreadContext *tc, - int bitmask) - { - FutexKey key(addr, tgid); - auto it = find(key); - - if (it == end()) { - WaiterList waiterList {WaiterState(tc, bitmask)}; - insert({key, waiterList}); - } else { - it->second.push_back(WaiterState(tc, bitmask)); - } - - /** Suspend the thread context */ - tc->suspend(); - } - - /** - * Wakes up all waiters waiting on the addr and associated with the - * given bitset - */ - int - wakeup_bitset(Addr addr, uint64_t tgid, int bitmask) - { - FutexKey key(addr, tgid); - auto it = find(key); - - if (it == end()) - return 0; - - int woken_up = 0; - - auto &waiterList = it->second; - auto iter = waiterList.begin(); - - while (iter != waiterList.end()) { - WaiterState& waiter = *iter; - - if (waiter.checkMask(bitmask)) { - waiter.tc->activate(); - iter = waiterList.erase(iter); - woken_up++; - } else { - ++iter; - } - } - - if (waiterList.empty()) - erase(it); - - return woken_up; - } + int wakeup_bitset(Addr addr, uint64_t tgid, int bitmask); /** * This operation wakes a given number (val) of waiters. If there are @@ -235,49 +115,7 @@ class FutexMap : public std::unordered_map * The return value is the number of waiters that are woken or * requeued. */ - int - requeue(Addr addr1, uint64_t tgid, int count, int count2, Addr addr2) - { - FutexKey key1(addr1, tgid); - auto it1 = find(key1); - - if (it1 == end()) - return 0; - - int woken_up = 0; - auto &waiterList1 = it1->second; - - while (!waiterList1.empty() && woken_up < count) { - waiterList1.front().tc->activate(); - waiterList1.pop_front(); - woken_up++; - } - - WaiterList tmpList; - int requeued = 0; - - while (!waiterList1.empty() && requeued < count2) { - auto w = waiterList1.front(); - waiterList1.pop_front(); - tmpList.push_back(w); - requeued++; - } - - FutexKey key2(addr2, tgid); - auto it2 = find(key2); - - if (it2 == end() && requeued > 0) { - insert({key2, tmpList}); - } else { - it2->second.insert(it2->second.end(), - tmpList.begin(), tmpList.end()); - } - - if (waiterList1.empty()) - erase(it1); - - return woken_up + requeued; - } + int requeue(Addr addr1, uint64_t tgid, int count, int count2, Addr addr2); }; #endif // __FUTEX_MAP_HH__ -- 2.30.2