diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/file_util.cpp | 43 | ||||
| -rw-r--r-- | src/common/file_util.h | 26 | ||||
| -rw-r--r-- | src/common/thread.h | 46 | ||||
| -rw-r--r-- | src/common/x64/emitter.cpp | 28 | ||||
| -rw-r--r-- | src/common/x64/emitter.h | 2 |
5 files changed, 74 insertions, 71 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 687b7ae5a..6e2867658 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -833,13 +833,12 @@ size_t WriteStringToFile(bool text_file, const std::string &str, const char *fil | |||
| 833 | 833 | ||
| 834 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str) | 834 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str) |
| 835 | { | 835 | { |
| 836 | FileUtil::IOFile file(filename, text_file ? "r" : "rb"); | 836 | IOFile file(filename, text_file ? "r" : "rb"); |
| 837 | auto const f = file.GetHandle(); | ||
| 838 | 837 | ||
| 839 | if (!f) | 838 | if (!file) |
| 840 | return false; | 839 | return false; |
| 841 | 840 | ||
| 842 | str.resize(static_cast<u32>(GetSize(f))); | 841 | str.resize(static_cast<u32>(file.GetSize())); |
| 843 | return file.ReadArray(&str[0], str.size()); | 842 | return file.ReadArray(&str[0], str.size()); |
| 844 | } | 843 | } |
| 845 | 844 | ||
| @@ -886,15 +885,10 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 886 | } | 885 | } |
| 887 | 886 | ||
| 888 | IOFile::IOFile() | 887 | IOFile::IOFile() |
| 889 | : m_file(nullptr), m_good(true) | 888 | { |
| 890 | {} | 889 | } |
| 891 | |||
| 892 | IOFile::IOFile(std::FILE* file) | ||
| 893 | : m_file(file), m_good(true) | ||
| 894 | {} | ||
| 895 | 890 | ||
| 896 | IOFile::IOFile(const std::string& filename, const char openmode[]) | 891 | IOFile::IOFile(const std::string& filename, const char openmode[]) |
| 897 | : m_file(nullptr), m_good(true) | ||
| 898 | { | 892 | { |
| 899 | Open(filename, openmode); | 893 | Open(filename, openmode); |
| 900 | } | 894 | } |
| @@ -905,7 +899,6 @@ IOFile::~IOFile() | |||
| 905 | } | 899 | } |
| 906 | 900 | ||
| 907 | IOFile::IOFile(IOFile&& other) | 901 | IOFile::IOFile(IOFile&& other) |
| 908 | : m_file(nullptr), m_good(true) | ||
| 909 | { | 902 | { |
| 910 | Swap(other); | 903 | Swap(other); |
| 911 | } | 904 | } |
| @@ -944,26 +937,12 @@ bool IOFile::Close() | |||
| 944 | return m_good; | 937 | return m_good; |
| 945 | } | 938 | } |
| 946 | 939 | ||
| 947 | std::FILE* IOFile::ReleaseHandle() | 940 | u64 IOFile::GetSize() const |
| 948 | { | ||
| 949 | std::FILE* const ret = m_file; | ||
| 950 | m_file = nullptr; | ||
| 951 | return ret; | ||
| 952 | } | ||
| 953 | |||
| 954 | void IOFile::SetHandle(std::FILE* file) | ||
| 955 | { | ||
| 956 | Close(); | ||
| 957 | Clear(); | ||
| 958 | m_file = file; | ||
| 959 | } | ||
| 960 | |||
| 961 | u64 IOFile::GetSize() | ||
| 962 | { | 941 | { |
| 963 | if (IsOpen()) | 942 | if (IsOpen()) |
| 964 | return FileUtil::GetSize(m_file); | 943 | return FileUtil::GetSize(m_file); |
| 965 | else | 944 | |
| 966 | return 0; | 945 | return 0; |
| 967 | } | 946 | } |
| 968 | 947 | ||
| 969 | bool IOFile::Seek(s64 off, int origin) | 948 | bool IOFile::Seek(s64 off, int origin) |
| @@ -974,12 +953,12 @@ bool IOFile::Seek(s64 off, int origin) | |||
| 974 | return m_good; | 953 | return m_good; |
| 975 | } | 954 | } |
| 976 | 955 | ||
| 977 | u64 IOFile::Tell() | 956 | u64 IOFile::Tell() const |
| 978 | { | 957 | { |
| 979 | if (IsOpen()) | 958 | if (IsOpen()) |
| 980 | return ftello(m_file); | 959 | return ftello(m_file); |
| 981 | else | 960 | |
| 982 | return -1; | 961 | return -1; |
| 983 | } | 962 | } |
| 984 | 963 | ||
| 985 | bool IOFile::Flush() | 964 | bool IOFile::Flush() |
diff --git a/src/common/file_util.h b/src/common/file_util.h index 880b8a1e3..b54a9fb72 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -176,7 +176,6 @@ class IOFile : public NonCopyable | |||
| 176 | { | 176 | { |
| 177 | public: | 177 | public: |
| 178 | IOFile(); | 178 | IOFile(); |
| 179 | explicit IOFile(std::FILE* file); | ||
| 180 | IOFile(const std::string& filename, const char openmode[]); | 179 | IOFile(const std::string& filename, const char openmode[]); |
| 181 | 180 | ||
| 182 | ~IOFile(); | 181 | ~IOFile(); |
| @@ -192,6 +191,9 @@ public: | |||
| 192 | template <typename T> | 191 | template <typename T> |
| 193 | size_t ReadArray(T* data, size_t length) | 192 | size_t ReadArray(T* data, size_t length) |
| 194 | { | 193 | { |
| 194 | static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); | ||
| 195 | static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); | ||
| 196 | |||
| 195 | if (!IsOpen()) { | 197 | if (!IsOpen()) { |
| 196 | m_good = false; | 198 | m_good = false; |
| 197 | return -1; | 199 | return -1; |
| @@ -207,9 +209,8 @@ public: | |||
| 207 | template <typename T> | 209 | template <typename T> |
| 208 | size_t WriteArray(const T* data, size_t length) | 210 | size_t WriteArray(const T* data, size_t length) |
| 209 | { | 211 | { |
| 210 | static_assert(std::is_standard_layout<T>::value, "Given array does not consist of standard layout objects"); | 212 | static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); |
| 211 | // TODO: gcc 4.8 does not support is_trivially_copyable, but we really should check for it here. | 213 | static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); |
| 212 | //static_assert(std::is_trivially_copyable<T>::value, "Given array does not consist of trivially copyable objects"); | ||
| 213 | 214 | ||
| 214 | if (!IsOpen()) { | 215 | if (!IsOpen()) { |
| 215 | m_good = false; | 216 | m_good = false; |
| @@ -243,25 +244,20 @@ public: | |||
| 243 | 244 | ||
| 244 | // m_good is set to false when a read, write or other function fails | 245 | // m_good is set to false when a read, write or other function fails |
| 245 | bool IsGood() const { return m_good; } | 246 | bool IsGood() const { return m_good; } |
| 246 | operator void*() { return m_good ? m_file : nullptr; } | 247 | explicit operator bool() const { return IsGood(); } |
| 247 | |||
| 248 | std::FILE* ReleaseHandle(); | ||
| 249 | |||
| 250 | std::FILE* GetHandle() { return m_file; } | ||
| 251 | |||
| 252 | void SetHandle(std::FILE* file); | ||
| 253 | 248 | ||
| 254 | bool Seek(s64 off, int origin); | 249 | bool Seek(s64 off, int origin); |
| 255 | u64 Tell(); | 250 | u64 Tell() const; |
| 256 | u64 GetSize(); | 251 | u64 GetSize() const; |
| 257 | bool Resize(u64 size); | 252 | bool Resize(u64 size); |
| 258 | bool Flush(); | 253 | bool Flush(); |
| 259 | 254 | ||
| 260 | // clear error state | 255 | // clear error state |
| 261 | void Clear() { m_good = true; std::clearerr(m_file); } | 256 | void Clear() { m_good = true; std::clearerr(m_file); } |
| 262 | 257 | ||
| 263 | std::FILE* m_file; | 258 | private: |
| 264 | bool m_good; | 259 | std::FILE* m_file = nullptr; |
| 260 | bool m_good = true; | ||
| 265 | }; | 261 | }; |
| 266 | 262 | ||
| 267 | } // namespace | 263 | } // namespace |
diff --git a/src/common/thread.h b/src/common/thread.h index 8255ee6d3..bbfa8befa 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -30,8 +30,7 @@ | |||
| 30 | # endif | 30 | # endif |
| 31 | #endif | 31 | #endif |
| 32 | 32 | ||
| 33 | namespace Common | 33 | namespace Common { |
| 34 | { | ||
| 35 | 34 | ||
| 36 | int CurrentThreadId(); | 35 | int CurrentThreadId(); |
| 37 | 36 | ||
| @@ -43,55 +42,55 @@ public: | |||
| 43 | Event() : is_set(false) {} | 42 | Event() : is_set(false) {} |
| 44 | 43 | ||
| 45 | void Set() { | 44 | void Set() { |
| 46 | std::lock_guard<std::mutex> lk(m_mutex); | 45 | std::lock_guard<std::mutex> lk(mutex); |
| 47 | if (!is_set) { | 46 | if (!is_set) { |
| 48 | is_set = true; | 47 | is_set = true; |
| 49 | m_condvar.notify_one(); | 48 | condvar.notify_one(); |
| 50 | } | 49 | } |
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | void Wait() { | 52 | void Wait() { |
| 54 | std::unique_lock<std::mutex> lk(m_mutex); | 53 | std::unique_lock<std::mutex> lk(mutex); |
| 55 | m_condvar.wait(lk, [&]{ return is_set; }); | 54 | condvar.wait(lk, [&]{ return is_set; }); |
| 56 | is_set = false; | 55 | is_set = false; |
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | void Reset() { | 58 | void Reset() { |
| 60 | std::unique_lock<std::mutex> lk(m_mutex); | 59 | std::unique_lock<std::mutex> lk(mutex); |
| 61 | // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration | 60 | // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration |
| 62 | is_set = false; | 61 | is_set = false; |
| 63 | } | 62 | } |
| 64 | 63 | ||
| 65 | private: | 64 | private: |
| 66 | bool is_set; | 65 | bool is_set; |
| 67 | std::condition_variable m_condvar; | 66 | std::condition_variable condvar; |
| 68 | std::mutex m_mutex; | 67 | std::mutex mutex; |
| 69 | }; | 68 | }; |
| 70 | 69 | ||
| 71 | class Barrier { | 70 | class Barrier { |
| 72 | public: | 71 | public: |
| 73 | Barrier(size_t count) : m_count(count), m_waiting(0) {} | 72 | explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {} |
| 74 | 73 | ||
| 75 | /// Blocks until all "count" threads have called Sync() | 74 | /// Blocks until all "count" threads have called Sync() |
| 76 | void Sync() { | 75 | void Sync() { |
| 77 | std::unique_lock<std::mutex> lk(m_mutex); | 76 | std::unique_lock<std::mutex> lk(mutex); |
| 77 | const size_t current_generation = generation; | ||
| 78 | 78 | ||
| 79 | // TODO: broken when next round of Sync()s | 79 | if (++waiting == count) { |
| 80 | // is entered before all waiting threads return from the notify_all | 80 | generation++; |
| 81 | 81 | waiting = 0; | |
| 82 | if (++m_waiting == m_count) { | 82 | condvar.notify_all(); |
| 83 | m_waiting = 0; | ||
| 84 | m_condvar.notify_all(); | ||
| 85 | } else { | 83 | } else { |
| 86 | m_condvar.wait(lk, [&]{ return m_waiting == 0; }); | 84 | condvar.wait(lk, [this, current_generation]{ return current_generation != generation; }); |
| 87 | } | 85 | } |
| 88 | } | 86 | } |
| 89 | 87 | ||
| 90 | private: | 88 | private: |
| 91 | std::condition_variable m_condvar; | 89 | std::condition_variable condvar; |
| 92 | std::mutex m_mutex; | 90 | std::mutex mutex; |
| 93 | const size_t m_count; | 91 | const size_t count; |
| 94 | size_t m_waiting; | 92 | size_t waiting; |
| 93 | size_t generation; // Incremented once each time the barrier is used | ||
| 95 | }; | 94 | }; |
| 96 | 95 | ||
| 97 | void SleepCurrentThread(int ms); | 96 | void SleepCurrentThread(int ms); |
| @@ -100,8 +99,7 @@ void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | |||
| 100 | // Use this function during a spin-wait to make the current thread | 99 | // Use this function during a spin-wait to make the current thread |
| 101 | // relax while another thread is working. This may be more efficient | 100 | // relax while another thread is working. This may be more efficient |
| 102 | // than using events because event functions use kernel calls. | 101 | // than using events because event functions use kernel calls. |
| 103 | inline void YieldCPU() | 102 | inline void YieldCPU() { |
| 104 | { | ||
| 105 | std::this_thread::yield(); | 103 | std::this_thread::yield(); |
| 106 | } | 104 | } |
| 107 | 105 | ||
diff --git a/src/common/x64/emitter.cpp b/src/common/x64/emitter.cpp index 1dcf2416c..5662f7f86 100644 --- a/src/common/x64/emitter.cpp +++ b/src/common/x64/emitter.cpp | |||
| @@ -455,6 +455,18 @@ void XEmitter::CALL(const void* fnptr) | |||
| 455 | Write32(u32(distance)); | 455 | Write32(u32(distance)); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | FixupBranch XEmitter::CALL() | ||
| 459 | { | ||
| 460 | FixupBranch branch; | ||
| 461 | branch.type = 1; | ||
| 462 | branch.ptr = code + 5; | ||
| 463 | |||
| 464 | Write8(0xE8); | ||
| 465 | Write32(0); | ||
| 466 | |||
| 467 | return branch; | ||
| 468 | } | ||
| 469 | |||
| 458 | FixupBranch XEmitter::J(bool force5bytes) | 470 | FixupBranch XEmitter::J(bool force5bytes) |
| 459 | { | 471 | { |
| 460 | FixupBranch branch; | 472 | FixupBranch branch; |
| @@ -531,6 +543,22 @@ void XEmitter::SetJumpTarget(const FixupBranch& branch) | |||
| 531 | } | 543 | } |
| 532 | } | 544 | } |
| 533 | 545 | ||
| 546 | void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) | ||
| 547 | { | ||
| 548 | if (branch.type == 0) | ||
| 549 | { | ||
| 550 | s64 distance = (s64)(target - branch.ptr); | ||
| 551 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); | ||
| 552 | branch.ptr[-1] = (u8)(s8)distance; | ||
| 553 | } | ||
| 554 | else if (branch.type == 1) | ||
| 555 | { | ||
| 556 | s64 distance = (s64)(target - branch.ptr); | ||
| 557 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); | ||
| 558 | ((s32*)branch.ptr)[-1] = (s32)distance; | ||
| 559 | } | ||
| 560 | } | ||
| 561 | |||
| 534 | //Single byte opcodes | 562 | //Single byte opcodes |
| 535 | //There is no PUSHAD/POPAD in 64-bit mode. | 563 | //There is no PUSHAD/POPAD in 64-bit mode. |
| 536 | void XEmitter::INT3() {Write8(0xCC);} | 564 | void XEmitter::INT3() {Write8(0xCC);} |
diff --git a/src/common/x64/emitter.h b/src/common/x64/emitter.h index 7c6548fb5..a33724146 100644 --- a/src/common/x64/emitter.h +++ b/src/common/x64/emitter.h | |||
| @@ -425,12 +425,14 @@ public: | |||
| 425 | #undef CALL | 425 | #undef CALL |
| 426 | #endif | 426 | #endif |
| 427 | void CALL(const void* fnptr); | 427 | void CALL(const void* fnptr); |
| 428 | FixupBranch CALL(); | ||
| 428 | void CALLptr(OpArg arg); | 429 | void CALLptr(OpArg arg); |
| 429 | 430 | ||
| 430 | FixupBranch J_CC(CCFlags conditionCode, bool force5bytes = false); | 431 | FixupBranch J_CC(CCFlags conditionCode, bool force5bytes = false); |
| 431 | void J_CC(CCFlags conditionCode, const u8* addr, bool force5Bytes = false); | 432 | void J_CC(CCFlags conditionCode, const u8* addr, bool force5Bytes = false); |
| 432 | 433 | ||
| 433 | void SetJumpTarget(const FixupBranch& branch); | 434 | void SetJumpTarget(const FixupBranch& branch); |
| 435 | void SetJumpTarget(const FixupBranch& branch, const u8* target); | ||
| 434 | 436 | ||
| 435 | void SETcc(CCFlags flag, OpArg dest); | 437 | void SETcc(CCFlags flag, OpArg dest); |
| 436 | // Note: CMOV brings small if any benefit on current cpus. | 438 | // Note: CMOV brings small if any benefit on current cpus. |