?? 2.html
字號:
cli();<br> }<br> ++timer_jiffies;<br> tv1.index = (tv1.index + 1) & TVR_MASK;<br>}<br>sti();<br>}<br>對run_timer_list函數的說明如下:<br>關中。<br>判斷jiffies是否大等于timer_jiffies,若不是,goto 8。<br>判斷tv1.index是否為0(即此時系統已經掃描過整個tv1的256個timer_list鏈表,又回到的第一個鏈表處,此時需重整TVECS結構),若是,置n為1;若不是,goto 6。<br>調用cascade_timers()函數把TVECS[n]中由其index指定的那條鏈表上的timer放到TVECS[n-1]中來。注意:調用cascade_timers()函數后,index已經加1。<br>判斷TVECS[n]->index是否為1,即原來為0。如果是(表明TVECS[n]上所有都已經掃描一遍,此時需對其后一級的TVECS[++n]調用cascade_timers()進行重整),把n加1,goto 4。<br>執行tv1.vec上由tv1->index指定的那條鏈表上的所有timer的服務函數,并把該timer從鏈表中移走。在執行服務函數的過程中,允許中斷。<br>timer_jiffies加1,tv1->index加1,若tv1->index等于256,則重新置為0,goto 2。<br>開中,返回。<p>Linux提供了兩種定時器服務。一種早期的由timer_struct等結構描述,由run_old_times函數處理。另一種“新”的服務由timer_list等結構描述,由add_timer、del_timer、cascade_time和run_timer_list等函數處理。<br>早期的定時器服務利用如下數據結構:<br>struct timer_struct {<br> unsigned long expires; /*本定時器被喚醒的時刻 */<br> void (*fn)(void); /* 定時器喚醒后的處理函數 */<br>}<br>struct timer_struct timer_table[32]; /*最多可同時啟用32個定時器 */<br>unsigned long timer_active; /* 每位對應一定時器,置1表示啟用 */<br>新的定時器服務依靠鏈表結構突破了32個的限制,利用如下的數據結構:<br>struct timer_list {<br> struct timer_list *next;<br> struct timer_list *prev;<br> unsigned long expires;<br> unsigned long data; /* 用來存放當前進程的PCB塊的指針,可作為參數傳<br> void (*function)(unsigned long); 給function */<br>}<p><br>表示上述數據結構的圖示如下:<p><br> 在這里,順便簡單介紹一下舊的timer機制的運作情況。<br> 系統在每次調用函數do_bottom_half時,都會調用一次函數run_old_timers()。<br>函數run_old_timers()<br>該函數處理的很簡單,只不過依次掃描timer_table中的32個定時器,若掃描到的定時器已經到期,并且已經被激活,則執行該timer的服務函數。<p>間隔定時器itimer<br>系統為每個進程提供了三個間隔定時器。當其中任意一個定時器到期時,就會發出一個信號給進程,同時,定時器重新開始運作。三種定時器描述如下:<br>ITIMER_REAL 真實時鐘,到期時送出SIGALRM信號。<br>ITIMER_VIRTUAL 僅在進程運行時的計時,到期時送出SIGVTALRM信號。<br>ITIMER_PROF 不僅在進程運行時計時,在系統為進程運作而運行時它也計時,與ITIMER_VIRTUAL對比,該定時器通常為那些在用戶態和核心態空間運行的應用所花去的時間計時,到期時送出SIGPROF信號。<br>與itimer有關的數據結構定義如下:<br>struct timespec {<br> long tv_sec; /* seconds */<br> long tv_nsec; /* nanoseconds */<br>};<br>struct timeval {<br> int tv_sec; /* seconds */<br> int tv_usec; /* microseconds */<br>};<br>struct itimerspec {<br> struct timespec it_interval; /* timer period */<br> struct timespec it_value; /* timer expiration */<br>};<br>struct itimerval {<br> struct timeval it_interval; /* timer interval */<br> struct timeval it_value; /* current value */<br>};<p>這三種定時器在task_struct中定義:<br>struct task_struct {<br> ……<br> unsigned long timeout;<br> unsigned long it_real_value,it_prof_value,it_virt_value;<br> unsigned long it_real_incr,it_prof_incr,it_virt_incr;<br> struct timer_list real_timer;<br> ……<br>}<br>在進程創建時,系統把it_real_fn函數的入口地址賦給real_timer.function。(見sched.h)<br>我們小組分析了三個系統調用:sys_getitimer,sys_setitimer,sys_alarm。<br>在這三個系統調用中,需用到以下一些函數:<br>函數static int _getitimer(int which, struct itimerval *value)<br>該函數的運行過程大致如下:<br>根據傳進的參數which按三種itimer分別處理:<br>若是ITIMER_REAL,則設置interval為current進程的it_real_incr,val設置為0;判斷current進程的real_timer有否設置并掛入TVECS結構中,若有,設置val為current進程real_timer的expires,并把real_timer重新掛到TVECS結構中,接著把val與當前jiffies作比較,若小等于當前jiffies,則說明該real_timer已經到期,于是重新設置val為當前jiffies的值加1。最后把val減去當前jiffies的值,goto 2。<br>若是ITIMER_VIRTUAL,則分別設置interval,val的值為current進程的it_virt_incr、it_virt_value,goto 2。<br>若是ITIMER_PROF,則分別設置interval,val的值為current進程的it_prof_incr、it_prof_value,goto 2。<br> (2)調用函數jiffiestotv把val,interval的jiffies值轉換為timeval,返回0。<br>函數 int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue)<br>該函數的運行過程大致如下:<br>調用函數tvtojiffies把value中的interval和value轉換為jiffies i 和 j。<br>判斷指針ovalue是否為空,若空,goto ;若不空,則把由which指定類型的itimer存入ovalue中,若存放不成功,goto 4;<br>根據which指定的itimer按三種類型分別處理:<br>若是ITIMER_REAL,則從TVECS結構中取出current進程的real_timer,并重新設置current進程的it_real_value和it_real_incr為j和i。若j等于0,goto 4;若不等于0,則把當前jiffies的值加上定時器剩余時間j,得到觸發時間。若i小于j,則表明I已經溢出,應該重新設為ULONG_MAX。最后把current進程的real_timer的expires設為i,把設置過的real_timer重新加入TVECS結構,goto 4。<br>若是ITIMER_VIRTUAL,則設置current進程的it-_virt_value和it_virt_incr為j和i。<br>若是ITIMER_PROF,則設置current進程的it-_prof_value和it_prof_incr為j和i。<br> (4)返回0。<p>函數verify_area(int type, const void *addr, unsigned long size)<br>該函數的主要功能是對以addr為始址的,長度為size的一塊存儲區是否有type類型的操作權利。<p>函數memcpy_tofs(to, from, n)<br>該函數的主要功能是從以from為始址的存儲區中取出長度為n的一塊數據放入以to為始址的存儲區。<p>函數memcpy_fromfs(from, to, n)<br>該函數的主要功能是從以from為始址的存儲區中取出長度為n的一塊數據放入以to為始址的存儲區。<p>函數memset((char*)&set_buffer, 0, sizeof(set_buffer))<br>該函數的主要功能是把set_buffer中的內容置為0,在這里,即把it_value和it_interval置為0。<p>現在,我簡單介紹一下這三個系統調用:<br>系統調用sys_getitimer(int which, struct itimerval *value)<p>首先,若value為NULL,則返回-EFAULT,說明這是一個bad address。<br>其次,把which類型的itimer取出放入get_buffer。<br>再次,若存放成功,再確認對value的寫權利。<br>最后,則把get_buffer中的itimer取出,拷入value。<p>系統調用sys_setitimer(int which, struct itimerval *value,struct itimerval *ovalue)<p>首先,判斷value是否為NULL,若不是,則確認對value是否有讀的權利,并把set_buffer中的數據拷入value;若value為NULL,則把set_buffer中的內容置為0,即把it_value和it_interval置為0。<br>其次,判斷ovalue是否為NULL,若不是,則確認對ovalue是否有寫的權利。<br>再次,調用函數_setitimer設置由which指定類型的itimer。<br>最后,調用函數memcpy_tofs把get_buffer中的數據拷入ovalue,返回。<p>系統調用sys_alarm(unsigned int seconds)<p>該系統調用重新設置進程的real_itimer,若seconds為0,則把原先的alarm定時器刪掉。并且設interval為0,故只觸發一次,并把舊的real_timer存入oldalarm,并返回oldalarm。<p><p><p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I366" ID="I366"></A><center><b><font size=+2>from aka</font></b></center><br><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I367" ID="I367"></A><center><b><font size=+2>硬件中斷</font></b></center><br>硬件中斷<p>硬件中斷概述<p>中斷可以用下面的流程來表示:<p>中斷產生源 --> 中斷向量表 (idt) --> 中斷入口 ( 一般簡單處理后調用相應的函數) --->do_IRQ--> 后續處理(軟中斷等工作)<p>具體地說,處理過程如下:<p>中斷信號由外部設備發送到中斷芯片(模塊)的引腳<p>中斷芯片將引腳的信號轉換成數字信號傳給CPU,例如8259主芯片引腳0發送的是0x20<p>CPU接收中斷后,到中斷向量表IDT中找中斷向量<p>根據存在中斷向量中的數值找到向量入口<p>由向量入口跳轉到一個統一的處理函數do_IRQ<p>在do_IRQ中可能會標注一些軟中斷,在執行完do_IRQ后執行這些軟中斷。<p>下面一一介紹。<p>8259芯片<p>本文主要參考周明德《微型計算機系統原理及應用》和billpan的相關帖子<p>1.中斷產生過程<p>(1)如果IR引腳上有信號,會使中斷請求寄存器(Interrupt Request Register,IRR)相應的位置位,比如圖中, IR3, IR4, IR5上有信號,那么IRR的3,4,5為1<p>(2)如果這些IRR中有一個是允許的,也就是沒有被屏蔽,那么就會通過INT向CPU發出中斷請求信號。屏蔽是由中斷屏蔽寄存器(Interrupt Mask Register,IMR)來控制的,比如圖中位3被置1,也就是IRR位3的信號被屏蔽了。在圖中,還有4,5的信號沒
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -