refactor the implementation of timer in Linux
This commit is contained in:
parent
5acbbf548e
commit
07871b1f36
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user