|
|
@ -6,18 +6,40 @@
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <functional>
|
|
|
|
#include <functional>
|
|
|
|
#include <memory>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <thread>
|
|
|
|
#include <thread>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
|
#include <catch2/catch.hpp>
|
|
|
|
#include <catch2/catch.hpp>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/fiber.h"
|
|
|
|
#include "common/fiber.h"
|
|
|
|
#include "common/spin_lock.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Common {
|
|
|
|
namespace Common {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ThreadIds {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
void Register(u32 id) {
|
|
|
|
|
|
|
|
const auto thread_id = std::this_thread::get_id();
|
|
|
|
|
|
|
|
std::scoped_lock lock{mutex};
|
|
|
|
|
|
|
|
if (ids.contains(thread_id)) {
|
|
|
|
|
|
|
|
throw std::logic_error{"Registering the same thread twice"};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ids.emplace(thread_id, id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] u32 Get() const {
|
|
|
|
|
|
|
|
std::scoped_lock lock{mutex};
|
|
|
|
|
|
|
|
return ids.at(std::this_thread::get_id());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
mutable std::mutex mutex;
|
|
|
|
|
|
|
|
std::unordered_map<std::thread::id, u32> ids;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class TestControl1 {
|
|
|
|
class TestControl1 {
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
TestControl1() = default;
|
|
|
|
TestControl1() = default;
|
|
|
@ -26,7 +48,7 @@ public:
|
|
|
|
|
|
|
|
|
|
|
|
void ExecuteThread(u32 id);
|
|
|
|
void ExecuteThread(u32 id);
|
|
|
|
|
|
|
|
|
|
|
|
std::unordered_map<std::thread::id, u32> ids;
|
|
|
|
ThreadIds thread_ids;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> work_fibers;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> work_fibers;
|
|
|
|
std::vector<u32> items;
|
|
|
|
std::vector<u32> items;
|
|
|
@ -39,8 +61,7 @@ static void WorkControl1(void* control) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestControl1::DoWork() {
|
|
|
|
void TestControl1::DoWork() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
u32 value = items[id];
|
|
|
|
u32 value = items[id];
|
|
|
|
for (u32 i = 0; i < id; i++) {
|
|
|
|
for (u32 i = 0; i < id; i++) {
|
|
|
|
value++;
|
|
|
|
value++;
|
|
|
@ -50,8 +71,7 @@ void TestControl1::DoWork() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestControl1::ExecuteThread(u32 id) {
|
|
|
|
void TestControl1::ExecuteThread(u32 id) {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
thread_ids.Register(id);
|
|
|
|
ids[this_id] = id;
|
|
|
|
|
|
|
|
auto thread_fiber = Fiber::ThreadToFiber();
|
|
|
|
auto thread_fiber = Fiber::ThreadToFiber();
|
|
|
|
thread_fibers[id] = thread_fiber;
|
|
|
|
thread_fibers[id] = thread_fiber;
|
|
|
|
work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this);
|
|
|
|
work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this);
|
|
|
@ -98,8 +118,7 @@ public:
|
|
|
|
value1 += i;
|
|
|
|
value1 += i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Fiber::YieldTo(fiber1, fiber3);
|
|
|
|
Fiber::YieldTo(fiber1, fiber3);
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
assert1 = id == 1;
|
|
|
|
assert1 = id == 1;
|
|
|
|
value2 += 5000;
|
|
|
|
value2 += 5000;
|
|
|
|
Fiber::YieldTo(fiber1, thread_fibers[id]);
|
|
|
|
Fiber::YieldTo(fiber1, thread_fibers[id]);
|
|
|
@ -115,8 +134,7 @@ public:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoWork3() {
|
|
|
|
void DoWork3() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
assert2 = id == 0;
|
|
|
|
assert2 = id == 0;
|
|
|
|
value1 += 1000;
|
|
|
|
value1 += 1000;
|
|
|
|
Fiber::YieldTo(fiber3, thread_fibers[id]);
|
|
|
|
Fiber::YieldTo(fiber3, thread_fibers[id]);
|
|
|
@ -125,14 +143,12 @@ public:
|
|
|
|
void ExecuteThread(u32 id);
|
|
|
|
void ExecuteThread(u32 id);
|
|
|
|
|
|
|
|
|
|
|
|
void CallFiber1() {
|
|
|
|
void CallFiber1() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
Fiber::YieldTo(thread_fibers[id], fiber1);
|
|
|
|
Fiber::YieldTo(thread_fibers[id], fiber1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CallFiber2() {
|
|
|
|
void CallFiber2() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
Fiber::YieldTo(thread_fibers[id], fiber2);
|
|
|
|
Fiber::YieldTo(thread_fibers[id], fiber2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -145,7 +161,7 @@ public:
|
|
|
|
u32 value2{};
|
|
|
|
u32 value2{};
|
|
|
|
std::atomic<bool> trap{true};
|
|
|
|
std::atomic<bool> trap{true};
|
|
|
|
std::atomic<bool> trap2{true};
|
|
|
|
std::atomic<bool> trap2{true};
|
|
|
|
std::unordered_map<std::thread::id, u32> ids;
|
|
|
|
ThreadIds thread_ids;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber1;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber1;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber2;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber2;
|
|
|
@ -168,15 +184,13 @@ static void WorkControl2_3(void* control) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestControl2::ExecuteThread(u32 id) {
|
|
|
|
void TestControl2::ExecuteThread(u32 id) {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
thread_ids.Register(id);
|
|
|
|
ids[this_id] = id;
|
|
|
|
|
|
|
|
auto thread_fiber = Fiber::ThreadToFiber();
|
|
|
|
auto thread_fiber = Fiber::ThreadToFiber();
|
|
|
|
thread_fibers[id] = thread_fiber;
|
|
|
|
thread_fibers[id] = thread_fiber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestControl2::Exit() {
|
|
|
|
void TestControl2::Exit() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
thread_fibers[id]->Exit();
|
|
|
|
thread_fibers[id]->Exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -228,24 +242,21 @@ public:
|
|
|
|
void DoWork1() {
|
|
|
|
void DoWork1() {
|
|
|
|
value1 += 1;
|
|
|
|
value1 += 1;
|
|
|
|
Fiber::YieldTo(fiber1, fiber2);
|
|
|
|
Fiber::YieldTo(fiber1, fiber2);
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
value3 += 1;
|
|
|
|
value3 += 1;
|
|
|
|
Fiber::YieldTo(fiber1, thread_fibers[id]);
|
|
|
|
Fiber::YieldTo(fiber1, thread_fibers[id]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoWork2() {
|
|
|
|
void DoWork2() {
|
|
|
|
value2 += 1;
|
|
|
|
value2 += 1;
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
Fiber::YieldTo(fiber2, thread_fibers[id]);
|
|
|
|
Fiber::YieldTo(fiber2, thread_fibers[id]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExecuteThread(u32 id);
|
|
|
|
void ExecuteThread(u32 id);
|
|
|
|
|
|
|
|
|
|
|
|
void CallFiber1() {
|
|
|
|
void CallFiber1() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
Fiber::YieldTo(thread_fibers[id], fiber1);
|
|
|
|
Fiber::YieldTo(thread_fibers[id], fiber1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -254,7 +265,7 @@ public:
|
|
|
|
u32 value1{};
|
|
|
|
u32 value1{};
|
|
|
|
u32 value2{};
|
|
|
|
u32 value2{};
|
|
|
|
u32 value3{};
|
|
|
|
u32 value3{};
|
|
|
|
std::unordered_map<std::thread::id, u32> ids;
|
|
|
|
ThreadIds thread_ids;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
|
|
|
|
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber1;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber1;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber2;
|
|
|
|
std::shared_ptr<Common::Fiber> fiber2;
|
|
|
@ -271,15 +282,13 @@ static void WorkControl3_2(void* control) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestControl3::ExecuteThread(u32 id) {
|
|
|
|
void TestControl3::ExecuteThread(u32 id) {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
thread_ids.Register(id);
|
|
|
|
ids[this_id] = id;
|
|
|
|
|
|
|
|
auto thread_fiber = Fiber::ThreadToFiber();
|
|
|
|
auto thread_fiber = Fiber::ThreadToFiber();
|
|
|
|
thread_fibers[id] = thread_fiber;
|
|
|
|
thread_fibers[id] = thread_fiber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestControl3::Exit() {
|
|
|
|
void TestControl3::Exit() {
|
|
|
|
std::thread::id this_id = std::this_thread::get_id();
|
|
|
|
const u32 id = thread_ids.Get();
|
|
|
|
u32 id = ids[this_id];
|
|
|
|
|
|
|
|
thread_fibers[id]->Exit();
|
|
|
|
thread_fibers[id]->Exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|