mirror of https://github.com/RPCS3/rpcs3
Util/sync.h: Fix iterator invalidation in futex emulation
This commit is contained in:
parent
103d580d9a
commit
812d84e7f4
|
|
@ -86,11 +86,21 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
|
||||||
std::condition_variable cv;
|
std::condition_variable cv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bucket_t
|
||||||
|
{
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::unordered_multimap<volatile void*, waiter*> map;
|
std::unordered_multimap<volatile void*, waiter*> map;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Not a power of 2 on purpose (for alignment optimiations)
|
||||||
|
bucket_t bucks[63];
|
||||||
|
|
||||||
int operator()(volatile void* uaddr, int futex_op, uint val, const timespec* timeout, uint mask)
|
int operator()(volatile void* uaddr, int futex_op, uint val, const timespec* timeout, uint mask)
|
||||||
{
|
{
|
||||||
|
auto& bucket = bucks[(reinterpret_cast<u64>(uaddr) / 8) % std::size(bucks)];
|
||||||
|
auto& mutex = bucket.mutex;
|
||||||
|
auto& map = bucket.map;
|
||||||
|
|
||||||
std::unique_lock lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
switch (futex_op)
|
switch (futex_op)
|
||||||
|
|
@ -111,7 +121,9 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
|
||||||
waiter rec;
|
waiter rec;
|
||||||
rec.val = val;
|
rec.val = val;
|
||||||
rec.mask = mask;
|
rec.mask = mask;
|
||||||
const auto itr = map.emplace(uaddr, &rec);
|
|
||||||
|
// Announce the waiter
|
||||||
|
map.emplace(uaddr, &rec);
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
|
|
@ -127,6 +139,16 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
|
||||||
{
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
errno = ETIMEDOUT;
|
errno = ETIMEDOUT;
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
for (auto range = map.equal_range(uaddr); range.first != range.second; range.first++)
|
||||||
|
{
|
||||||
|
if (range.first->second == &rec)
|
||||||
|
{
|
||||||
|
map.erase(range.first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -134,7 +156,6 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
|
||||||
// TODO: absolute timeout
|
// TODO: absolute timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
map.erase(itr);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,13 +174,29 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
|
||||||
|
|
||||||
if (entry.mask & mask)
|
if (entry.mask & mask)
|
||||||
{
|
{
|
||||||
entry.cv.notify_one();
|
|
||||||
entry.mask = 0;
|
entry.mask = 0;
|
||||||
|
entry.cv.notify_one();
|
||||||
res++;
|
res++;
|
||||||
val--;
|
val--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
// Cleanup
|
||||||
|
for (auto range = map.equal_range(uaddr); range.first != range.second;)
|
||||||
|
{
|
||||||
|
if (range.first->second->mask == 0)
|
||||||
|
{
|
||||||
|
map.erase(range.first);
|
||||||
|
range = map.equal_range(uaddr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
range.first++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue