1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00
rpcs3/Utilities/sync.h
Jan Beich cd6bf37d06 Utilities: explicitly add more includes found by GCC
Utilities/Log.cpp: In member function 'void logs::file_writer::log(logs::level, const char*, std::size_t)':
Utilities/Log.cpp:559:9: error: 'memcpy' is not a member of 'std'
    std::memcpy(pos, text, frag);
         ^~~~~~
Utilities/Log.cpp:559:9: note: suggested alternative: 'empty'
    std::memcpy(pos, text, frag);
         ^~~~~~
         empty
Utilities/Log.cpp:560:9: error: 'memcpy' is not a member of 'std'
    std::memcpy(m_fptr, text + frag, size - frag);
         ^~~~~~
Utilities/Log.cpp:560:9: note: suggested alternative: 'empty'
    std::memcpy(m_fptr, text + frag, size - frag);
         ^~~~~~
         empty
Utilities/Log.cpp:564:9: error: 'memcpy' is not a member of 'std'
    std::memcpy(pos, text, size);
         ^~~~~~
Utilities/Log.cpp:564:9: note: suggested alternative: 'empty'
    std::memcpy(pos, text, size);
         ^~~~~~
         empty
Utilities/sync.h: In member function 'int futex(int*, int, int, const timespec*, int*, int)::futex_map::operator()(int*, int, int, const timespec*, int*, uint)':
Utilities/sync.h:110:20: error: 'find' is not a member of 'std'
     map.erase(std::find(map.find(uaddr), map.end(), ref));
                    ^~~~
Utilities/sync.h:110:20: note: suggested alternative: 'rend'
     map.erase(std::find(map.find(uaddr), map.end(), ref));
                    ^~~~
                    rend
2018-08-31 03:19:17 +04:00

149 lines
3.0 KiB
C++

#pragma once
/* For internal use. Don't include. */
#include "types.h"
#include "Atomic.h"
#include "dynamic_library.h"
#ifdef _WIN32
#include <Windows.h>
#include <time.h>
#elif __linux__
#include <errno.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/time.h>
#include <unistd.h>
#else
#endif
#include <algorithm>
#include <ctime>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <unordered_map>
#ifdef _WIN32
DYNAMIC_IMPORT("ntdll.dll", NtWaitForKeyedEvent, NTSTATUS(HANDLE Handle, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout));
DYNAMIC_IMPORT("ntdll.dll", NtReleaseKeyedEvent, NTSTATUS(HANDLE Handle, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout));
DYNAMIC_IMPORT("ntdll.dll", NtDelayExecution, NTSTATUS(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval));
#endif
#ifndef __linux__
enum
{
FUTEX_PRIVATE_FLAG = 0,
FUTEX_WAIT = 0,
FUTEX_WAIT_PRIVATE = FUTEX_WAIT,
FUTEX_WAKE = 1,
FUTEX_WAKE_PRIVATE = FUTEX_WAKE,
FUTEX_BITSET = 2,
FUTEX_WAIT_BITSET = FUTEX_WAIT | FUTEX_BITSET,
FUTEX_WAIT_BITSET_PRIVATE = FUTEX_WAIT_BITSET,
FUTEX_WAKE_BITSET = FUTEX_WAKE | FUTEX_BITSET,
FUTEX_WAKE_BITSET_PRIVATE = FUTEX_WAKE_BITSET,
};
#endif
inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int* uaddr2, int val3)
{
#ifdef __linux__
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3);
#else
static struct futex_map
{
struct waiter
{
int val;
uint mask;
std::condition_variable cv;
};
std::mutex mutex;
std::unordered_multimap<int*, waiter*, pointer_hash<int>> map;
int operator()(int* uaddr, int futex_op, int val, const timespec* timeout, int*, uint val3)
{
std::unique_lock<std::mutex> lock(mutex);
switch (futex_op)
{
case FUTEX_WAIT:
{
val3 = -1;
// Fallthrough
}
case FUTEX_WAIT_BITSET:
{
if (*(volatile int*)uaddr != val)
{
errno = EAGAIN;
return -1;
}
waiter rec;
rec.val = val;
rec.mask = val3;
const auto& ref = *map.emplace(uaddr, &rec);
int res = 0;
if (!timeout)
{
rec.cv.wait(lock, [&] { return !rec.mask; });
}
else if (futex_op == FUTEX_WAIT)
{
const auto nsec = std::chrono::nanoseconds(timeout->tv_nsec + timeout->tv_sec * 1000000000ull);
if (!rec.cv.wait_for(lock, nsec, [&] { return !rec.mask; }))
{
res = -1;
errno = ETIMEDOUT;
}
}
else
{
// TODO
}
map.erase(std::find(map.find(uaddr), map.end(), ref));
return res;
}
case FUTEX_WAKE:
{
val3 = -1;
// Fallthrough
}
case FUTEX_WAKE_BITSET:
{
int res = 0;
for (auto range = map.equal_range(uaddr); val && range.first != range.second; range.first++)
{
auto& entry = *range.first->second;
if (entry.mask & val3)
{
entry.cv.notify_one();
entry.mask = 0;
res++;
val--;
}
}
return res;
}
}
errno = EINVAL;
return -1;
}
} g_futex;
return g_futex(uaddr, futex_op, val, timeout, uaddr2, val3);
#endif
}