refactor the implementation of timer in Linux

This commit is contained in:
Jinhao 2019-07-14 13:40:17 +08:00
parent 5acbbf548e
commit 07871b1f36
5 changed files with 91 additions and 74 deletions

View File

@ -22,14 +22,16 @@
namespace nana namespace nana
{ {
/// Can repeatedly call a piece of code.
class timer;
struct arg_elapse struct arg_elapse
: public event_arg : public event_arg
{ {
long long id; //timer identifier; timer* sender; //indicates which timer emitted this notification
}; };
/// Can repeatedly call a piece of code.
class timer class timer
{ {
struct implement; struct implement;

View File

@ -210,15 +210,15 @@ namespace detail
class timer_runner class timer_runner
{ {
typedef void (*timer_proc_t)(std::size_t id); using handler_type = void(*)(const timer_core*);
struct timer_tag struct timer_tag
{ {
std::size_t id; const timer_core* handle;
thread_t tid; thread_t thread_id;
std::size_t interval; std::size_t interval;
std::size_t timestamp; std::size_t timestamp;
timer_proc_t proc; handler_type handler;
}; };
//timer_group //timer_group
@ -234,32 +234,32 @@ namespace detail
struct timer_group struct timer_group
{ {
bool proc_entered{false}; //This flag indicates whether the timers are going to do event. bool proc_entered{false}; //This flag indicates whether the timers are going to do event.
std::set<std::size_t> timers; std::set<const timer_core*> timers;
std::vector<std::size_t> delay_deleted; std::vector<const timer_core*> delay_deleted;
}; };
public: public:
timer_runner() timer_runner()
: is_proc_handling_(false) : is_proc_handling_(false)
{} {}
void set(std::size_t id, std::size_t interval, timer_proc_t proc) void set(const timer_core* handle, std::size_t interval, handler_type handler)
{ {
auto i = holder_.find(id); auto i = holder_.find(handle);
if(i != holder_.end()) if(i != holder_.end())
{ {
i->second.interval = interval; i->second.interval = interval;
i->second.proc = proc; i->second.handler = handler;
return; return;
} }
auto tid = nana::system::this_thread_id(); auto tid = nana::system::this_thread_id();
threadmap_[tid].timers.insert(id); threadmap_[tid].timers.insert(handle);
timer_tag & tag = holder_[id]; timer_tag & tag = holder_[handle];
tag.id = id; tag.handle = handle;
tag.tid = tid; tag.thread_id = tid;
tag.interval = interval; tag.interval = interval;
tag.timestamp = 0; tag.timestamp = 0;
tag.proc = proc; tag.handler = handler;
} }
bool is_proc_handling() const bool is_proc_handling() const
@ -267,12 +267,12 @@ namespace detail
return is_proc_handling_; return is_proc_handling_;
} }
void kill(std::size_t id) bool kill(const timer_core* handle)
{ {
auto i = holder_.find(id); auto i = holder_.find(handle);
if(i != holder_.end()) if(i != holder_.end())
{ {
auto tid = i->second.tid; auto tid = i->second.thread_id;
auto ig = threadmap_.find(tid); auto ig = threadmap_.find(tid);
if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_ if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_
@ -280,20 +280,16 @@ namespace detail
auto & group = ig->second; auto & group = ig->second;
if(!group.proc_entered) if(!group.proc_entered)
{ {
group.timers.erase(id); group.timers.erase(handle);
if(group.timers.empty()) if(group.timers.empty())
threadmap_.erase(ig); threadmap_.erase(ig);
} }
else else
group.delay_deleted.push_back(id); group.delay_deleted.push_back(handle);
} }
holder_.erase(i); holder_.erase(i);
} }
} return holder_.empty();
bool empty() const
{
return (holder_.empty());
} }
void timer_proc(thread_t tid) void timer_proc(thread_t tid)
@ -315,7 +311,7 @@ namespace detail
tag.timestamp = ticks; tag.timestamp = ticks;
try try
{ {
tag.proc(tag.id); tag.handler(tag.handle);
}catch(...){} //nothrow }catch(...){} //nothrow
} }
} }
@ -331,7 +327,7 @@ namespace detail
private: private:
bool is_proc_handling_; bool is_proc_handling_;
std::map<thread_t, timer_group> threadmap_; std::map<thread_t, timer_group> threadmap_;
std::map<std::size_t, timer_tag> holder_; std::map<const timer_core*, timer_tag> holder_;
}; };
drawable_impl_type::drawable_impl_type() drawable_impl_type::drawable_impl_type()
@ -439,7 +435,7 @@ namespace detail
} }
platform_spec::timer_runner_tag::timer_runner_tag() platform_spec::timer_runner_tag::timer_runner_tag()
: runner(0), delete_declared(false) : runner(nullptr), delete_declared(false)
{} {}
platform_spec::platform_spec() platform_spec::platform_spec()
@ -981,32 +977,34 @@ namespace detail
return r; return r;
} }
void platform_spec::set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t)) void platform_spec::set_timer(const timer_core* handle, std::size_t interval, void (*timer_proc)(const timer_core*))
{ {
std::lock_guard<decltype(timer_.mutex)> lock(timer_.mutex); std::lock_guard<decltype(timer_.mutex)> lock(timer_.mutex);
if(0 == timer_.runner) if(!timer_.runner)
timer_.runner = new timer_runner; timer_.runner = new timer_runner;
timer_.runner->set(id, interval, timer_proc);
timer_.runner->set(handle, interval, timer_proc);
timer_.delete_declared = false; timer_.delete_declared = false;
} }
void platform_spec::kill_timer(std::size_t id) void platform_spec::kill_timer(const timer_core* handle)
{ {
if(timer_.runner == 0) return;
std::lock_guard<decltype(timer_.mutex)> lock(timer_.mutex); std::lock_guard<decltype(timer_.mutex)> lock(timer_.mutex);
timer_.runner->kill(id); if(timer_.runner)
if(timer_.runner->empty()) {
// Test if there is not a timer after killing
if(timer_.runner->kill(handle))
{ {
if(timer_.runner->is_proc_handling() == false) if(timer_.runner->is_proc_handling() == false)
{ {
delete timer_.runner; delete timer_.runner;
timer_.runner = 0; timer_.runner = nullptr;
} }
else else
timer_.delete_declared = true; timer_.delete_declared = true;
} }
} }
}
void platform_spec::timer_proc(thread_t tid) void platform_spec::timer_proc(thread_t tid)
{ {
@ -1017,7 +1015,7 @@ namespace detail
if(timer_.delete_declared) if(timer_.delete_declared)
{ {
delete timer_.runner; delete timer_.runner;
timer_.runner = 0; timer_.runner = nullptr;
timer_.delete_declared = false; timer_.delete_declared = false;
} }
} }

