kvm线程-003

本文介绍kvm中关于线程操作中的下列函数:

registerAlarm
checkTimerQueue
removePendingAlarm

这三个函数,涉及到了一个队列–TimerQueue.其定义如下:

THREAD TimerQueue;
typedef struct threadQueue*         THREAD;

而threadQueue(说是queue,其数据结构上是用链表实现的队列)就是kvm内部的线程,这点在kvm线程-001 中有介绍.

registerAlarm

其中的代码如下:

void
registerAlarm(THREAD thread, long64 delta, void (*wakeupCall)(THREAD))
{
#if NEED_LONG_ALIGNMENT
    Java8 tdub;
#endif

    THREAD q, prev_q;
    ulong64 wakeupTime;

    // 1. 在队列中查找,如果有的话,则直接return
    q = TimerQueue;
    while (q != NULL) {
        if (q == thread)
            return; /* already on the queue so leave  */
        q = q->nextAlarmThread;
    }
    /* 2. 计算wakeupTime ,并保存在thread 中 */
    wakeupTime = CurrentTime_md();
    ll_inc(wakeupTime, delta);      /* wakeUp += delta */

    SET_ULONG(thread->wakeupTime, wakeupTime);

#if INCLUDEDEBUGCODE
    if (tracethreading) {
        TraceThread(thread, "Adding to timer queue");
    }
#endif

    /* 3. 保存回调 */
    thread->wakeupCall = wakeupCall;

    /* 4. 插入队列*/
    q = TimerQueue;
    prev_q = NULL;
    while (q != NULL) {
        ulong64 qtime = GET_ULONG(q->wakeupTime);
        if (ll_compare_ge(qtime, wakeupTime)) { // !ll_compare_lt(qtime,wakeupTime) = ! qtime < wakeupTime 也就是qtime >=wakeupTime
            break;
        }
        prev_q = q;
        q = q->nextAlarmThread;
    }
    if (prev_q != NULL) {  // 插入
        /* This is the first item in the queue. */
        prev_q->nextAlarmThread = thread;
        thread->nextAlarmThread = q;
    } else {// 如果是等于null,则意味着目前没有TimerQueue
        thread->nextAlarmThread = TimerQueue;
        TimerQueue = thread;
    }
}

注意一点: TimerQueue中的元素是按照唤醒时间(wakeupTime)的先后顺序排列的.其head是最先需要唤醒的.

该方法的调用点为:

  1. java.lang.thread.sleep方法.在Thread中,sleep方法为本地方法,定义如下:

     public static native void sleep(long millis) throws InterruptedException;
    

    而在kvm中,最终对应的方法为:

    void Java_java_lang_Thread_sleep(void)
     {
         long64  period;
         THREAD thisThread = CurrentThread; // 获得执行线程
     
         popLong(period); // 获得要等待的时间
         if (ll_zero_lt(period)) { // 如果period < 0 ,则抛出IllegalArgumentException
             raiseException(IllegalArgumentException);
         } else  if (thisThread->isPendingInterrupt) { // 如果线程正在Interrupt,则调用handlePendingInterrupt
             handlePendingInterrupt();
         } else if (ll_zero_gt(period)) { // 如果>=0。则将线程挂起,同时加入timer队列,等时间到时,则调用resumeThread方法进行恢复
             /* Suspend the current thread before we add the timer */
             suspendThread();
     
             /* Now add the timer (this is the safe way) */
             registerAlarm(thisThread, period, resumeThread);
         } else if (ll_zero_eq(period)) {
             signalTimeToReschedule();
         }
        }
    

    在该方法中的其他方法handlePendingInterrupt, signalTimeToReschedule会在后续文章中介绍.

  2. 异步i/o.代码如下:

    #ifndef GENERIC_IO_WAIT_TIME
     #define GENERIC_IO_WAIT_TIME 0
     #endif
    
     void Java_com_sun_cldc_io_Waiter_waitForIO(void)
     {
     #if GENERIC_IO_WAIT_TIME > 0
         /* Suspend the current thread for GENERIC_IO_WAIT_TIME milliseconds */
         THREAD thisThread = CurrentThread;
         suspendThread();
         // 加入到timer队列中,进行恢复
         registerAlarm(thisThread, (long64)GENERIC_IO_WAIT_TIME, resumeThread);
     #else
         /* Try to switch to another thread 切换为其他线程*/
         signalTimeToReschedule();
     #endif
     }
    
  3. 在monitorWait中调用.代码如下:

    // 如果是有限等待的话,则加入到等待队列中以唤醒
    if (ll_zero_gt(delta)) {
        registerAlarm(CurrentThread, delta, monitorWaitAlarm);
    }
    

    关于monitorWait,会在后续文章中介绍.

