欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
hrtimer clockevent Timekeeping
hrtimer + clockevent + Timekeeping
    kernel-2.6.22中的arm arch加入了對dynticks, clocksource/event支持. imx31的BSP在clock這里有一些改動(dòng). 找了些kernel clock及timer子系統近來(lái)的變化, 總結一下.
    一般來(lái)說(shuō)Soft-Timer (timer wheel / hrtimer) 都是由Hardware-Timer(時(shí)鐘中斷之類(lèi))以及相關(guān)的clock source(e.g GPT in Soc)驅動(dòng), 所以我打算先從clock這層開(kāi)始介紹, 接著(zhù)是soft-timer, kernel timekeeping, 最后來(lái)看一些應用.

Clock Source

clock source定義了一個(gè)clock device的基本屬性及行為, 這些clock device一般都有計數, 定時(shí), 產(chǎn)生中斷能力, 比如GPT. 結構定義如下:

struct clocksource {
    char *name;
    struct list_head list;
    int rating;
    cycle_t (*read)(void);
    cycle_t mask;
    u32 mult; /* cycle -> xtime interval, maybe two clock cycle trigger one interrupt (one xtime interval) */
    u32 shift;
    unsigned long flags;
    cycle_t (*vread)(void);
    void (*resume)(void);

    /* timekeeping specific data, ignore */
    cycle_t cycle_interval; /* just the rate of GPT count per OS HZ */
    u64    xtime_interval; /* xtime_interval = cycle_interval * mult. */
    cycle_t cycle_last ____cacheline_aligned_in_smp; /* last cycle in rate count */
    u64 xtime_nsec; /* cycle count, remain from xtime.tv_nsec
                     * now nsec rate count offset = xtime_nsec +                              * xtime.tv_nsec << shift */

    s64 error;
};


最重要的成員是read(), cycle_last和cycle_interval. 分別定義了讀取clock device count 寄存器當前計數值接口, 保存上一次周期計數值和每個(gè)tick周期間隔值. 這個(gè)結構內的值, 無(wú)論是cycle_t, 還是u64類(lèi)型(實(shí)際cycle_t就是u64)都是計數值(cycle), 而不是nsec, sec和jiffies. read()是整個(gè)kernel讀取精確的單調時(shí)間計數的接口, kernel會(huì )用它來(lái)計算其他時(shí)間, 比如:jiffies, xtime.
clocksource的引入, 解決了之前kernel各個(gè)arch都有自己的clock device的管理方式, 基本都隱藏在MSL層, kernel core 及driver很難訪(fǎng)問(wèn)的問(wèn)題. 它導出了以下接口:
1) clocksource_register() 注冊clocksource
2) clocksource_get_next() 獲取當前clocksource設備
3) clocksource_read() 讀取clock, 實(shí)際跑到clocksource->read()
當driver處理的時(shí)間精度比較高的時(shí), 可以通過(guò)上面的接口, 直接拿clock device來(lái)讀.
當然目前ticker時(shí)鐘中斷源也會(huì )以clocksource的形式存在.

Clock Event

Clock event的主要作用是分發(fā)clock事件及設置下一次觸發(fā)條件. 在沒(méi)有clock event之前, 時(shí)鐘中斷都是周期性地產(chǎn)生, 也就是熟知的jiffies和HZ.
Clock Event device主要的結構:

struct clock_event_device {
    const char        *name;
    unsigned int        features;
    unsigned long        max_delta_ns;
    unsigned long        min_delta_ns;
    unsigned long        mult;
    int            shift;
    int            rating;
    int            irq;
    cpumask_t        cpumask;
    int            (*set_next_event)(unsigned long evt,
                         struct clock_event_device *);
    void            (*set_mode)(enum clock_event_mode mode,
                     struct clock_event_device *);
    void            (*event_handler)(struct clock_event_device *);
    void            (*broadcast)(cpumask_t mask);
    struct list_head    list;
    enum clock_event_mode    mode;
    ktime_t            next_event;
};

最重要的是set_next_event(), event_handler(). 前者是設置下一個(gè)clock事件的觸發(fā)條件, 一般就是往clock device里重設一下定時(shí)器. 后者是event handler, 事件處理函數. 該處理函數會(huì )在時(shí)鐘中斷ISR里被調用. 如果這個(gè)clock用來(lái)做為ticker時(shí)鐘, 那么handler的執行和之前kernel的時(shí)鐘中斷ISR基本相同, 類(lèi)似timer_tick(). 事件處理函數可以在運行時(shí)動(dòng)態(tài)替換, 這就給kernel一個(gè)改變整個(gè)時(shí)鐘中斷處理方式的機會(huì ), 也就給highres tick及dynamic tick一個(gè)動(dòng)態(tài)掛載的機會(huì ). 目前kernel內部有periodic/highres/dynamic tick三種時(shí)鐘中斷處理方式. 后面會(huì )介紹.