View File

@ -146,6 +146,13 @@ namespace detail
//A forward declaration of caret data //A forward declaration of caret data
struct caret_rep; struct caret_rep;
/// class timer_core
/**
* Platform-spec only provides the declaration for intrducing a handle type, the definition
* of timer_core is given by gui/timer.cpp
*/
class timer_core;
class timer_runner; class timer_runner;
class platform_scope_guard class platform_scope_guard
@ -226,8 +233,8 @@ namespace detail
//when native_interface::show a window that is registered as a grab //when native_interface::show a window that is registered as a grab
//window, the native_interface grabs the window. //window, the native_interface grabs the window.
Window grab(Window); Window grab(Window);
void set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t id)); void set_timer(const timer_core*, std::size_t interval, void (*timer_proc)(const timer_core* tm));
void kill_timer(std::size_t id); void kill_timer(const timer_core*);
void timer_proc(thread_t tid); void timer_proc(thread_t tid);
//Message dispatcher //Message dispatcher

View File

@ -14,6 +14,7 @@
#include <nana/gui/compact.hpp> #include <nana/gui/compact.hpp>
#include <nana/gui/msgbox.hpp> #include <nana/gui/msgbox.hpp>
#include <nana/gui/drawing.hpp>
#include <nana/gui/widgets/form.hpp> #include <nana/gui/widgets/form.hpp>
#include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/button.hpp> #include <nana/gui/widgets/button.hpp>

View File

