linux WIP

This commit is contained in:
Mikulas Florek 2020-02-14 19:56:38 +01:00
parent fa858997d4
commit a6413f7d57
21 changed files with 258 additions and 446 deletions

View file

@ -22,7 +22,6 @@
#include "engine/job_system.h"
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "engine/path_utils.h"
#include "engine/plugin_manager.h"
@ -187,7 +186,7 @@ public:
, m_events(m_allocator)
, m_windows(m_allocator)
{
if (!JobSystem::init(MT::getCPUsCount(), m_allocator)) {
if (!JobSystem::init(OS::getCPUsCount(), m_allocator)) {
logError("Engine") << "Failed to initialize job system.";
}
}
@ -299,7 +298,7 @@ public:
if (frame_time < 1 / wanted_fps) {
PROFILE_BLOCK("sleep");
MT::sleep(u32(1000 / wanted_fps - frame_time * 1000));
OS::sleep(u32(1000 / wanted_fps - frame_time * 1000));
}
m_inactive_fps_timer.tick();
}

View file

@ -8,7 +8,6 @@
#include "engine/math.h"
#include "engine/mt/sync.h"
#include "engine/mt/task.h"
#include "engine/mt/thread.h"
#include "engine/profiler.h"
@ -70,11 +69,10 @@ struct System
, m_free_queue(allocator)
, m_free_fibers(allocator)
, m_backup_workers(allocator)
, m_outside_job_semaphore(0, 1)
{
m_signals_pool.resize(4096);
m_free_queue.resize(4096);
m_event_outside_job.trigger();
m_work_signal.reset();
for(int i = 0; i < 4096; ++i) {
m_free_queue[i] = i;
m_signals_pool[i].sibling = JobSystem::INVALID_HANDLE;
@ -85,8 +83,7 @@ struct System
MT::CriticalSection m_sync;
MT::CriticalSection m_job_queue_sync;
MT::Event m_event_outside_job;
MT::Event m_work_signal;
MT::Semaphore m_outside_job_semaphore;
Array<WorkerTask*> m_workers;
Array<WorkerTask*> m_backup_workers;
Array<Job> m_job_queue;
@ -119,8 +116,6 @@ struct WorkerTask : MT::Task
, m_job_queue(system.m_allocator)
, m_ready_fibers(system.m_allocator)
{
m_enabled.reset();
m_work_signal.reset();
}
@ -159,8 +154,6 @@ struct WorkerTask : MT::Task
u8 m_worker_index;
bool m_is_enabled = false;
bool m_is_backup = false;
MT::Event m_enabled;
MT::Event m_work_signal;
};
@ -184,11 +177,13 @@ static void pushJob(const Job& job)
if (job.worker_index != ANY_WORKER) {
WorkerTask* worker = g_system->m_workers[job.worker_index % g_system->m_workers.size()];
worker->m_job_queue.push(job);
worker->m_work_signal.trigger();
worker->wakeup();
return;
}
g_system->m_job_queue.push(job);
g_system->m_work_signal.trigger();
for (WorkerTask* worker : g_system->m_workers) {
worker->wakeup();
}
}
@ -285,12 +280,6 @@ void enableBackupWorker(bool enable)
for (WorkerTask* task : g_system->m_backup_workers) {
if (task->m_is_enabled != enable) {
task->m_is_enabled = enable;
if (enable) {
task->m_enabled.trigger();
}
else {
task->m_enabled.reset();
}
return;
}
}
@ -301,7 +290,6 @@ void enableBackupWorker(bool enable)
g_system->m_backup_workers.push(task);
task->m_is_enabled = true;
task->m_is_backup = true;
task->m_enabled.trigger();
}
else {
logError("Engine") << "Job system backup worker failed to initialize.";
@ -358,38 +346,43 @@ void runEx(void* data, void(*task)(void*), SignalHandle* on_finished, SignalHand
WorkerTask* worker = getWorker();
while (!worker->m_finished) {
if (worker->m_is_backup) {
if (!worker->m_enabled.poll()) {
MT::CriticalSectionLock guard(g_system->m_sync);
while (!worker->m_is_enabled) {
PROFILE_BLOCK("disabled");
Profiler::blockColor(0xff, 0, 0xff);
worker->m_enabled.wait();
worker->sleep(g_system->m_sync);
}
}
FiberDecl* fiber = nullptr;
Job job;
{
while (!worker->m_finished) {
MT::CriticalSectionLock lock(g_system->m_job_queue_sync);
if (!worker->m_ready_fibers.empty()) {
fiber = worker->m_ready_fibers.back();
worker->m_ready_fibers.pop();
if (worker->m_ready_fibers.empty()) worker->m_work_signal.reset();
break;
}
else if (!worker->m_job_queue.empty()) {
if (!worker->m_job_queue.empty()) {
job = worker->m_job_queue.back();
worker->m_job_queue.pop();
if (worker->m_job_queue.empty()) worker->m_work_signal.reset();
break;
}
else if (!g_system->m_ready_fibers.empty()) {
if (!g_system->m_ready_fibers.empty()) {
fiber = g_system->m_ready_fibers.back();
g_system->m_ready_fibers.pop();
if (g_system->m_ready_fibers.empty()) g_system->m_work_signal.reset();
break;
}
else if(!g_system->m_job_queue.empty()) {
if(!g_system->m_job_queue.empty()) {
job = g_system->m_job_queue.back();
g_system->m_job_queue.pop();
if (g_system->m_job_queue.empty()) g_system->m_work_signal.reset();
break;
}
PROFILE_BLOCK("sleeping");
Profiler::blockColor(0xff, 0, 0xff);
worker->sleep(g_system->m_job_queue_sync);
}
if (fiber) {
@ -406,10 +399,8 @@ void runEx(void* data, void(*task)(void*), SignalHandle* on_finished, SignalHand
Profiler::blockColor(0, 0, 0xff);
worker = getWorker();
worker->m_current_fiber = this_fiber;
continue;
}
if (job.task) {
else {
Profiler::endBlock();
Profiler::beginBlock("job");
if (isValid(job.dec_on_finish) || isValid(job.precondition)) {
@ -426,12 +417,6 @@ void runEx(void* data, void(*task)(void*), SignalHandle* on_finished, SignalHand
Profiler::beginBlock("job management");
Profiler::blockColor(0, 0, 0xff);
}
else
{
PROFILE_BLOCK("idle");
Profiler::blockColor(0xff, 0, 0xff);
MT::Event::waitMultiple(g_system->m_work_signal, worker->m_work_signal, 1);
}
}
Profiler::endBlock();
Fiber::switchTo(&getWorker()->m_current_fiber->fiber, getWorker()->m_primary_fiber);
@ -443,7 +428,6 @@ bool init(u8 workers_count, IAllocator& allocator)
ASSERT(!g_system);
g_system = LUMIX_NEW(allocator, System)(allocator);
g_system->m_work_signal.reset();
g_system->m_free_fibers.reserve(lengthOf(g_system->m_fiber_pool));
for (FiberDecl& fiber : g_system->m_fiber_pool) {
@ -461,7 +445,6 @@ bool init(u8 workers_count, IAllocator& allocator)
WorkerTask* task = LUMIX_NEW(allocator, WorkerTask)(*g_system, i < 64 ? u64(1) << i : 0);
if (task->create("Worker", false)) {
task->m_is_enabled = true;
task->m_enabled.trigger();
g_system->m_workers.push(task);
task->setAffinityMask((u64)1 << i);
}
@ -493,23 +476,22 @@ void shutdown()
WorkerTask* wt = (WorkerTask*)task;
wt->m_finished = true;
}
for (MT::Task* task : g_system->m_backup_workers)
{
for (MT::Task* task : g_system->m_backup_workers) {
WorkerTask* wt = (WorkerTask*)task;
wt->m_finished = true;
wt->m_enabled.trigger();
wt->wakeup();
}
for (MT::Task* task : g_system->m_backup_workers)
for (WorkerTask* task : g_system->m_backup_workers)
{
while (!task->isFinished()) g_system->m_work_signal.trigger();
while (!task->isFinished()) task->wakeup();
task->destroy();
LUMIX_DELETE(allocator, task);
}
for (MT::Task* task : g_system->m_workers)
for (WorkerTask* task : g_system->m_workers)
{
while (!task->isFinished()) g_system->m_work_signal.trigger();
while (!task->isFinished()) task->wakeup();
task->destroy();
LUMIX_DELETE(allocator, task);
}
@ -543,12 +525,14 @@ void wait(SignalHandle handle)
FiberDecl* fiber = (FiberDecl*)data;
if (fiber->current_job.worker_index == ANY_WORKER) {
g_system->m_ready_fibers.push(fiber);
g_system->m_work_signal.trigger();
for (WorkerTask* worker : g_system->m_workers) {
worker->wakeup();
}
}
else {
WorkerTask* worker = g_system->m_workers[fiber->current_job.worker_index % g_system->m_workers.size()];
worker->m_ready_fibers.push(fiber);
worker->m_work_signal.trigger();
worker->wakeup();
}
}, handle, false, nullptr, 0);
@ -576,18 +560,16 @@ void wait(SignalHandle handle)
PROFILE_BLOCK("not a job waiting");
Profiler::blockColor(0xff, 0, 0);
g_system->m_event_outside_job.reset();
static bool singleton = true;
ASSERT(singleton); // only one external thread supported
singleton = false;
runInternal(nullptr, [](void* data) {
g_system->m_event_outside_job.trigger();
g_system->m_outside_job_semaphore.signal();
}, handle, false, nullptr, 0);
g_system->m_sync.exit();
MT::yield();
while (!isSignalZero(handle, true)) {
g_system->m_event_outside_job.waitTimeout(100);
}
g_system->m_outside_job_semaphore.wait();
singleton = true;
}
}

View file

@ -192,6 +192,9 @@ OutputFile& OutputFile::operator <<(float value)
return *this;
}
u32 getCPUsCount() { return sysconf(_SC_NPROCESSORS_ONLN); }
void sleep(u32 milliseconds) { if (milliseconds) usleep(useconds_t(milliseconds * 1000)); }
ThreadID getCurrentThreadID() { return pthread_self(); }
void logVersion() {
struct utsname tmp;

View file

@ -2,7 +2,6 @@
#include "engine/crt.h"
#include "engine/mt/sync.h"
#include "engine/mt/atomic.h"
#include "engine/mt/thread.h"
#include "engine/profiler.h"
#include "engine/string.h"
#include <errno.h>
@ -15,6 +14,25 @@ namespace Lumix
namespace MT
{
ConditionVariable::ConditionVariable() {
const int res = pthread_cond_init(&cv, nullptr);
ASSERT(res == 0);
}
ConditionVariable::~ConditionVariable() {
const int res = pthread_cond_destroy(&cv);
ASSERT(res == 0);
}
void ConditionVariable::sleep(CriticalSection& cs) {
const int res = pthread_cond_wait(&cv, &cs.mutex);
ASSERT(res == 0);
}
void ConditionVariable::wakeup() {
const int res = pthread_cond_signal(&cv);
ASSERT(res == 0);
}
Semaphore::Semaphore(int init_count, int max_count)
{
@ -61,82 +79,6 @@ void Semaphore::wait()
ASSERT(res == 0);
}
bool Semaphore::poll()
{
int res = pthread_mutex_lock(&m_id.mutex);
ASSERT(res == 0);
bool ret = false;
if(m_id.count > 0)
{
--m_id.count;
ret = true;
}
res = pthread_mutex_unlock(&m_id.mutex);
ASSERT(res == 0);
return ret;
}
Event::Event()
{
m_id = eventfd(0, EFD_NONBLOCK);
}
Event::~Event()
{
close(m_id);
}
void Event::reset()
{
u64 v;
read(m_id, &v, sizeof(v)); // reset to 0, nonblocking
}
void Event::trigger()
{
const u64 v = 1;
const ssize_t res = write(m_id, &v, sizeof(v));
ASSERT(res == sizeof(v));
}
void Event::waitMultiple(Event& event0, Event& event1, u32 timeout_ms)
{
pollfd fds[2];
fds[0].fd = event0.m_id;
fds[1].fd = event1.m_id;
fds[0].events = POLLIN;
fds[1].events = POLLIN;
::poll(fds, 2, timeout_ms);
}
void Event::waitTimeout(u32 timeout_ms)
{
pollfd pfd;
pfd.fd = m_id;
pfd.events = POLLIN;
::poll(&pfd, 1, timeout_ms);
}
void Event::wait()
{
pollfd pfd;
pfd.fd = m_id;
pfd.events = POLLIN;
::poll(&pfd, 1, -1);
}
bool Event::poll()
{
pollfd pfd;
pfd.fd = m_id;
pfd.events = POLLIN;
const int res = ::poll(&pfd, 1, 0);
return res > 0;
}
CriticalSection::CriticalSection()
{

View file

@ -1,107 +0,0 @@
#include "engine/allocator.h"
#include "engine/lumix.h"
#include "engine/mt/task.h"
#include "engine/mt/thread.h"
#include "engine/profiler.h"
#include <pthread.h>
namespace Lumix
{
namespace MT
{
struct TaskImpl
{
IAllocator& allocator;
bool force_exit;
bool exited;
bool is_running;
pthread_t handle;
const char* thread_name;
u64 affinity_mask;
Task* owner;
};
static void* threadFunction(void* ptr)
{
struct TaskImpl* impl = reinterpret_cast<TaskImpl*>(ptr);
setThreadName(getCurrentThreadID(), impl->thread_name);
Profiler::setThreadName(impl->thread_name);
u32 ret = 0xffffFFFF;
if (!impl->force_exit) ret = impl->owner->task();
impl->exited = true;
impl->is_running = false;
return nullptr;
}
Task::Task(IAllocator& allocator)
{
auto impl = LUMIX_NEW(allocator, TaskImpl) {allocator};
impl->is_running = false;
impl->force_exit = false;
impl->exited = false;
impl->thread_name = "";
impl->owner = this;
impl->affinity_mask = getThreadAffinityMask();
m_implementation = impl;
}
Task::~Task()
{
LUMIX_DELETE(m_implementation->allocator, m_implementation);
}
bool Task::create(const char* name, bool is_extended)
{
pthread_attr_t attr;
int res = pthread_attr_init(&attr);
ASSERT(res == 0);
if (res != 0) return false;
res = pthread_create(&m_implementation->handle, &attr, threadFunction, m_implementation);
ASSERT(res == 0);
if (res != 0) return false;
return true;
}
bool Task::destroy()
{
return pthread_join(m_implementation->handle, nullptr) == 0;
}
void Task::setAffinityMask(u64 affinity_mask)
{
cpu_set_t set;
CPU_ZERO(&set);
for (int i = 0; i < 64; ++i)
{
if (affinity_mask & ((u64)1 << i))
{
CPU_SET(i, &set);
}
}
m_implementation->affinity_mask = affinity_mask;
pthread_setaffinity_np(m_implementation->handle, sizeof(set), &set);
}
bool Task::isRunning() const
{
return m_implementation->is_running;
}
bool Task::isFinished() const
{
return m_implementation->exited;
}
IAllocator& Task::getAllocator()
{
return m_implementation->allocator;
}
} // namespace MT
} // namespace Lumix

View file

@ -1,8 +1,10 @@
#include "engine/allocator.h"
#include "engine/lumix.h"
#include "engine/mt/thread.h"
#include "engine/mt/task.h"
#include "engine/mt/sync.h"
#include "engine/os.h"
#include "engine/profiler.h"
#include <pthread.h>
#include <time.h>
#include <unistd.h>
namespace Lumix
@ -10,50 +12,102 @@ namespace Lumix
namespace MT
{
void sleep(u32 milliseconds)
struct TaskImpl
{
if (milliseconds) usleep(useconds_t(milliseconds * 1000));
IAllocator& allocator;
bool force_exit;
bool exited;
bool is_running;
pthread_t handle;
const char* thread_name;
Task* owner;
ConditionVariable cv;
};
static void* threadFunction(void* ptr)
{
struct TaskImpl* impl = reinterpret_cast<TaskImpl*>(ptr);
pthread_setname_np(OS::getCurrentThreadID(), impl->thread_name);
Profiler::setThreadName(impl->thread_name);
u32 ret = 0xffffFFFF;
if (!impl->force_exit) ret = impl->owner->task();
impl->exited = true;
impl->is_running = false;
return nullptr;
}
void yield()
Task::Task(IAllocator& allocator)
{
pthread_yield();
auto impl = LUMIX_NEW(allocator, TaskImpl) {allocator};
impl->is_running = false;
impl->force_exit = false;
impl->exited = false;
impl->thread_name = "";
impl->owner = this;
m_implementation = impl;
}
u32 getCPUsCount()
Task::~Task()
{
return sysconf(_SC_NPROCESSORS_ONLN);
LUMIX_DELETE(m_implementation->allocator, m_implementation);
}
ThreadID getCurrentThreadID()
{
return pthread_self();
void Task::sleep(CriticalSection& cs) {
ASSERT(pthread_self() == m_implementation->handle);
m_implementation->cv.sleep(cs);
}
u64 getThreadAffinityMask()
void Task::wakeup() { m_implementation->cv.wakeup(); }
bool Task::create(const char* name, bool is_extended)
{
cpu_set_t cpu_set;
int r = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
ASSERT(r == 0);
if(CPU_COUNT(&cpu_set) == 0) return 0;
int affinity = 0;
for(u64 i = 0; i < sizeof(u64) * 8; ++i)
pthread_attr_t attr;
int res = pthread_attr_init(&attr);
ASSERT(res == 0);
if (res != 0) return false;
res = pthread_create(&m_implementation->handle, &attr, threadFunction, m_implementation);
ASSERT(res == 0);
if (res != 0) return false;
return true;
}
bool Task::destroy()
{
return pthread_join(m_implementation->handle, nullptr) == 0;
}
void Task::setAffinityMask(u64 affinity_mask)
{
cpu_set_t set;
CPU_ZERO(&set);
for (int i = 0; i < 64; ++i)
{
if (CPU_ISSET(i, &cpu_set)) affinity = affinity | (1 << i);
if (affinity_mask & ((u64)1 << i))
{
CPU_SET(i, &set);
}
}
return affinity;
pthread_setaffinity_np(m_implementation->handle, sizeof(set), &set);
}
void setThreadName(ThreadID thread_id, const char* thread_name)
bool Task::isRunning() const
{
pthread_setname_np(thread_id, thread_name);
return m_implementation->is_running;
}
bool Task::isFinished() const
{
return m_implementation->exited;
}
IAllocator& Task::getAllocator()
{
return m_implementation->allocator;
}
} // namespace MT
} // namespace Lumix
} //! namespace MT
} //! namespace Lumix

View file

@ -28,6 +28,7 @@ namespace MT
class alignas(8) LUMIX_ENGINE_API CriticalSection
{
friend class ConditionVariable;
public:
CriticalSection();
~CriticalSection();
@ -55,31 +56,25 @@ public:
void signal();
void wait();
bool poll();
private:
SemaphoreHandle m_id;
};
class LUMIX_ENGINE_API Event
class ConditionVariable
{
public:
explicit Event();
~Event();
void reset();
void trigger();
void wait();
void waitTimeout(u32 timeout_ms);
bool poll();
static void waitMultiple(Event& event0, Event& event1, u32 timeout_ms);
ConditionVariable();
~ConditionVariable();
void sleep(CriticalSection& cs);
void wakeup();
private:
EventHandle m_id;
#ifdef _WIN32
u8 data[64];
#else
pthread_cond_t cv;
#endif
};

View file

@ -11,6 +11,7 @@ struct IAllocator;
namespace MT
{
class CriticalSection;
class LUMIX_ENGINE_API Task
{
@ -25,6 +26,10 @@ public:
void setAffinityMask(u64 affinity_mask);
// call only from task's thread
void sleep(CriticalSection& cs);
void wakeup();
bool isRunning() const;
bool isFinished() const;

View file

@ -1,29 +0,0 @@
#pragma once
#include "engine/lumix.h"
#ifdef __linux__
#include <pthread.h>
#endif
namespace Lumix { namespace MT {
#ifdef _WIN32
typedef u32 ThreadID;
#else
typedef pthread_t ThreadID;
#endif
LUMIX_ENGINE_API void setThreadName(ThreadID thread_id, const char* thread_name);
LUMIX_ENGINE_API void sleep(u32 milliseconds);
LUMIX_ENGINE_API void yield();
LUMIX_ENGINE_API u32 getCPUsCount();
LUMIX_ENGINE_API ThreadID getCurrentThreadID();
LUMIX_ENGINE_API u64 getThreadAffinityMask();
} // namespace MT
} // namespace Lumix

View file

@ -2,7 +2,6 @@
#include "engine/crt.h"
#include "engine/mt/sync.h"
#include "engine/mt/atomic.h"
#include "engine/mt/thread.h"
#include "engine/profiler.h"
#include "engine/string.h"
#include "engine/win/simple_win.h"
@ -35,53 +34,20 @@ void Semaphore::wait()
::WaitForSingleObject(m_id, INFINITE);
}
bool Semaphore::poll()
{
return WAIT_OBJECT_0 == ::WaitForSingleObject(m_id, 0);
ConditionVariable::~ConditionVariable() {
((CONDITION_VARIABLE*)data)->~CONDITION_VARIABLE();
}
Event::Event()
{
m_id = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
}
Event::~Event()
{
::CloseHandle(m_id);
}
void Event::reset()
{
::ResetEvent(m_id);
}
void Event::trigger()
{
::SetEvent(m_id);
}
void Event::waitMultiple(Event& event0, Event& event1, u32 timeout_ms)
{
const HANDLE handles[2] = { event0.m_id, event1.m_id };
::WaitForMultipleObjects(2, handles, false, timeout_ms);
}
void Event::waitTimeout(u32 timeout_ms)
{
::WaitForSingleObject(m_id, timeout_ms);
}
void Event::wait()
{
::WaitForSingleObject(m_id, INFINITE);
}
bool Event::poll()
{
return WAIT_OBJECT_0 == ::WaitForSingleObject(m_id, 0);
ConditionVariable::ConditionVariable() {
static_assert(sizeof(data) >= sizeof(CONDITION_VARIABLE), "Size is not enough");
static_assert(alignof(CONDITION_VARIABLE) == alignof(CONDITION_VARIABLE), "Alignment does not match");
memset(data, 0, sizeof(data));
CONDITION_VARIABLE* cv = new (NewPlaceholder(), data) CONDITION_VARIABLE;
InitializeConditionVariable(cv);
}
void ConditionVariable::sleep(CriticalSection& cs) { SleepConditionVariableCS((CONDITION_VARIABLE*)data, (CRITICAL_SECTION*)cs.data, INFINITE); }
void ConditionVariable::wakeup() { WakeConditionVariable((CONDITION_VARIABLE*)data); }
CriticalSection::CriticalSection()
{

View file

@ -1,7 +1,8 @@
#include "engine/lumix.h"
#include "engine/allocator.h"
#include "engine/mt/sync.h"
#include "engine/mt/task.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "engine/win/simple_win.h"
#include "engine/profiler.h"
@ -29,9 +30,39 @@ struct TaskImpl
volatile bool m_is_running;
volatile bool m_exited;
const char* m_thread_name;
MT::ConditionVariable m_cv;
Task* m_owner;
};
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD type;
LPCSTR name;
DWORD thread_id;
DWORD flags;
} THREADNAME_INFO;
#pragma pack(pop)
static void setThreadName(OS::ThreadID thread_id, const char* thread_name)
{
THREADNAME_INFO info;
info.type = 0x1000;
info.name = thread_name;
info.thread_id = thread_id;
info.flags = 0;
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
static DWORD WINAPI threadFunction(LPVOID ptr)
{
struct TaskImpl* impl = reinterpret_cast<TaskImpl*>(ptr);
@ -47,7 +78,6 @@ Task::Task(IAllocator& allocator)
{
TaskImpl* impl = LUMIX_NEW(allocator, TaskImpl)(allocator);
impl->m_handle = nullptr;
impl->m_affinity_mask = getThreadAffinityMask();
impl->m_priority = ::GetThreadPriority(GetCurrentThread());
impl->m_is_running = false;
impl->m_exited = false;
@ -73,7 +103,6 @@ bool Task::create(const char* name, bool is_extended)
m_implementation->m_thread_name = name;
m_implementation->m_handle = handle;
m_implementation->m_is_running = true;
SetThreadAffinityMask(handle, m_implementation->m_affinity_mask);
bool success = ::ResumeThread(m_implementation->m_handle) != -1;
if (success)
@ -89,10 +118,7 @@ bool Task::create(const char* name, bool is_extended)
bool Task::destroy()
{
while (m_implementation->m_is_running)
{
yield();
}
while (m_implementation->m_is_running) OS::sleep(1);
::CloseHandle(m_implementation->m_handle);
m_implementation->m_handle = nullptr;
@ -108,6 +134,14 @@ void Task::setAffinityMask(u64 affinity_mask)
}
}
void Task::sleep(CriticalSection& cs) {
m_implementation->m_cv.sleep(cs);
}
void Task::wakeup() {
m_implementation->m_cv.wakeup();
}
bool Task::isRunning() const
{
return m_implementation->m_is_running;

View file

@ -1,64 +0,0 @@
#include "engine/lumix.h"
#include "engine/mt/thread.h"
#include "engine/win/simple_win.h"
namespace Lumix
{
namespace MT
{
static_assert(sizeof(ThreadID) == sizeof(::GetCurrentThreadId()), "Not matching");
void sleep(u32 milliseconds) { ::Sleep(milliseconds); }
void yield() { sleep(0); }
u32 getCPUsCount()
{
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
u32 num = sys_info.dwNumberOfProcessors;
num = num > 0 ? num : 1;
return num;
}
ThreadID getCurrentThreadID() { return ::GetCurrentThreadId(); }
u64 getThreadAffinityMask()
{
DWORD_PTR affinity_mask = ::SetThreadAffinityMask(::GetCurrentThread(), ~(DWORD_PTR)0);
::SetThreadAffinityMask(::GetCurrentThread(), affinity_mask);
return affinity_mask;
}
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD type;
LPCSTR name;
DWORD thread_id;
DWORD flags;
} THREADNAME_INFO;
#pragma pack(pop)
void setThreadName(ThreadID thread_id, const char* thread_name)
{
THREADNAME_INFO info;
info.type = 0x1000;
info.name = thread_name;
info.thread_id = thread_id;
info.flags = 0;
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
} //!namespace MT
} //!namespace Lumix

View file

@ -3,6 +3,9 @@
#include "lumix.h"
#include "stream.h"
#ifdef __linux__
#include <pthread.h>
#endif
namespace Lumix
@ -13,6 +16,12 @@ struct IAllocator;
namespace OS
{
#ifdef _WIN32
typedef u32 ThreadID;
#else
typedef pthread_t ThreadID;
#endif
enum class Keycode : u8;
enum class ExecuteOpenResult : int
@ -158,6 +167,9 @@ struct WindowState {
};
LUMIX_ENGINE_API void logVersion();
LUMIX_ENGINE_API u32 getCPUsCount();
LUMIX_ENGINE_API void sleep(u32 milliseconds);
LUMIX_ENGINE_API ThreadID getCurrentThreadID();
LUMIX_ENGINE_API void* memReserve(size_t size);
LUMIX_ENGINE_API void memCommit(void* ptr, size_t size);

View file

@ -13,7 +13,6 @@
#include "engine/mt/atomic.h"
#include "engine/mt/sync.h"
#include "engine/mt/task.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "profiler.h"
@ -155,7 +154,7 @@ static struct Instance
{
thread_local ThreadContext* ctx = [&](){
ThreadContext* new_ctx = LUMIX_NEW(allocator, ThreadContext)(allocator);
new_ctx->thread_id = MT::getCurrentThreadID();
new_ctx->thread_id = OS::getCurrentThreadID();
MT::CriticalSectionLock lock(mutex);
contexts.push(new_ctx);
return new_ctx;

View file

@ -229,6 +229,20 @@ struct WCharStr
WCHAR data[N];
};
void sleep(u32 milliseconds) { ::Sleep(milliseconds); }
static_assert(sizeof(ThreadID) == sizeof(::GetCurrentThreadId()), "Not matching");
ThreadID getCurrentThreadID() { return ::GetCurrentThreadId(); }
u32 getCPUsCount() {
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
u32 num = sys_info.dwNumberOfProcessors;
num = num > 0 ? num : 1;
return num;
}
void logVersion() {
DWORD dwVersion = 0;

View file

@ -284,6 +284,13 @@ typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY;
typedef struct _RTL_CONDITION_VARIABLE {
PVOID Ptr;
} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
typedef struct _RTL_CRITICAL_SECTION_DEBUG {
WORD Type;
WORD CreatorBackTraceIndex;
@ -311,6 +318,7 @@ typedef struct _RTL_CRITICAL_SECTION {
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION;
typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION;
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
@ -550,6 +558,9 @@ WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSectio
WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
WINBASEAPI BOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,

View file

@ -9,7 +9,7 @@
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/math.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "engine/path.h"
#include "engine/profiler.h"
#include "engine/reflection.h"
@ -244,7 +244,7 @@ struct PhysicsSceneImpl final : public PhysicsScene
},
nullptr);
}
PxU32 getWorkerCount() const override { return MT::getCPUsCount(); }
PxU32 getWorkerCount() const override { return OS::getCPUsCount(); }
};

View file

@ -8,7 +8,6 @@
#include "engine/job_system.h"
#include "engine/lumix.h"
#include "engine/math.h"
#include "engine/mt/thread.h"
#include "engine/page_allocator.h"
#include "engine/profiler.h"
#include "engine/simd.h"

View file

@ -18,7 +18,6 @@
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/lumix.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "engine/path_utils.h"
#include "engine/plugin_manager.h"
@ -2942,7 +2941,7 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
, 10
, 1
, cmft::EdgeFixup::None
, MT::getCPUsCount()
, OS::getCPUsCount()
);
}
cmft::imageFromRgba32f(image, cmft::TextureFormat::RGBA8);

View file

@ -5,7 +5,6 @@
#include "engine/log.h"
#include "engine/math.h"
#include "engine/mt/sync.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "engine/stream.h"
#ifdef _WIN32
@ -116,7 +115,7 @@ static struct {
Pool<Texture, Texture::MAX_COUNT> textures;
Pool<Program, Program::MAX_COUNT> programs;
MT::CriticalSection handle_mutex;
Lumix::MT::ThreadID thread;
Lumix::OS::ThreadID thread;
int instance_attributes = 0;
int max_vertex_attributes = 16;
ProgramHandle last_program = INVALID_PROGRAM;
@ -713,7 +712,7 @@ static void flipCompressedTexture(int w, int h, int format, void* surface)
void checkThread()
{
ASSERT(g_gpu.thread == Lumix::MT::getCurrentThreadID());
ASSERT(g_gpu.thread == OS::getCurrentThreadID());
}
static void try_load_renderdoc()
@ -2125,7 +2124,7 @@ bool init(void* window_handle, u32 init_flags)
const bool debug = init_flags & (u32)InitFlags::DEBUG_OUTPUT;
#endif
g_gpu.thread = MT::getCurrentThreadID();
g_gpu.thread = OS::getCurrentThreadID();
g_gpu.contexts[0].window_handle = window_handle;
#ifdef _WIN32
g_gpu.contexts[0].device_context = GetDC((HWND)window_handle);

View file

@ -10,7 +10,6 @@
#include "engine/job_system.h"
#include "engine/mt/sync.h"
#include "engine/mt/task.h"
#include "engine/mt/thread.h"
#include "engine/os.h"
#include "engine/profiler.h"
#include "engine/reflection.h"
@ -209,7 +208,7 @@ struct GPUProfiler
const u64 cpu_timestamp = OS::Timer::getRawTimestamp();
u32 try_num = 0;
while (!gpu::isQueryReady(q) && try_num < 1000) {
MT::sleep(1);
OS::sleep(1);
++try_num;
}
if (try_num == 1000) {