This commit is contained in:
Nekotekina 2016-05-13 17:01:48 +03:00
parent e2d82394f6
commit 266db1336d
81 changed files with 2247 additions and 1731 deletions

View file

@ -1,8 +1,8 @@
#pragma once
#include <exception>
#include <string>
#include <memory>
#include <thread>
#include "Platform.h"
#include "Atomic.h"
@ -28,38 +28,41 @@ class task_stack
}
};
template<typename F>
struct task_type : task_base
{
std::remove_reference_t<F> func;
task_type(F&& func)
: func(std::forward<F>(func))
{
}
void exec() override
{
func();
task_base::exec();
}
};
std::unique_ptr<task_base> m_stack;
public:
task_stack() = default;
template<typename F>
void push(F&& func)
task_stack(F&& func)
: m_stack(new task_type<F>(std::forward<F>(func)))
{
struct task_t : task_base
{
std::remove_reference_t<F> func;
}
task_t(F&& func)
: func(std::forward<F>(func))
{
}
void exec() override
{
func();
task_base::exec();
}
};
auto _top = new task_t(std::forward<F>(func));
void push(task_stack stack)
{
auto _top = stack.m_stack.release();
auto _next = m_stack.release();
m_stack.reset(_top);
#ifndef _MSC_VER
while (UNLIKELY(_top->next)) _top = _top->next.get();
_top->next.reset(_next);
#else
auto& next = _top->next;
next.release();
next.reset(_next);
#endif
}
void reset()
@ -79,42 +82,48 @@ public:
// Thread control class
class thread_ctrl final
{
public: // TODO
struct internal;
private:
static thread_local thread_ctrl* g_tls_this_thread;
// Thread handle
std::thread m_thread;
// Thread handle storage
std::aligned_storage_t<16> m_thread;
// Thread join contention counter
atomic_t<uint> m_joining{};
atomic_t<u32> m_joining{};
// Thread internals
atomic_t<internal*> m_data{};
// Fixed name
std::string m_name;
// Thread internals
mutable atomic_t<internal*> m_data{};
// Start thread
static void start(const std::shared_ptr<thread_ctrl>&, task_stack);
// Called at the thread start
void initialize();
// Set std::current_exception
void set_exception() noexcept;
// Called at the thread end
void finalize() noexcept;
// Get atexit function
task_stack& get_atexit() const;
void push_atexit(task_stack);
// Start waiting
void wait_start(u64 timeout);
// Proceed waiting
bool wait_wait(u64 timeout);
// Check exception
void test();
public:
template<typename N>
thread_ctrl(N&& name)
: m_name(std::forward<N>(name))
{
}
thread_ctrl(std::string&& name);
// Disable copy/move constructors and operators
thread_ctrl(const thread_ctrl&) = delete;
~thread_ctrl();
@ -126,54 +135,139 @@ public:
}
// Initialize internal data
void initialize_once() const;
void initialize_once();
// Get thread result (may throw, simultaneous joining allowed)
void join();
// Lock thread mutex
void lock();
// Lock conditionally (double-checked)
template<typename F>
bool lock_if(F&& pred)
{
if (pred())
{
lock();
try
{
if (LIKELY(pred()))
{
return true;
}
else
{
unlock();
return false;
}
}
catch (...)
{
unlock();
throw;
}
}
else
{
return false;
}
}
// Unlock thread mutex (internal data must be initialized)
void unlock();
// Lock, unlock, notify the thread (required if the condition changed locklessly)
void lock_notify() const;
void lock_notify();
// Notify the thread, beware the condition change
void notify() const;
// Notify the thread (internal data must be initialized)
void notify();
//
internal* get_data() const;
// Set exception (internal data must be initialized, thread mutex must be locked)
void set_exception(std::exception_ptr);
// Current thread sleeps for specified amount of microseconds.
// Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl.
[[deprecated]] static void sleep(u64 useconds);
// Wait until pred(). Abortable, may throw. Thread must be locked.
// Timeout in microseconds (zero means infinite).
template<typename F>
static inline auto wait(u64 useconds, F&& pred)
{
g_tls_this_thread->wait_start(useconds);
while (true)
{
g_tls_this_thread->test();
if (auto&& result = pred())
{
return result;
}
else if (!g_tls_this_thread->wait_wait(useconds) && useconds)
{
return result;
}
}
}
// Wait until pred(). Abortable, may throw. Thread must be locked.
template<typename F>
static inline auto wait(F&& pred)
{
while (true)
{
g_tls_this_thread->test();
if (auto&& result = pred())
{
return result;
}
g_tls_this_thread->wait_wait(0);
}
}
// Wait once. Thread must be locked.
static inline void wait()
{
g_tls_this_thread->test();
g_tls_this_thread->wait_wait(0);
g_tls_this_thread->test();
}
// Wait unconditionally until aborted. Thread must be locked.
[[noreturn]] static inline void eternalize()
{
while (true)
{
g_tls_this_thread->test();
g_tls_this_thread->wait_wait(0);
}
}
// Get current thread (may be nullptr)
static const thread_ctrl* get_current()
static thread_ctrl* get_current()
{
return g_tls_this_thread;
}
// Register function at thread exit (for the current thread)
template<typename F>
static inline void at_exit(F&& func)
static inline void atexit(F&& func)
{
return g_tls_this_thread->get_atexit().push(std::forward<F>(func));
return g_tls_this_thread->push_atexit(std::forward<F>(func));
}
// Named thread factory
template<typename N, typename F, typename... Args>
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func, Args&&... args)
template<typename N, typename F>
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func)
{
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)](Args&&... args)
{
try
{
ctrl->initialize();
task(std::forward<Args>(args)...);
}
catch (...)
{
ctrl->set_exception();
}
ctrl->finalize();
}, std::forward<Args>(args)...);
thread_ctrl::start(ctrl, std::forward<F>(func));
return ctrl;
}
@ -218,22 +312,43 @@ public:
m_thread->join();
}
// Get thread_ctrl
const thread_ctrl* operator->() const
// Access thread_ctrl
thread_ctrl* operator->() const
{
return m_thread.get();
}
};
// Lock mutex, notify condition variable
void lock_notify() const
// Simple thread mutex locker
class thread_lock final
{
thread_ctrl* m_thread;
public:
thread_lock(const thread_lock&) = delete;
// Lock specified thread
thread_lock(thread_ctrl* thread)
: m_thread(thread)
{
m_thread->lock_notify();
m_thread->lock();
}
// Notify condition variable
void notify() const
// Lock specified named_thread
thread_lock(named_thread& thread)
: thread_lock(thread.operator->())
{
m_thread->notify();
}
// Lock current thread
thread_lock()
: thread_lock(thread_ctrl::get_current())
{
}
~thread_lock()
{
m_thread->unlock();
}
};