@ -28,22 +28,26 @@
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#include <windows.h> #include <windows.h>
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)
#include "../detail/platform_spec_selector.hpp" #include "../detail/posix/platform_spec.hpp"
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#endif #endif
namespace nana namespace nana
{ {
namespace detail
{
class timer_core; class timer_core;
}
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
typedef UINT_PTR timer_identifier; typedef UINT_PTR timer_identifier;
#else #else
typedef timer_core* timer_identifier; typedef const detail::timer_core* timer_identifier;
#endif #endif
class timer_driver class timer_driver
{ {
friend class timer_core; friend class detail::timer_core;
timer_driver() = default; timer_driver() = default;
public: public:
@ -54,7 +58,7 @@ namespace nana
} }
template<typename Factory> template<typename Factory>
timer_core* create(unsigned ms, Factory && factory) detail::timer_core* create(unsigned ms, Factory && factory)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc); auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc);
@ -66,7 +70,7 @@ namespace nana
#else #else
auto p = factory(); auto p = factory();
auto tmid = p; auto tmid = p;
::nana::detail::platform_spec::instance().set_timer(reinterpret_cast<std::size_t>(tmid), ms, &timer_driver::_m_timer_proc); ::nana::detail::platform_spec::instance().set_timer(tmid, ms, &timer_driver::_m_timer_proc);
#endif #endif
::nana::internal_scope_guard lock; ::nana::internal_scope_guard lock;
timer_table_[tmid].reset(p); timer_table_[tmid].reset(p);
@ -78,17 +82,17 @@ namespace nana
return nullptr; return nullptr;
} }
void destroy(timer_identifier tid) void destroy(timer_identifier handle)
{ {
::nana::internal_scope_guard lock; ::nana::internal_scope_guard lock;
auto i = timer_table_.find(tid); auto i = timer_table_.find(handle);
if (i != timer_table_.end()) if (i != timer_table_.end())
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::KillTimer(nullptr, tid); ::KillTimer(nullptr, handle);
#else #else
::nana::detail::platform_spec::instance().kill_timer(reinterpret_cast<std::size_t>(tid)); ::nana::detail::platform_spec::instance().kill_timer(handle);
#endif #endif
timer_table_.erase(i); timer_table_.erase(i);
} }
@ -97,22 +101,26 @@ namespace nana
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime); static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime);
#else #else
static void _m_timer_proc(std::size_t id); static void _m_timer_proc(timer_identifier id);
#endif #endif
private: private:
std::map<timer_identifier, std::unique_ptr<timer_core>> timer_table_; std::map<timer_identifier, std::unique_ptr<detail::timer_core>> timer_table_;
}; };
class timer_core class detail::timer_core
{ {
public: public:
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
timer_core(timer_identifier tmid, basic_event<arg_elapse>& evt_elapse) timer_core(timer* sender, timer_identifier tmid, basic_event<arg_elapse>& evt_elapse):
: timer_(tmid), evt_elapse_(evt_elapse) sender_(sender),
timer_(tmid),
evt_elapse_(evt_elapse)
{} {}
#else #else
timer_core(basic_event<arg_elapse>& evt_elapse) timer_core(timer* sender, basic_event<arg_elapse>& evt_elapse):
: timer_(this), evt_elapse_(evt_elapse) sender_(sender),
timer_(this),
evt_elapse_(evt_elapse)
{} {}
#endif #endif
@ -126,43 +134,44 @@ namespace nana
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc); ::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc);
#else #else
::nana::detail::platform_spec::instance().set_timer(reinterpret_cast<std::size_t>(timer_), ms, &timer_driver::_m_timer_proc); ::nana::detail::platform_spec::instance().set_timer(timer_, ms, &timer_driver::_m_timer_proc);
#endif #endif
} }
void emit(const arg_elapse& arg) void emit()
{ {
arg_elapse arg;
arg.sender = sender_;
evt_elapse_.emit(arg, nullptr); evt_elapse_.emit(arg, nullptr);
} }
private: private:
timer * const sender_;
const timer_identifier timer_; const timer_identifier timer_;
nana::basic_event<arg_elapse> & evt_elapse_; nana::basic_event<arg_elapse> & evt_elapse_;
}; //end class timer_core }; //end class timer_core
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR id, DWORD /*dwTime*/) void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR handle, DWORD /*dwTime*/)
#else #else
void timer_driver::_m_timer_proc(std::size_t id) void timer_driver::_m_timer_proc(timer_identifier handle)
#endif #endif
{ {
auto & time_tbl = instance().timer_table_; auto & time_tbl = instance().timer_table_;
::nana::internal_scope_guard lock; ::nana::internal_scope_guard lock;
auto i = time_tbl.find(id); auto i = time_tbl.find(handle);
if (i == time_tbl.end()) if (i == time_tbl.end())
return; return;
arg_elapse arg; i->second->emit();
arg.id = id;
i->second->emit(arg);
} }
struct timer::implement struct timer::implement
{ {
unsigned interval = 1000; //Defaultly 1 second. unsigned interval{ 1000 }; //1 second in default
timer_core * tm_core = nullptr; detail::timer_core * tm_core{ nullptr };
}; };
//class timer //class timer
@ -196,12 +205,12 @@ namespace nana
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id) impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id)
{ {
return new timer_core(id, elapse_); return new detail::timer_core(this, id, elapse_);
}); });
#else #else
impl_->tm_core = timer_driver::instance().create(impl_->interval, [this] impl_->tm_core = timer_driver::instance().create(impl_->interval, [this]
{ {
return new timer_core(elapse_); return new detail::timer_core(this, elapse_);
}); });
#endif #endif
} }