hrtimer & timer wheel

首先說(shuō)一下timer wheel. 它就是kernel一直采用的基于jiffies的timer機制, 接口包括init_timer(), mod_timer(), del_timer()等, 很熟悉把.
hrtimer 的出現, 并沒(méi)有拋棄老的timer wheel機制(也不太可能拋棄:)). hrtimer做為kernel里的timer定時(shí)器, 而timer wheel則主要用來(lái)做timeout定時(shí)器. 分工比較明確. hrtimers采用紅黑樹(shù)來(lái)組織timers, 而timer wheel采用鏈表和桶.
hrtimer精度由原來(lái)的timer wheel的jiffies提高到nanosecond. 主要用于向應用層提供nanosleep, posix-timers和itimer接口, 當然驅動(dòng)和其他子系統也會(huì )需要high resolution的timer.
kernel 里原先每秒周期性地產(chǎn)生HZ個(gè)ticker(中斷), 被在下一個(gè)過(guò)期的hrtimer的時(shí)間點(diǎn)上產(chǎn)生中斷代替. 也就是說(shuō)時(shí)鐘中斷不再是周期性的, 而是由timer來(lái)驅動(dòng)(靠clockevent的set_next_event接口設置下一個(gè)事件中斷), 只要沒(méi)有hrtimer加載, 就沒(méi)有中斷. 但是為了保證系統時(shí)間(進(jìn)程時(shí)間統計, jiffies的維護)更新, 每個(gè)tick_period(NSEC_PER_SEC/HZ, 再次強調hrtimer精度是nsec)都會(huì )有一個(gè)叫做tick_sched_timer的hrtimer加載.
接下來(lái)對比一下, hrtimer引入之前及之后, kernel里時(shí)鐘中斷的處理的不同. (這里都是基于arm arch的source去分析)

1)no hrtimer

kernel 起來(lái), setup_arch()之后的time_init()會(huì )去初始化相應machine結構下的timer. 初始化timer函數都在各個(gè)machine的體系結構代碼中, 初始化完硬件時(shí)鐘, 注冊中斷服務(wù)函數, 使能時(shí)鐘中斷. 中斷服務(wù)程序會(huì )清中斷, 調用timer_tick(), 它執行:
1. profile_tick(); /* kernel profile, 不是很了解 */
2. do_timer(1); /* 更新jiffies */
3. update_process_times(); /* 計算進(jìn)程耗時(shí), 喚起TIMER_SOFTIRQ(timer wheel), 重新計算調度時(shí)間片等等 */
最后中斷服務(wù)程序設置定時(shí)器, 使其在下一個(gè)tick產(chǎn)生中斷.

這樣的框架, 使得high-res的timer很難加入. 所有中斷處理code都在體系結構代碼里被寫(xiě)死, 并且代碼重用率很低, 畢竟大多的arch都會(huì )寫(xiě)同樣的中斷處理函數.

2)hrtimer

kernel 里有了clockevent/source的引入, 就把clocksource的中斷以一種事件的方式被抽象出來(lái). 事件本身的處理交給event handler. handler可以在kernel里做替換從而改變時(shí)鐘中斷的行為. 時(shí)鐘中斷ISR會(huì )看上去象這樣:

static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
    /* clear timer interrupt flag */
    .....
    /* call clock event handler */
    arch_clockevent.event_handler(
&arch_clockevent);
    ....
    return IRQ_HANDLED;
}


event_handler 在注冊clockevent device時(shí), 會(huì )被默認設置成tick_handle_periodic(). 所以kernel剛起來(lái)的時(shí)候, 時(shí)鐘處理機制仍然是periodic的, ticker中斷周期性的產(chǎn)生. tick_handle_periodic()會(huì )做和timer_tick差不多的事情, 然后調用clockevents_program_event() => arch_clockevent.set_next_event()去設置下一個(gè)周期的定時(shí)器. tick-common.c里把原來(lái)kernel時(shí)鐘的處理方式在clockevent框架下實(shí)現了, 這就是periodic tick的時(shí)鐘機制.

