named_thread: implement "default" event loop

Fixup "sleepy" thread at startup on Windows.
Permit threads which lack operator()() overload.
This commit is contained in:
Nekotekina 2021-02-24 13:56:02 +03:00
parent 29e7eda887
commit 3aaa0172d5
3 changed files with 22 additions and 8 deletions

View File

@ -2336,16 +2336,14 @@ bool thread_base::join(bool dtor) const
if (i > 20 && Emu.IsStopped())
{
stamp0 = __rdtsc();
atomic_wait_engine::raw_notify(0, get_native_id());
stamp0 = __rdtsc() - stamp0;
warn = true;
}
}
if (warn)
{
sig_log.error(u8"Thread [%s] is too sleepy. Took %.3fµs to wake it up!", *m_tname.load(), stamp0 / (utils::get_tsc_freq() / 1000000.));
sig_log.error(u8"Thread [%s] is too sleepy. Took %.3fµs to wake it up!", *m_tname.load(), (__rdtsc() - stamp0) / (utils::get_tsc_freq() / 1000000.));
}
return (m_sync & 3) == 3;

View File

@ -42,6 +42,8 @@ class need_wakeup {};
template <class Context>
class named_thread;
class thread_base;
template <typename Ctx, typename X = void, typename... Args>
struct result_storage
{
@ -234,7 +236,7 @@ public:
}
// Wait for both thread sync var and provided atomic var
template <typename T, atomic_wait::op op = atomic_wait::op::eq, typename U>
template <atomic_wait::op Op = atomic_wait::op::eq, typename T, typename U>
static inline void wait_on(T& wait, U old, u64 usec = -1)
{
auto _this = g_tls_this_thread;
@ -245,7 +247,7 @@ public:
}
atomic_wait::list<2> list{};
list.set<0, op>(wait, old);
list.set<0, Op>(wait, old);
list.set<1>(_this->m_sync, 0, 4 + 1);
list.wait(atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff});
}
@ -329,12 +331,23 @@ class named_thread final : public Context, result_storage<Context>, thread_base
if constexpr (result::empty)
{
// No result
Context::operator()();
if constexpr (std::is_invocable_v<Context>)
{
Context::operator()();
}
else
{
// Default event loop
while (thread_ctrl::state() != thread_state::aborting)
{
thread_ctrl::wait();
}
}
}
else
{
// Construct the result using placement new (copy elision should happen)
new (result::get()) typename result::type(Context::operator()());
new (result::get()) decltype(auto)(Context::operator()());
}
return thread::finalize(thread_state::finished);

View File

@ -377,8 +377,11 @@ int main(int argc, char** argv)
}
#endif
// Initialize TSC freq (in case it isn't)
static_cast<void>(utils::get_tsc_freq());
// Initialize thread pool finalizer (on first use)
named_thread("", []{})();
static_cast<void>(named_thread("", [](int) {}));
static std::unique_ptr<logs::listener> log_file;
{