Timer Class and Timer start
1.TimerBase
Base class for timer . has function "start", "stop" and so forth.
2.Timer
Timer is subclass of TimerBase, it's also Class template.
" TimerFiredClass" is it's template parameter, has a member
TimerFiredClass* m_object
It also has a fire function defined as below
virtual void fired() { (m_object->*m_function)(this); }
that means all the "TimerFiredClass" must has a mumeber ship m_function.
void TimerBase:start(double nextFireInterval, double repeatInterval){
threadGlobalData().threadTimer().updateSharedTimer();
}
start a new timer with "nextFireInterval" interval.3.ThreadTimers
the class who really manage the timer process.
a.it has a class a member of TimerBase vector
and a shareTimer member.
Vector<TimerBase*> m_timerHeap;
SharedTimer* m_sharedTimer;
m_timerHeap is the object to hold all timer
m_shareTimer is the intermediary class to handle a Timer(TimerBase)
b.sharedTimerFired
void ThreadTimers::sharedTimerFired()
{
// Redirect to non-static method.
threadGlobalData().threadTimers().sharedTimerFiredInternal();
}
void ThreadTimers::sharedTimerFiredInternal()
{
// Do a re-entrancy check.
if (m_firingTimers)
return;
m_firingTimers = true;
double fireTime = currentTime();
double timeToQuit = fireTime + maxDurationOfFiringTimers;
while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) {
TimerBase* timer = m_timerHeap.first();
timer->m_nextFireTime = 0;
timer->heapDeleteMin();
double interval = timer->repeatInterval();
timer->setNextFireTime(interval ? fireTime + interval : 0);
//LOGY("lyftest ThreadTimers sharedTimerFiredInternal name=%s begin",timer->mTimerName);
// Once the timer has been fired, it may be deleted, so do nothing else with it after this point.
timer->fired();
//LOGY("lyftest ThreadTimers sharedTimerFiredInternal name=%s end",timer->mTimerName);
// Catch the case where the timer asked timers to fire in a nested event loop, or we are over time limit.
if (!m_firingTimers || timeToQuit < currentTime())
break;
}
m_firingTimers = false;
updateSharedTimer();
}
first call the overtime's fire(), and then call "updateSharedTimer" to set another timer.
c.updateSharedTimer()
void ThreadTimers::updateSharedTimer()
{
if (!m_sharedTimer)
return;
if (m_firingTimers || m_timerHeap.isEmpty())
m_sharedTimer->stop();
else
m_sharedTimer->setFireTime(m_timerHeap.first()->m_nextFireTime);
}
use the intermediary class "ShareTimer" to set another timer.
4.SharedTimer
it's a intermediary class for porting different platform.
in SharedTimer.h
class MainThreadSharedTimer : public SharedTimer {
public:
virtual void setFiredFunction(void (*function)())
{
setSharedTimerFiredFunction(function);
}
virtual void setFireTime(double fireTime)
{
setSharedTimerFireTime(fireTime);
}
virtual void stop()
{
stopSharedTimer();
}
};
so we will have cpp files such as:
"SharedTimerAndroid.cpp","SharedTimerWin.cpp" and so on.
in it's implementation , it will call the timerclient's function
void setSharedTimerFiredFunction(void (*f)())
{
if (JavaSharedClient::GetTimerClient())
JavaSharedClient::GetTimerClient()->setSharedTimerCallback(f);
}
void setSharedTimerFireTime(double fireTime)
{
long long timeInMs = static_cast<long long>((fireTime - WTF::currentTime()) * 1000);
LOGV("setSharedTimerFireTime: in %ld millisec", timeInMs);
if (JavaSharedClient::GetTimerClient())
JavaSharedClient::GetTimerClient()->setSharedTimer(timeInMs);
}
void stopSharedTimer()
{
if (JavaSharedClient::GetTimerClient())
JavaSharedClient::GetTimerClient()->stopSharedTimer();
}
5.JavaSharedClient
a jni class which will return the client of JNI.
class JavaSharedClient
{
public:
static TimerClient* GetTimerClient();
static CookieClient* GetCookieClient();
static PluginClient* GetPluginClient();
static KeyGeneratorClient* GetKeyGeneratorClient();
static FileSystemClient* GetFileSystemClient();
........
static TimerClient* gTimerClient;
static CookieClient* gCookieClient;
static PluginClient* gPluginClient;
static KeyGeneratorClient* gKeyGeneratorClient;
static FileSystemClient* gFileSystemClient;
for the timer, it will return the TimerClient.
6.TimerClient
class TimerClient
{
public:
virtual ~TimerClient() {}
virtual void setSharedTimerCallback(void(*f)()) = 0;
virtual void setSharedTimer(long long timemillis) = 0;
virtual void stopSharedTimer() = 0;
virtual void signalServiceFuncPtrQueue() = 0;
};
the class who use system clock to set the timer.
7.JavaBridge.cpp
Android's TimerClient .
class JavaBridge : public TimerClient,....{
virtual void setSharedTimer(long long timemillis);
virtual void stopSharedTimer();
virtual void setSharedTimerCallback(void (*f)());
........
}
void
JavaBridge::setSharedTimer(long long timemillis)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis);
}
void
JavaBridge::stopSharedTimer()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mStopSharedTimer);
}
mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
so the implementation of clock timer is in java code.
for JavaBridge, its java code is JWebCoreJavaBridge.java
so setSharedTimer will call
JWebCoreJavaBridge's
setSharedTimer
and stopSharedTimer will call
JWebCoreJavaBridge's stopSharedTimer
Android's TimerClient
a.define a subclass of TimerClient
class JavaBridge : public TimerClient{
......
}
b.define a callback
static void (*sSharedTimerFiredCallback)();
c. implement the setSharedTimerCallbackand value the func pointer
JavaBridge::setSharedTimerCallback(void (*f)())
{
LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
"Shared timer callback may already be set or null!");
sSharedTimerFiredCallback = f;
}
d. define a SharedTimerFired function (this function should be called when timer out.)
void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
{
if (sSharedTimerFiredCallback)
{
SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired");
SharedTimerFiredCallback();
}
}
that means we should call the call back when the timer is out.
5. implement the setSharedTimer to add a real timer.
void
JavaBridge::setSharedTimer(long long timemillis)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis);
}
Timer out call trace
a.JWebCoreJavaBridge.sharedTimerFired
b.JavaBridge::SharedTimerFire
c. sSharedTimerFiredCallback(the function pointer)
call back func definition
a. ThreadTimers.setSharedTimer()
void ThreadTimers::setSharedTimer(SharedTimer* sharedTimer)
{
if (m_sharedTimer) {
m_sharedTimer->setFiredFunction(0);
m_sharedTimer->stop();
}
m_sharedTimer = sharedTimer;
if (sharedTimer) {
m_sharedTimer->setFiredFunction(ThreadTimers::sharedTimerFired);
updateSharedTimer();
}
}
// we can see here f is ThreadTimers::sharedTimerFired, finally shredTimerFiredInternal()
void ThreadTimers::sharedTimerFired()
{
// Redirect to non-static method.
threadGlobalData().threadTimers().sharedTimerFiredInternal();
}
void ThreadTimers::sharedTimerFiredInternal()
{
// Do a re-entrancy check.
if (m_firingTimers)
return;
m_firingTimers = true;
double fireTime = currentTime();
double timeToQuit = fireTime + maxDurationOfFiringTimers;
while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) {
TimerBase* timer = m_timerHeap.first();
timer->m_nextFireTime = 0;
timer->heapDeleteMin();
double interval = timer->repeatInterval();
timer->setNextFireTime(interval ? fireTime + interval : 0);
//LOGY("lyftest ThreadTimers sharedTimerFiredInternal name=%s begin",timer->mTimerName);
// Once the timer has been fired, it may be deleted, so do nothing else with it after this point.
timer->fired();
//LOGY("lyftest ThreadTimers sharedTimerFiredInternal name=%s end",timer->mTimerName);
// Catch the case where the timer asked timers to fire in a nested event loop, or we are over time limit.
if (!m_firingTimers || timeToQuit < currentTime())
break;
}
m_firingTimers = false;
updateSharedTimer();
}
b.SharedTimer.setFiredFunction
virtual void setFiredFunction(void (*function)())
{
setSharedTimerFiredFunction(function);
}
SharedTimer.setSharedTimerFiredFunction
c.ShareTimerAndroid.setSharedTimerFiredFunction
void setSharedTimerFiredFunction(void (*f)())
{
if (JavaSharedClient::GetTimerClient())
JavaSharedClient::GetTimerClient()->setSharedTimerCallback(f);
}
d.TimerClient.setSharedTimerCallback
that's JavaBridge.setSharedTimerCallback
two ways to call a timer's out function
a. you call the TimerClient's "sharedTimerFired" yourself.
b. Construct a new timer and add it to the ThreadTimer's queue with time's "heapInsert",
when it's time, ThreadTimer found your timer out of time, it will call your "callback function"
when is timerThread created?
a.ThreadGlobalData::ThreadGlobalData()
ThreadGlobalData::ThreadGlobalData()
: m_eventNames(new EventNames)
, m_threadTimers(new ThreadTimers)
b.MainThreadSharedTimer* mainThreadSharedTimer();
ThreadTimers::ThreadTimers()
: m_sharedTimer(0)
, m_firingTimers(false)
{
if (isMainThread())
setSharedTimer(mainThreadSharedTimer());
}
c. create a new mainTrheadSharedTimer
static MainThreadSharedTimer* mainThreadSharedTimer()
{
static MainThreadSharedTimer* timer = new MainThreadSharedTimer;
return timer;
}
d. set to ThreadTimer
void ThreadTimers::setSharedTimer(SharedTimer* sharedTimer)
{
if (m_sharedTimer) {
m_sharedTimer->setFiredFunction(0);
m_sharedTimer->stop();
}
m_sharedTimer = sharedTimer;
if (sharedTimer) {
m_sharedTimer->setFiredFunction(ThreadTimers::sharedTimerFired);
updateSharedTimer();
}
}
e. it mustn't be empty() , however i havn't check the detail
void ThreadTimers::updateSharedTimer()
{
if (!m_sharedTimer)
return;
if (m_firingTimers || m_timerHeap.isEmpty())
m_sharedTimer->stop();
else
m_sharedTimer->setFireTime(m_timerHeap.first()->m_nextFireTime);
}
....
final TimerClient's setSharedTimer()
why is it so complex, i think it's main purpose is manager a timer manager that can manage a lot of timer.
And also a lot client can use it , but they even don't know each other's existence.