diff options
| author | 2020-02-05 15:48:20 -0400 | |
|---|---|---|
| committer | 2020-06-18 16:29:15 -0400 | |
| commit | be320a9e10fda32a984b12cdfe3aaf09cc67b39a (patch) | |
| tree | f2bb28be6adc2a416b59393bb8f438636e9c79c1 /src/tests/common/fibers.cpp | |
| parent | Tests: Add tests for fibers and refactor/fix Fiber class (diff) | |
| download | yuzu-be320a9e10fda32a984b12cdfe3aaf09cc67b39a.tar.gz yuzu-be320a9e10fda32a984b12cdfe3aaf09cc67b39a.tar.xz yuzu-be320a9e10fda32a984b12cdfe3aaf09cc67b39a.zip | |
Common: Polish Fiber class, add comments, asserts and more tests.
Diffstat (limited to 'src/tests/common/fibers.cpp')
| -rw-r--r-- | src/tests/common/fibers.cpp | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp index ff840afa6..358393a19 100644 --- a/src/tests/common/fibers.cpp +++ b/src/tests/common/fibers.cpp | |||
| @@ -64,7 +64,9 @@ static void ThreadStart1(u32 id, TestControl1& test_control) { | |||
| 64 | test_control.ExecuteThread(id); | 64 | test_control.ExecuteThread(id); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | 67 | /** This test checks for fiber setup configuration and validates that fibers are | |
| 68 | * doing all the work required. | ||
| 69 | */ | ||
| 68 | TEST_CASE("Fibers::Setup", "[common]") { | 70 | TEST_CASE("Fibers::Setup", "[common]") { |
| 69 | constexpr u32 num_threads = 7; | 71 | constexpr u32 num_threads = 7; |
| 70 | TestControl1 test_control{}; | 72 | TestControl1 test_control{}; |
| @@ -188,6 +190,10 @@ static void ThreadStart2_2(u32 id, TestControl2& test_control) { | |||
| 188 | test_control.Exit(); | 190 | test_control.Exit(); |
| 189 | } | 191 | } |
| 190 | 192 | ||
| 193 | /** This test checks for fiber thread exchange configuration and validates that fibers are | ||
| 194 | * that a fiber has been succesfully transfered from one thread to another and that the TLS | ||
| 195 | * region of the thread is kept while changing fibers. | ||
| 196 | */ | ||
| 191 | TEST_CASE("Fibers::InterExchange", "[common]") { | 197 | TEST_CASE("Fibers::InterExchange", "[common]") { |
| 192 | TestControl2 test_control{}; | 198 | TestControl2 test_control{}; |
| 193 | test_control.thread_fibers.resize(2, nullptr); | 199 | test_control.thread_fibers.resize(2, nullptr); |
| @@ -210,5 +216,92 @@ TEST_CASE("Fibers::InterExchange", "[common]") { | |||
| 210 | REQUIRE(test_control.value1 == cal_value); | 216 | REQUIRE(test_control.value1 == cal_value); |
| 211 | } | 217 | } |
| 212 | 218 | ||
| 219 | class TestControl3 { | ||
| 220 | public: | ||
| 221 | TestControl3() = default; | ||
| 222 | |||
| 223 | void DoWork1() { | ||
| 224 | value1 += 1; | ||
| 225 | Fiber::YieldTo(fiber1, fiber2); | ||
| 226 | std::thread::id this_id = std::this_thread::get_id(); | ||
| 227 | u32 id = ids[this_id]; | ||
| 228 | value3 += 1; | ||
| 229 | Fiber::YieldTo(fiber1, thread_fibers[id]); | ||
| 230 | } | ||
| 231 | |||
| 232 | void DoWork2() { | ||
| 233 | value2 += 1; | ||
| 234 | std::thread::id this_id = std::this_thread::get_id(); | ||
| 235 | u32 id = ids[this_id]; | ||
| 236 | Fiber::YieldTo(fiber2, thread_fibers[id]); | ||
| 237 | } | ||
| 238 | |||
| 239 | void ExecuteThread(u32 id); | ||
| 240 | |||
| 241 | void CallFiber1() { | ||
| 242 | std::thread::id this_id = std::this_thread::get_id(); | ||
| 243 | u32 id = ids[this_id]; | ||
| 244 | Fiber::YieldTo(thread_fibers[id], fiber1); | ||
| 245 | } | ||
| 246 | |||
| 247 | void Exit(); | ||
| 248 | |||
| 249 | u32 value1{}; | ||
| 250 | u32 value2{}; | ||
| 251 | u32 value3{}; | ||
| 252 | std::unordered_map<std::thread::id, u32> ids; | ||
| 253 | std::vector<std::shared_ptr<Common::Fiber>> thread_fibers; | ||
| 254 | std::shared_ptr<Common::Fiber> fiber1; | ||
| 255 | std::shared_ptr<Common::Fiber> fiber2; | ||
| 256 | }; | ||
| 257 | |||
| 258 | static void WorkControl3_1(void* control) { | ||
| 259 | TestControl3* test_control = static_cast<TestControl3*>(control); | ||
| 260 | test_control->DoWork1(); | ||
| 261 | } | ||
| 262 | |||
| 263 | static void WorkControl3_2(void* control) { | ||
| 264 | TestControl3* test_control = static_cast<TestControl3*>(control); | ||
| 265 | test_control->DoWork2(); | ||
| 266 | } | ||
| 267 | |||
| 268 | void TestControl3::ExecuteThread(u32 id) { | ||
| 269 | std::thread::id this_id = std::this_thread::get_id(); | ||
| 270 | ids[this_id] = id; | ||
| 271 | auto thread_fiber = Fiber::ThreadToFiber(); | ||
| 272 | thread_fibers[id] = thread_fiber; | ||
| 273 | } | ||
| 274 | |||
| 275 | void TestControl3::Exit() { | ||
| 276 | std::thread::id this_id = std::this_thread::get_id(); | ||
| 277 | u32 id = ids[this_id]; | ||
| 278 | thread_fibers[id]->Exit(); | ||
| 279 | } | ||
| 280 | |||
| 281 | static void ThreadStart3(u32 id, TestControl3& test_control) { | ||
| 282 | test_control.ExecuteThread(id); | ||
| 283 | test_control.CallFiber1(); | ||
| 284 | test_control.Exit(); | ||
| 285 | } | ||
| 286 | |||
| 287 | /** This test checks for one two threads racing for starting the same fiber. | ||
| 288 | * It checks execution occured in an ordered manner and by no time there were | ||
| 289 | * two contexts at the same time. | ||
| 290 | */ | ||
| 291 | TEST_CASE("Fibers::StartRace", "[common]") { | ||
| 292 | TestControl3 test_control{}; | ||
| 293 | test_control.thread_fibers.resize(2, nullptr); | ||
| 294 | test_control.fiber1 = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_1}, &test_control); | ||
| 295 | test_control.fiber2 = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_2}, &test_control); | ||
| 296 | std::thread thread1(ThreadStart3, 0, std::ref(test_control)); | ||
| 297 | std::thread thread2(ThreadStart3, 1, std::ref(test_control)); | ||
| 298 | thread1.join(); | ||
| 299 | thread2.join(); | ||
| 300 | REQUIRE(test_control.value1 == 1); | ||
| 301 | REQUIRE(test_control.value2 == 1); | ||
| 302 | REQUIRE(test_control.value3 == 1); | ||
| 303 | } | ||
| 304 | |||
| 305 | |||
| 213 | 306 | ||
| 214 | } // namespace Common | 307 | } // namespace Common |