checkTimerQueue

此处的代码如下:

oid
checkTimerQueue(ulong64 *nextTimerDelta)
{
#if NEED_LONG_ALIGNMENT
    Java8 tdub;
#endif
    ulong64 now = CurrentTime_md();
    // 1. 如果代码存在的话
    if (TimerQueue != NULL) {
        do {
            ulong64 firstTime = GET_ULONG(TimerQueue->wakeupTime); // 获得队首的唤醒时间
            if (ll_compare_le(firstTime, now)) {// 如果小于当前时间的话,则需要唤醒
                
                THREAD thread = TimerQueue;
                void (*wakeupCall)() = thread->wakeupCall;

#if INCLUDEDEBUGCODE
                if (tracethreading) {
                    TraceThread(thread, "Removing from timer queue");
                }
#endif

                TimerQueue = thread->nextAlarmThread;
                thread->nextAlarmThread = NULL;
                thread->wakeupCall = NULL; /* signal that not on queue */
                wakeupCall(thread);
            } else {
                break;
            }
        } while (TimerQueue != NULL);
    }

    /* 2. 计算下次唤醒的时间 */
    if (TimerQueue == NULL) { // 如果TimerQueue = null,则将nextTimerDelta = 0 
        ll_setZero(*nextTimerDelta);
    } else {
        ulong64 nextwakeup = GET_ULONG(TimerQueue->wakeupTime);
        if (ll_compare_le(nextwakeup, now)) { // 如果nextwakeup <= now,则设置nextTimerDelta 为0
            ll_setZero(*nextTimerDelta);
        } else {
                ll_dec(nextwakeup, now);
            *nextTimerDelta = nextwakeup; // 否则,就设置nextTimerDelta为nextwakeup 和now的差值
        }
    }
}

此方法只在reschedule()中调用,如下:

#define reschedule()                                                \
     do  {                                                          \
        ulong64 wakeupDelta;                                        \
        if (!areAliveThreads()) {                                   \
            return;   /* end of program */                          \
        }                                                           \
        checkTimerQueue(&wakeupDelta);                              \
        InterpreterHandleEvent(wakeupDelta);                        \
        __ProcessDebugCmds(0);                                      \
    } while (!SwitchThread());

关于这点,在后续文章中介绍

removePendingAlarm

此处的代码为:

static void
removePendingAlarm(THREAD thread) {
    THREAD q, prev_q;

#if INCLUDEDEBUGCODE
    if (tracethreading) {
        TraceThread(thread, "Purging from timer queue");
    }
#endif

    for (q = TimerQueue, prev_q = NULL;
               q != NULL; prev_q = q, q = q->nextAlarmThread) {
        if (q == thread) {// 从队列中删除
            if (prev_q) {
                prev_q->nextAlarmThread = q->nextAlarmThread;
            } else {
                TimerQueue = q->nextAlarmThread;
            }
            q->nextAlarmThread = NULL;
            q->wakeupCall = NULL; 
            break;
        }
    }
}

此方法是在线程终止,线程中断时调用.关于如何调用,同样是在后续文章中介绍.

上一篇:003-结构型-06-组合模式(Composite)


下一篇:C++复习笔记之从0到1 (003)