hres tick機制在第一個(gè)TIMER SOFTIRQ里會(huì )替換掉periodic tick, 當然要符合一定條件, 比如command line里沒(méi)有把hres(highres=off)禁止掉, clocksource/event支持hres和oneshot的能力. 這里的切換做的比較ugly, 作者的comments也提到了, 每次timer softirq被調度, 都要調用hrtimer_run_queues()檢查一遍hres是否active, 如果能在timer_init()里就把clocksource/event的條件check過(guò), 直接切換到hres就最好了, 不知道是不是有什么限制條件. TIMER SOFTIRQ代碼如下:

static void run_timer_softirq(struct softirq_action *h)
{
    tvec_base_t *base = __get_cpu_var(tvec_bases);

    hrtimer_run_queues(); /* 有機會(huì )就切換到hres或者nohz */

    if (time_after_eq(jiffies, base->timer_jiffies))
        __run_timers(base); /* timer wheel */
}


切換的過(guò)程比較簡(jiǎn)單, 用hrtimer_interrupt()替換當前clockevent hander, 加載一個(gè)hrtimer: tick_sched_timer在下一個(gè)tick_period過(guò)期, retrigger下一次事件.
hrtimer_interrupt() 將過(guò)期的hrtimers從紅黑樹(shù)上摘下來(lái), 放到相應clock_base->cpu_base->cb_pending列表里, 這些過(guò)期timers會(huì )在HRTIMER_SOFTIRQ里執行. 然后根據剩余的最早過(guò)期的timer來(lái)retrigger下一個(gè)event, 再調度HRTIMER_SOFTIRQ. hrtimer softirq執行那些再cb_pending上的過(guò)期定時(shí)器函數. tick_sched_timer這個(gè)hrtimer在每個(gè)tick_period都會(huì )過(guò)期, 執行過(guò)程和timer_tick()差不多, 只是在最后調用hrtimer_forward將自己加載到下一個(gè)周期里去, 保證每個(gè)tick_period都能正確更新kernel內部時(shí)間統計.

Timekeeping

Timekeeping子系統負責更新xtime, 調整誤差, 及提供get/settimeofday接口. 為了便于理解, 首先介紹一些概念:

Times in Kernel

kernel的time基本類(lèi)型:
1) system time
A monotonically increasing value that represents the amount of time the system has been running. 單調增長(cháng)的系統運行時(shí)間, 可以通過(guò)time source, xtimewall_to_monotonic計算出來(lái).
2) wall time
A value representing the the human time of day, as seen on a wrist-watch. Realtime時(shí)間: xtime.
3) time source
A representation of a free running counter running at a known frequency, usually in hardware, e.g GPT. 可以通過(guò)clocksource->read()得到counter值
4) tick
A periodic interrupt generated by a hardware-timer, typically with a fixed interval
defined by HZ: jiffies

這些time之間互相關(guān)聯(lián), 互相可以轉換.
system_time = xtime + cyc2ns(clock->read() - clock->cycle_last) + wall_to_monotonic;
real_time = xtime + cyc2ns(clock->read() - clock->cycle_last)
也就是說(shuō)real time是從1970年開(kāi)始到現在的nanosecond, 而system time是系統啟動(dòng)到現在的nanosecond.
這兩個(gè)是最重要的時(shí)間, 由此hrtimer可以基于這兩個(gè)time來(lái)設置過(guò)期時(shí)間. 所以引入兩個(gè)clock base.

Clock Base

CLOCK_REALTIME: base在實(shí)際的wall time
CLOCK_MONOTONIC: base在系統運行system time
hrtimer可以選擇其中之一, 來(lái)設置expire time, 可以是實(shí)際的時(shí)間, 也可以是相對系統的時(shí)間.
他們提供get_time()接口:
CLOCK_REALTIME 調用ktime_get_real()來(lái)獲得真實(shí)時(shí)間, 該函數用上面提到的等式計算出realtime.
CLOCK_MONOTONIC 調用ktime_get(), 用system_time的等式獲得monotonic time.


timekeeping提供兩個(gè)接口do_gettimeofday()/do_settimeofday(), 都是針對realtime操作. 用戶(hù)空間對gettimeofday的syscall也會(huì )最終跑到這里來(lái).
do_gettimeofday()會(huì )調用__get_realtime_clock_ts()獲得時(shí)間, 然后轉成timeval.
do_settimeofday(), 將用戶(hù)設置的時(shí)間更新到xtime, 重新計算xtime到monotonic的轉換值, 最后通知hrtimers子系統時(shí)間變更.

