早期的內(nèi)核版本中,進(jìn)程的調(diào)度基于一個(gè)稱之為tick的時(shí)鐘滴答,通常使用時(shí)鐘中斷來定時(shí)地產(chǎn)生tick信號(hào),每次tick定時(shí)中斷都會(huì)進(jìn)行進(jìn)程的統(tǒng)計(jì)和調(diào)度,并對(duì)tick進(jìn)行計(jì)數(shù),記錄在一個(gè)jiffies變量中,定時(shí)器的設(shè)計(jì)也是基于jiffies。這時(shí)候的內(nèi)核代碼中,幾乎所有關(guān)于時(shí)鐘的操作都是在machine級(jí)的代碼中實(shí)現(xiàn),很多公共的代碼要在每個(gè)平臺(tái)上重復(fù)實(shí)現(xiàn)。隨后,隨著通用時(shí)鐘框架的引入,內(nèi)核需要支持高精度的定時(shí)器,為此,通用時(shí)間框架為定時(shí)器硬件定義了一個(gè)標(biāo)準(zhǔn)的接口:clock_event_device,machine級(jí)的代碼只要按這個(gè)標(biāo)準(zhǔn)接口實(shí)現(xiàn)相應(yīng)的硬件控制功能,剩下的與平臺(tái)無關(guān)的特性則統(tǒng)一由通用時(shí)間框架層來實(shí)現(xiàn)。
1. ?時(shí)鐘事件軟件架構(gòu)
本系列文章的第一節(jié)中,我們?cè)?jīng)討論了時(shí)鐘源設(shè)備:clocksource,現(xiàn)在又來一個(gè)時(shí)鐘事件設(shè)備:clock_event_device,它們有何區(qū)別?看名字,好像都是給系統(tǒng)提供時(shí)鐘的設(shè)備,實(shí)際上,clocksource不能被編程,沒有產(chǎn)生事件的能力,它主要被用于timekeeper來實(shí)現(xiàn)對(duì)真實(shí)時(shí)間進(jìn)行精確的統(tǒng)計(jì),而clock_event_device則是可編程的,它可以工作在周期觸發(fā)或單次觸發(fā)模式,系統(tǒng)可以對(duì)它進(jìn)行編程,以確定下一次事件觸發(fā)的時(shí)間,clock_event_device主要用于實(shí)現(xiàn)普通定時(shí)器和高精度定時(shí)器,同時(shí)也用于產(chǎn)生tick事件,供給進(jìn)程調(diào)度子系統(tǒng)使用。時(shí)鐘事件設(shè)備與通用時(shí)間框架中的其他模塊的關(guān)系如下圖所示:
圖1.1 ? clock_event_device軟件架構(gòu)
與clocksource一樣,系統(tǒng)中可以存在多個(gè)clock_event_device,系統(tǒng)會(huì)根據(jù)它們的精度和能力,選擇合適的clock_event_device對(duì)系統(tǒng)提供時(shí)鐘事件服務(wù)。在smp系統(tǒng)中,為了減少處理器間的通信開銷,基本上每個(gè)cpu都會(huì)具備一個(gè)屬于自己的本地clock_event_device,獨(dú)立地為該cpu提供時(shí)鐘事件服務(wù),smp中的每個(gè)cpu基于本地的clock_event_device,建立自己的tick_device,普通定時(shí)器和高精度定時(shí)器。
在軟件架構(gòu)上看,clock_event_device被分為了兩層,與硬件相關(guān)的被放在了machine層,而與硬件無關(guān)的通用代碼則被集中到了通用時(shí)間框架層,這符合內(nèi)核對(duì)軟件的設(shè)計(jì)需求,平臺(tái)的開發(fā)者只需實(shí)現(xiàn)平臺(tái)相關(guān)的接口即可,無需關(guān)注復(fù)雜的上層時(shí)間框架。
tick_device是基于clock_event_device的進(jìn)一步封裝,用于代替原有的時(shí)鐘滴答中斷,給內(nèi)核提供tick事件,以完成進(jìn)程的調(diào)度和進(jìn)程信息統(tǒng)計(jì),負(fù)載平衡和時(shí)間更新等操作。
2. ?時(shí)鐘事件設(shè)備相關(guān)數(shù)據(jù)結(jié)構(gòu)
2.1 ?struct clock_event_device
時(shí)鐘事件設(shè)備的核心數(shù)據(jù)結(jié)構(gòu)是clock_event_device結(jié)構(gòu),它代表著一個(gè)時(shí)鐘硬件設(shè)備,該設(shè)備就好像是一個(gè)具有事件觸發(fā)能力(通常就是指中斷)的clocksource,它不停地計(jì)數(shù),當(dāng)計(jì)數(shù)值達(dá)到預(yù)先編程設(shè)定的數(shù)值那一刻,會(huì)引發(fā)一個(gè)時(shí)鐘事件中斷,繼而觸發(fā)該設(shè)備的事件處理回調(diào)函數(shù),以完成對(duì)時(shí)鐘事件的處理。clock_event_device結(jié)構(gòu)的定義如下:
[cpp]?view plain?copy
struct?clock_event_device?{??
void????????????(*event_handler)(struct?clock_event_device?*);??
int?????????(*set_next_event)(unsigned?long?evt,??
struct?clock_event_device?*);??
int?????????(*set_next_ktime)(ktime_t?expires,??
struct?clock_event_device?*);??
ktime_t?????????next_event;??
u64?????????max_delta_ns;??
u64?????????min_delta_ns;??
u32?????????mult;??
u32?????????shift;??
enum?clock_event_mode???mode;??
unsigned?int????????features;??
unsigned?long???????retries;??
void????????????(*broadcast)(const?struct?cpumask?*mask);??
void????????????(*set_mode)(enum?clock_event_mode?mode,??
struct?clock_event_device?*);??
unsigned?long???????min_delta_ticks;??
unsigned?long???????max_delta_ticks;??
const?char??????*name;??
int?????????rating;??
int?????????irq;??
const?struct?cpumask????*cpumask;??
struct?list_head????list;??
}?____cacheline_aligned;??
event_handler? 該字段是一個(gè)回調(diào)函數(shù)指針,通常由通用框架層設(shè)置,在時(shí)間中斷到來時(shí),machine底層的的中斷服務(wù)程序會(huì)調(diào)用該回調(diào),框架層利用該回調(diào)實(shí)現(xiàn)對(duì)時(shí)鐘事件的處理。
set_next_event??設(shè)置下一次時(shí)間觸發(fā)的時(shí)間,使用類似于clocksource的cycle計(jì)數(shù)值(離現(xiàn)在的cycle差值)作為參數(shù)。
set_next_ktime??設(shè)置下一次時(shí)間觸發(fā)的時(shí)間,直接使用ktime時(shí)間作為參數(shù)。
max_delta_ns ?可設(shè)置的最大時(shí)間差,單位是納秒。
min_delta_ns ?可設(shè)置的最小時(shí)間差,單位是納秒。
mult shift??與clocksource中的類似,只不過是用于把納秒轉(zhuǎn)換為cycle。
mode??該時(shí)鐘事件設(shè)備的工作模式,兩種主要的工作模式分別是:
CLOCK_EVT_MODE_PERIODIC ?周期觸發(fā)模式,設(shè)置后按給定的周期不停地觸發(fā)事件;
CLOCK_EVT_MODE_ONESHOT ?單次觸發(fā)模式,只在設(shè)置好的觸發(fā)時(shí)刻觸發(fā)一次;
set_mode??函數(shù)指針,用于設(shè)置時(shí)鐘事件設(shè)備的工作模式。
rating? 表示該設(shè)備的精度等級(jí)。
list? 系統(tǒng)中注冊(cè)的時(shí)鐘事件設(shè)備用該字段掛在全局鏈表變量clockevent_devices上。
2.2 ?全局變量clockevent_devices
系統(tǒng)中所有注冊(cè)的clock_event_device都會(huì)掛在該鏈表下面,它在kernel/time/clockevents.c中定義:
[cpp]?view plain?copy
static?LIST_HEAD(clockevent_devices);??
2.3 ?全局變量clockevents_chain
通用時(shí)間框架初始化時(shí)會(huì)注冊(cè)一個(gè)通知鏈(NOTIFIER),當(dāng)系統(tǒng)中的時(shí)鐘時(shí)間設(shè)備的狀態(tài)發(fā)生變化時(shí),利用該通知鏈通知系統(tǒng)的其它模塊。
[cpp]?view plain?copy
/*?Notification?for?clock?events?*/??
static?RAW_NOTIFIER_HEAD(clockevents_chain);??
3. ?clock_event_device的初始化和注冊(cè)
每一個(gè)machine,都要定義一個(gè)自己的machine_desc結(jié)構(gòu),該結(jié)構(gòu)定義了該machine的一些最基本的特性,其中需要設(shè)定一個(gè)sys_timer結(jié)構(gòu)指針,machine級(jí)的代碼負(fù)責(zé)定義sys_timer結(jié)構(gòu),sys_timer的聲明很簡(jiǎn)單:
[cpp]?view plain?copy
struct?sys_timer?{??
void????????????(*init)(void);??
void????????????(*suspend)(void);??
void????????????(*resume)(void);??
#ifdef?CONFIG_ARCH_USES_GETTIMEOFFSET??
unsigned?long???????(*offset)(void);??
#endif??
};??
通常,我們至少要定義它的init字段,系統(tǒng)初始化階段,該init回調(diào)會(huì)被調(diào)用,該init回調(diào)函數(shù)的主要作用就是完成系統(tǒng)中的clocksource和clock_event_device的硬件初始化工作,以samsung的exynos4為例,在V3.4內(nèi)核的代碼樹中,machine_desc的定義如下:
[cpp]?view plain?copy
MACHINE_START(SMDK4412,?"SMDK4412")??
/*?Maintainer:?Kukjin?Kim??*/??
/*?Maintainer:?Changhwan?Youn??*/??
.atag_offset????=?0x100,??
.init_irq???=?exynos4_init_irq,??
.map_io?????=?smdk4x12_map_io,??
.handle_irq?=?gic_handle_irq,??
.init_machine???=?smdk4x12_machine_init,??
.timer??????=?&exynos4_timer,??
.restart????=?exynos4_restart,??
MACHINE_END??
定義的sys_timer是exynos4_timer,它的定義和init回調(diào)定義如下:
[cpp]?view plain?copy
static?void?__init?exynos4_timer_init(void)??
{??
if?(soc_is_exynos4210())??
mct_int_type?=?MCT_INT_SPI;??
else??
mct_int_type?=?MCT_INT_PPI;??
exynos4_timer_resources();??
exynos4_clocksource_init();??
exynos4_clockevent_init();??
}??
struct?sys_timer?exynos4_timer?=?{??
.init???????=?exynos4_timer_init,??
};??
exynos4_clockevent_init函數(shù)顯然是初始化和注冊(cè)clock_event_device的合適時(shí)機(jī),在這里,它注冊(cè)了一個(gè)rating為250的clock_event_device,并把它指定給cpu0:
[cpp]?view plain?copy
static?struct?clock_event_device?mct_comp_device?=?{??
.name???????=?"mct-comp",??
.features???????=?CLOCK_EVT_FEAT_PERIODIC?|?CLOCK_EVT_FEAT_ONESHOT,??
.rating?????=?250,??
.set_next_event?=?exynos4_comp_set_next_event,??
.set_mode???=?exynos4_comp_set_mode,??
};??
......??
static?void?exynos4_clockevent_init(void)??
{??
clockevents_calc_mult_shift(&mct_comp_device,?clk_rate,?5);??
......??
mct_comp_device.cpumask?=?cpumask_of(0);??
clockevents_register_device(&mct_comp_device);??
setup_irq(EXYNOS4_IRQ_MCT_G0,?&mct_comp_event_irq);??
}??
因?yàn)檫@個(gè)階段其它c(diǎn)pu核尚未開始工作,所以該clock_event_device也只是在啟動(dòng)階段給系統(tǒng)提供服務(wù),實(shí)際上,因?yàn)閑xynos4是一個(gè)smp系統(tǒng),具備2-4個(gè)cpu核心,前面說過,smp系統(tǒng)中,通常會(huì)使用各個(gè)cpu的本地定時(shí)器來為每個(gè)cpu單獨(dú)提供時(shí)鐘事件服務(wù),繼續(xù)翻閱代碼,在系統(tǒng)初始化的后段,kernel_init會(huì)被調(diào)用,它會(huì)調(diào)用smp_prepare_cpus,其中會(huì)調(diào)用percpu_timer_setup函數(shù),在arch/arm/kernel/smp.c中,為每個(gè)cpu定義了一個(gè)clock_event_device:
[cpp]?view plain?copy
/*?
*?Timer?(local?or?broadcast)?support?
*/??
static?DEFINE_PER_CPU(struct?clock_event_device,?percpu_clockevent);??
percpu_timer_setup最終會(huì)調(diào)用exynos4_local_timer_setup函數(shù)完成對(duì)本地clock_event_device的初始化工作:
[cpp]?view plain?copy
static?int?__cpuinit?exynos4_local_timer_setup(struct?clock_event_device?*evt)??
{??
......??
evt->name?=?mevt->name;??
evt->cpumask?=?cpumask_of(cpu);??
evt->set_next_event?=?exynos4_tick_set_next_event;??
evt->set_mode?=?exynos4_tick_set_mode;??
evt->features?=?CLOCK_EVT_FEAT_PERIODIC?|?CLOCK_EVT_FEAT_ONESHOT;??
evt->rating?=?450;??
clockevents_calc_mult_shift(evt,?clk_rate?/?(TICK_BASE_CNT?+?1),?5);??
......??
clockevents_register_device(evt);??
......??
enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER,?0);??
......??
return?0;??
}??
由此可見,每個(gè)cpu的本地clock_event_device的rating是450,比啟動(dòng)階段的250要高,顯然,之前注冊(cè)給cpu0的精度要高,系統(tǒng)會(huì)用本地clock_event_device替換掉原來分配給cpu0的clock_event_device,至于怎么替換?我們先停一停,到這里我們一直在討論machine級(jí)別的初始化和注冊(cè),讓我們回過頭來,看看框架層的初始化。在繼續(xù)之前,讓我們看看整個(gè)clock_event_device的初始化的調(diào)用序列圖:
圖3.1 ?clock_event_device的系統(tǒng)初始化
由上面的圖示可以看出,框架層的初始化步驟很簡(jiǎn)單,又start_kernel開始,調(diào)用tick_init,它位于kernel/time/tick-common.c中,也只是簡(jiǎn)單地調(diào)用clockevents_register_notifier,同時(shí)把類型為notifier_block的tick_notifier作為參數(shù)傳入,回看2.3節(jié),clockevents_register_notifier注冊(cè)了一個(gè)通知鏈,這樣,當(dāng)系統(tǒng)中的clock_event_device狀態(tài)發(fā)生變化時(shí)(新增,刪除,掛起,喚醒等等),tick_notifier中的notifier_call字段中設(shè)定的回調(diào)函數(shù)tick_notify就會(huì)被調(diào)用。接下來start_kernel調(diào)用了time_init函數(shù),該函數(shù)通常定義在體系相關(guān)的代碼中,正如前面所討論的一樣,它主要完成machine級(jí)別對(duì)時(shí)鐘系統(tǒng)的初始化工作,最終通過clockevents_register_device注冊(cè)系統(tǒng)中的時(shí)鐘事件設(shè)備,把每個(gè)時(shí)鐘時(shí)間設(shè)備掛在clockevent_device全局鏈表上,最后通過clockevent_do_notify觸發(fā)框架層事先注冊(cè)好的通知鏈,其實(shí)就是調(diào)用了tick_notify函數(shù),我們主要關(guān)注CLOCK_EVT_NOTIFY_ADD通知,其它通知請(qǐng)自行參考代碼,下面是tick_notify的簡(jiǎn)化版本:
[cpp]?view plain?copy
static?int?tick_notify(struct?notifier_block?*nb,?unsigned?long?reason,??
void?*dev)??
{??
switch?(reason)?{??
case?CLOCK_EVT_NOTIFY_ADD:??
return?tick_check_new_device(dev);??
case?CLOCK_EVT_NOTIFY_BROADCAST_ON:??
case?CLOCK_EVT_NOTIFY_BROADCAST_OFF:??
case?CLOCK_EVT_NOTIFY_BROADCAST_FORCE:??
......??
case?CLOCK_EVT_NOTIFY_BROADCAST_ENTER:??
case?CLOCK_EVT_NOTIFY_BROADCAST_EXIT:??
......??
case?CLOCK_EVT_NOTIFY_CPU_DYING:??
......??
case?CLOCK_EVT_NOTIFY_CPU_DEAD:??
......??
case?CLOCK_EVT_NOTIFY_SUSPEND:??
......??
case?CLOCK_EVT_NOTIFY_RESUME:??
......??
}??
return?NOTIFY_OK;??
}??
可見,對(duì)于新注冊(cè)的clock_event_device,會(huì)發(fā)出CLOCK_EVT_NOTIFY_ADD通知,最終會(huì)進(jìn)入函數(shù):tick_check_new_device,這個(gè)函數(shù)比對(duì)當(dāng)前cpu所使用的與新注冊(cè)的clock_event_device之間的特性,如果認(rèn)為新的clock_event_device更好,則會(huì)進(jìn)行切換工作。下一節(jié)將會(huì)詳細(xì)的討論該函數(shù)。到這里,每個(gè)cpu已經(jīng)有了自己的clock_event_device,在這以后,框架層的代碼會(huì)根據(jù)內(nèi)核的配置項(xiàng)(CONFIG_NO_HZ、CONFIG_HIGH_RES_TIMERS),對(duì)注冊(cè)的clock_event_device進(jìn)行不同的設(shè)置,從而為系統(tǒng)的tick和高精度定時(shí)器提供服務(wù),這些內(nèi)容我們留在本系列的后續(xù)文章進(jìn)行討論。
4. ?tick_device
當(dāng)內(nèi)核沒有配置成支持高精度定時(shí)器時(shí),系統(tǒng)的tick由tick_device產(chǎn)生,tick_device其實(shí)是clock_event_device的簡(jiǎn)單封裝,它內(nèi)嵌了一個(gè)clock_event_device指針和它的工作模式:
[cpp]?view plain?copy
struct?tick_device?{??
struct?clock_event_device?*evtdev;??
enum?tick_device_mode?mode;??
};??
在kernel/time/tick-common.c中,定義了一個(gè)per-cpu的tick_device全局變量,tick_cpu_device:
[cpp]?view plain?copy
/*?
*?Tick?devices?
*/??
DEFINE_PER_CPU(struct?tick_device,?tick_cpu_device);??
前面曾經(jīng)說過,當(dāng)machine的代碼為每個(gè)cpu注冊(cè)clock_event_device時(shí),通知回調(diào)函數(shù)tick_notify會(huì)被調(diào)用,進(jìn)而進(jìn)入tick_check_new_device函數(shù),下面讓我們看看該函數(shù)如何工作,首先,該函數(shù)先判斷注冊(cè)的clock_event_device是否可用于本cpu,然后從per-cpu變量中取出本cpu的tick_device:
[cpp]?view plain?copy
static?int?tick_check_new_device(struct?clock_event_device?*newdev)??
{??
......??
cpu?=?smp_processor_id();??
if?(!cpumask_test_cpu(cpu,?newdev->cpumask))??
goto?out_bc;??
td?=?&per_cpu(tick_cpu_device,?cpu);??
curdev?=?td->evtdev;??
如果不是本地clock_event_device,會(huì)做進(jìn)一步的判斷:如果不能把irq綁定到本cpu,則放棄處理,如果本cpu已經(jīng)有了一個(gè)本地clock_event_device,也放棄處理:
[cpp]?view plain?copy
if?(!cpumask_equal(newdev->cpumask,?cpumask_of(cpu)))?{??
......??
if?(!irq_can_set_affinity(newdev->irq))??
goto?out_bc;??
......??
if?(curdev?&&?cpumask_equal(curdev->cpumask,?cpumask_of(cpu)))??
goto?out_bc;??
}??
反之,如果本cpu已經(jīng)有了一個(gè)clock_event_device,則根據(jù)是否支持單觸發(fā)模式和它的rating值,決定是否替換原來舊的clock_event_device:
[cpp]?view plain?copy
if?(curdev)?{??
if?((curdev->features?&?CLOCK_EVT_FEAT_ONESHOT)?&&??
!(newdev->features?&?CLOCK_EVT_FEAT_ONESHOT))??
goto?out_bc;??//?新的不支持單觸發(fā),但舊的支持,所以不能替換??
if?(curdev->rating?>=?newdev->rating)??
goto?out_bc;??//?舊的比新的精度高,不能替換??
}??
在這些判斷都通過之后,說明或者來cpu還沒有綁定tick_device,或者是新的更好,需要替換:
[cpp]?view plain?copy
if?(tick_is_broadcast_device(curdev))?{??
clockevents_shutdown(curdev);??
curdev?=?NULL;??
}??
clockevents_exchange_device(curdev,?newdev);??
tick_setup_device(td,?newdev,?cpu,?cpumask_of(cpu));??
上面的tick_setup_device函數(shù)負(fù)責(zé)重新綁定當(dāng)前cpu的tick_device和新注冊(cè)的clock_event_device,如果發(fā)現(xiàn)是當(dāng)前cpu第一次注冊(cè)tick_device,就把它設(shè)置為TICKDEV_MODE_PERIODIC模式,如果是替換舊的tick_device,則根據(jù)新的tick_device的特性,設(shè)置為TICKDEV_MODE_PERIODIC或TICKDEV_MODE_ONESHOT模式。可見,在系統(tǒng)的啟動(dòng)階段,tick_device是工作在周期觸發(fā)模式的,直到框架層在合適的時(shí)機(jī),才會(huì)開啟單觸發(fā)模式,以便支持NO_HZ和HRTIMER。
5. ?tick事件的處理--最簡(jiǎn)單的情況
clock_event_device最基本的應(yīng)用就是實(shí)現(xiàn)tick_device,然后給系統(tǒng)定期地產(chǎn)生tick事件,通用時(shí)間框架對(duì)clock_event_device和tick_device的處理相當(dāng)復(fù)雜,因?yàn)樯婕芭渲庙?xiàng):CONFIG_NO_HZ和CONFIG_HIGH_RES_TIMERS的組合,兩個(gè)配置項(xiàng)就有4種組合,這四種組合的處理都有所不同,所以這里我先只討論最簡(jiǎn)單的情況:
CONFIG_NO_HZ == 0;
CONFIG_HIGH_RES_TIMERS == 0;
在這種配置模式下,我們回到上一節(jié)的tick_setup_device函數(shù)的最后:
[cpp]?view plain?copy
if?(td->mode?==?TICKDEV_MODE_PERIODIC)??
tick_setup_periodic(newdev,?0);??
else??
tick_setup_oneshot(newdev,?handler,?next_event);??
因?yàn)閱?dòng)期間,第一個(gè)注冊(cè)的tick_device必然工作在TICKDEV_MODE_PERIODIC模式,所以tick_setup_periodic會(huì)設(shè)置clock_event_device的事件回調(diào)字段event_handler為tick_handle_periodic,工作一段時(shí)間后,就算有新的支持TICKDEV_MODE_ONESHOT模式的clock_event_device需要替換,再次進(jìn)入tick_setup_device函數(shù),tick_setup_oneshot的handler參數(shù)也是之前設(shè)置的tick_handle_periodic函數(shù),所以我們考察tick_handle_periodic即可:
[cpp]?view plain?copy
void?tick_handle_periodic(struct?clock_event_device?*dev)??
{??
int?cpu?=?smp_processor_id();??
ktime_t?next;??
tick_periodic(cpu);??
if?(dev->mode?!=?CLOCK_EVT_MODE_ONESHOT)??
return;??
next?=?ktime_add(dev->next_event,?tick_period);??
for?(;;)?{??
if?(!clockevents_program_event(dev,?next,?false))??
return;??
if?(timekeeping_valid_for_hres())??
tick_periodic(cpu);??
next?=?ktime_add(next,?tick_period);??
}??
}??
該函數(shù)首先調(diào)用tick_periodic函數(shù),完成tick事件的所有處理,如果是周期觸發(fā)模式,處理結(jié)束,如果工作在單觸發(fā)模式,則計(jì)算并設(shè)置下一次的觸發(fā)時(shí)刻,這里用了一個(gè)循環(huán),是為了防止當(dāng)該函數(shù)被調(diào)用時(shí),clock_event_device中的計(jì)時(shí)實(shí)際上已經(jīng)經(jīng)過了不止一個(gè)tick周期,這時(shí)候,tick_periodic可能被多次調(diào)用,使得jiffies和時(shí)間可以被正確地更新。tick_periodic的代碼如下:
[cpp]?view plain?copy
static?void?tick_periodic(int?cpu)??
{??
if?(tick_do_timer_cpu?==?cpu)?{??
write_seqlock(&xtime_lock);??
/*?Keep?track?of?the?next?tick?event?*/??
tick_next_period?=?ktime_add(tick_next_period,?tick_period);??
do_timer(1);??
write_sequnlock(&xtime_lock);??
}??
update_process_times(user_mode(get_irq_regs()));??
profile_tick(CPU_PROFILING);??
}??
如果當(dāng)前cpu負(fù)責(zé)更新時(shí)間,則通過do_timer進(jìn)行以下操作:
更新jiffies_64變量;
更新墻上時(shí)鐘;
每10個(gè)tick,更新一次cpu的負(fù)載信息;
調(diào)用update_peocess_times,完成以下事情:
更新進(jìn)程的時(shí)間統(tǒng)計(jì)信息;
觸發(fā)TIMER_SOFTIRQ軟件中斷,以便系統(tǒng)處理傳統(tǒng)的低分辨率定時(shí)器;
檢查rcu的callback;
通過scheduler_tick觸發(fā)調(diào)度系統(tǒng)進(jìn)行進(jìn)程統(tǒng)計(jì)和調(diào)度工作;
?
評(píng)論
查看更多