summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/file_util.cpp43
-rw-r--r--src/common/file_util.h26
-rw-r--r--src/common/thread.h46
-rw-r--r--src/common/x64/emitter.cpp28
-rw-r--r--src/common/x64/emitter.h2
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
834size_t ReadFileToString(bool text_file, const char *filename, std::string &str) 834size_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
888IOFile::IOFile() 887IOFile::IOFile()
889 : m_file(nullptr), m_good(true) 888{
890{} 889}
891
892IOFile::IOFile(std::FILE* file)
893 : m_file(file), m_good(true)
894{}
895 890
896IOFile::IOFile(const std::string& filename, const char openmode[]) 891IOFile::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
907IOFile::IOFile(IOFile&& other) 901IOFile::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
947std::FILE* IOFile::ReleaseHandle() 940u64 IOFile::GetSize() const
948{
949 std::FILE* const ret = m_file;
950 m_file = nullptr;
951 return ret;
952}
953
954void IOFile::SetHandle(std::FILE* file)
955{
956 Close();
957 Clear();
958 m_file = file;
959}
960
961u64 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
969bool IOFile::Seek(s64 off, int origin) 948bool 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
977u64 IOFile::Tell() 956u64 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
985bool IOFile::Flush() 964bool 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{
177public: 177public:
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; 258private:
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
33namespace Common 33namespace Common {
34{
35 34
36int CurrentThreadId(); 35int 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
65private: 64private:
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
71class Barrier { 70class Barrier {
72public: 71public:
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
90private: 88private:
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
97void SleepCurrentThread(int ms); 96void 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.
103inline void YieldCPU() 102inline 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
458FixupBranch 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
458FixupBranch XEmitter::J(bool force5bytes) 470FixupBranch 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
546void 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.
536void XEmitter::INT3() {Write8(0xCC);} 564void 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.