Webkit Timer study notes

本文深入探讨了定时器管理系统的内部工作原理,包括基础类、模板类、线程管理器和平台适配器等关键组件及其作用。详细阐述了如何通过回调函数实现定时任务的触发与管理,并解释了定时器在不同平台上的实现方式。文章最后揭示了定时器客户端如何与系统时钟交互以设置和停止定时任务,以及如何通过Java接口调用定时任务的回调函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值