int do_settimeofday(struct timespec *tv)
{
    unsigned long flags;
    time_t wtm_sec, sec = tv->tv_sec;
    long wtm_nsec, nsec = tv->tv_nsec;

    if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
        return -EINVAL;

    write_seqlock_irqsave(&xtime_lock, flags);

    nsec -= __get_nsec_offset();

    wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
    wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

    set_normalized_timespec(&xtime, sec, nsec); /* 重新計算xtime: 用戶(hù)設置的時(shí)間減去上一個(gè)周期到現在的nsec */
    set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); /* 重新調整wall_to_monotonic */

    clock->error = 0;
    ntp_clear();

    update_vsyscall(&xtime, clock);
    write_sequnlock_irqrestore(&xtime_lock, flags);
    /* signal hrtimers about time change */
    clock_was_set();

    return 0;
}



Userspace Application

hrtimer的引入, 對用戶(hù)最有用的接口如下:

Clock API
clock_gettime(clockid_t, struct timespec *)
獲取對應clock的時(shí)間
clock_settime(clockid_t, const struct timespec *)
設置對應clock時(shí)間
clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *)
進(jìn)程nano sleep
clock_getres(clockid_t, struct timespec *)
獲取時(shí)間精度, 一般是nanosec

clockid_t 定義了四種clock:
CLOCK_REALTIME
System-wide realtime clock. Setting this clock requires appropriate privileges.
CLOCK_MONOTONIC
Clock that cannot be set and represents monotonic time since some unspecified starting point.
CLOCK_PROCESS_CPUTIME_ID
High-resolution per-process timer from the CPU.
CLOCK_THREAD_CPUTIME_ID
Thread-specific CPU-time clock.
前兩者前面提到了, 后兩個(gè)是和進(jìn)程/線(xiàn)程統計時(shí)間有關(guān)系, 還沒(méi)有仔細研究過(guò), 是utime/stime之類(lèi)的時(shí)間. 應用層可以利用這四種clock, 提高靈活性及精度.

Timer API

Timer 可以建立進(jìn)程定時(shí)器,單次或者周期性定時(shí)。

int timer_create(clockid_t clockid, struct sigevent *restrict evp, timer_t *restrict timerid);
創(chuàng )建定時(shí)器。
clockid 指定在哪個(gè)clock base下創(chuàng )建定時(shí)器。
evp (sigevent) 可以指定定時(shí)器到期后內核發(fā)送哪個(gè)信號給進(jìn)程,以及信號所帶參數;默認為SIGALRM。
timerid 返回所建timer的id號。
在 signal處理函數里,可以通過(guò)siginfo_t.si_timerid 獲得當前的信號是由哪個(gè)timer過(guò)期觸發(fā)的。 試驗了一下,最多可創(chuàng )建的timer數目和ulimit里的pending signals的有關(guān)系,不能超過(guò)pending signals的數量。

int timer_gettime(timer_t timerid, struct itimerspec *value); 
獲得timer的下次過(guò)期的時(shí)間。

int timer_settime(timer_t timerid, int flags, const struct itimerspec *restrict value, struct itimerspec *restrict ovalue);

設置定時(shí)器的過(guò)期時(shí)間及間隔周期。

int timer_delete(timer_t timerid);
刪除定時(shí)器。

這些系統調用都會(huì )建立一個(gè)posix_timer的hrtimer,在過(guò)期的時(shí)候發(fā)送信號給進(jìn)程。

總結

hrtimer 及clockevent/source的引入對于kernel的實(shí)時(shí)性的提高有很大貢獻,也將clock的處理從體系結構的代碼中抽象了出來(lái),增強了代碼 的可重用性。并且對于posix的time/timer標準有了強有力的支持,提高了用戶(hù)空間的應用程序的時(shí)間處理精度及靈活性。如果應用層在使用這些 syscall時(shí)有任何不解之處,直接看看hrtimer的code,對于處理問(wèn)題,理解OS的行為都有很大幫助。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
LINUX高精度定時(shí)器實(shí)現分析 | 碼農故事
Linux時(shí)間子系統之六:高精度定時(shí)器(HRTIMER)的原理和實(shí)現
【轉】ARM Linux系統的時(shí)鐘機制【修改版】
淺析 Linux 中的時(shí)間編程和實(shí)現原理,第 4 部分: Linux 內核的工作
Linux 中 CPU 利用率是如何算出來(lái)的?
linux新定時(shí)器:timefd及相關(guān)操作函數
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久