--- /dev/null
+/*
+ * 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 <debug/Thread.hh>
+#include <sim/futex_map.hh>
+
+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<FutexKey>::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;
+}
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 {
template <>
struct hash<FutexKey>
{
- 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;
};
}
/**
* 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<WaiterState> WaiterList;
{
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
* 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__