操作系統(tǒng)課程設(shè)計內(nèi)核定時器_第1頁
操作系統(tǒng)課程設(shè)計內(nèi)核定時器_第2頁
操作系統(tǒng)課程設(shè)計內(nèi)核定時器_第3頁
操作系統(tǒng)課程設(shè)計內(nèi)核定時器_第4頁
操作系統(tǒng)課程設(shè)計內(nèi)核定時器_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、摘要摘要.11設(shè)計題目與要求設(shè)計題目與要求.21 11 1 設(shè)計題目設(shè)計題目:內(nèi)核定時器.21 12 2 設(shè)計要求設(shè)計要求:通過研究內(nèi)核的時間管理算法,學(xué)習(xí)內(nèi)核源代碼;然后應(yīng)用這些知識并且使用“信號”建立一種用戶空間機制來測量一個多線程程序的執(zhí)行時間。.22 2 總的設(shè)計思想及系統(tǒng)平臺、語言、工具總的設(shè)計思想及系統(tǒng)平臺、語言、工具.2設(shè)計思想:.2內(nèi)核對定時器的描述.22.1.2Linux 內(nèi)核定時器.32.1.3Linux 信號signal處理機制.6多線程編程.7內(nèi)核定時器機制的實現(xiàn).92.2.系統(tǒng)平臺:.122.3. 編程工具:.123數(shù)據(jù)結(jié)構(gòu)與模塊說明(功能與流程圖)數(shù)據(jù)結(jié)構(gòu)與模塊說明

2、(功能與流程圖).12定時器使用:.123.2 多線程程序:.13程序流程圖:.144.4. 源程序:源程序:.145 5運行結(jié)果與運行情況運行結(jié)果與運行情況.156 6調(diào)試記錄:調(diào)試記錄:.167 7自我評析和總結(jié):自我評析和總結(jié):.178.8.參考文獻參考文獻.17內(nèi)核定時器內(nèi)核定時器摘要摘要每個正在系統(tǒng)上運行的程序都是一個進程。每個進程包含一到多個線程。進程也可能是整個程序或者是部分程序的動態(tài)執(zhí)行。線程是一組指令的集合,或者是程序的特殊段,它可以在程序里獨立執(zhí)行。也可以把它理解為代碼運行的上下文。內(nèi)核時間指明線程執(zhí)行操作系統(tǒng)代碼已經(jīng)經(jīng)過了多少個 100ns 的 CPU 時間,linux

3、是一個具有保護模式的操作系統(tǒng)。它一直工作在 i386 cpu 的保護模式之下。內(nèi)存被分為兩個單元: 內(nèi)核區(qū)域和用戶區(qū)域。一般地,在使用虛擬內(nèi)存技術(shù)的多任務(wù)系統(tǒng)上,內(nèi)核和應(yīng)用有不同的地址空間,因此,在內(nèi)核和應(yīng)用之間以及在應(yīng)用與應(yīng)用之間進行數(shù)據(jù)交換需要專門的機制來實現(xiàn),本文站在用戶空間的角度,測試一個多線程程序的程序執(zhí)行時間。當一個進程希望獲得信號量時, 如果信號量已經(jīng)被占有, 則該進程將會被放到等待隊列上 sleep 直到 cpu 將其喚醒。相對于 spinlock 來說開銷太大,適用于長時間占有的 lock。不可用于中斷狀態(tài),因為它擁有信號量的進程可以 sleep, 可以被搶占,信號量可以設(shè)置

4、為同時允許的進程數(shù)。1設(shè)計題目與要求設(shè)計題目與要求11 設(shè)計題目:內(nèi)核定時器12 設(shè)計要求:通過研究內(nèi)核的時間管理算法,學(xué)習(xí)內(nèi)核源代碼;然后應(yīng)用這些知識并且使用“信號”建立一種用戶空間機制來測量一個多線程程序的執(zhí)行時間。2 2 總的設(shè)計思想及系統(tǒng)平臺、語言、工具2.12.1設(shè)計思想:Linux 內(nèi)核對定時器的描述 Linux 在頭文件中定義了數(shù)據(jù)結(jié)構(gòu) timer_list 來描述一個內(nèi)核定時器: struct timer_list struct list_head list; unsigned long expires; unsigned long data; void (*function)

5、(unsigned long); ; 各數(shù)據(jù)成員的含義如下: (1)雙向鏈表元素 list:用來將多個定時器連接成一條雙向循環(huán)隊列。 (2)expires:指定定時器到期的時間,這個時間被表示成自系統(tǒng)啟動以來的時鐘滴答計數(shù)(也即時鐘節(jié)拍數(shù))。當一個定時器的 expires 值小于或等于 jiffies 變量時,我們就說這個定時器已經(jīng)超時或到期了。在初始化一個定時器后,通常把它的 expires 域設(shè)置成當前expires變量的當前值加上某個時間間隔值(以時鐘滴答次數(shù)計)。 (3)函數(shù)指針 function:指向一個可執(zhí)行函數(shù)。當定時器到期時,內(nèi)核就執(zhí)行 function所指定的函數(shù)。而 dat

6、a 域則被內(nèi)核用作 function 函數(shù)的調(diào)用參數(shù)。 內(nèi)核函數(shù) init_timer()用來初始化一個定時器。實際上,這個初始化函數(shù)僅僅將結(jié)構(gòu)中的list 成員初始化為空。如下所示(): static inline void init_timer(struct timer_list * timer) timer-list.next = timer-list.prev = NULL; 由于定時器通常被連接在一個雙向循環(huán)隊列中等待執(zhí)行(此時我們說定時器處于 pending狀態(tài))。因此函數(shù) time_pending()就可以用 list 成員是否為空來判斷一個定時器是否處于pending 狀態(tài)。如

7、下所示 (): static inline int timer_pending (const struct timer_list * timer) return timer-list.next != NULL; 時間比較操作 在定時器應(yīng)用中經(jīng)常需要比較兩個時間值,以確定 timer 是否超時,所以 Linux 內(nèi)核在頭文件中定義了 4 個時間關(guān)系比較操作宏。這里我們說時刻 a 在時刻 b 之后,就意味著時間值 ab。Linux 強烈推薦用戶使用它所定義的下列 4 個時間比較操作宏(): #define time_after(a,b) (long)(b) - (long)(a) = 0) #de

8、fine time_before_eq(a,b) time_after_eq(b,a)2.1.2Linux 內(nèi)核定時器定時器是管理內(nèi)核時間的基礎(chǔ),用來計算流逝的時間,它以某種頻率(節(jié)拍率)自行觸發(fā)時鐘中斷,當時鐘中斷發(fā)生時,內(nèi)核就通過一種特殊中斷處理程序?qū)ζ溥M行處理。但是原來的實現(xiàn)只能是 time_t mytime 形式的,經(jīng)過簡單的 localtime(mytime)和ctime(&mytime)處理.精度是不夠的,為了返回高精度的時間,這里使用了 gettimeofday 函數(shù)。這個 syscall 用來供用戶獲取 timeval 格式的當前時間信息(精確度為微秒級) ,以及系統(tǒng)的

9、當前時區(qū)信息(timezone) 。結(jié)構(gòu)類型 timeval 的指針參數(shù) tv 指向接受時間信息的用戶空間緩沖區(qū),參數(shù) tz 是一個 timezone 結(jié)構(gòu)類型的指針,指向接收時區(qū)信息的用戶空間緩沖區(qū)。這兩個參數(shù)均為輸出參數(shù),返回值 0 表示成功,返回負值表示出錯。函數(shù) sys_gettimeofday()的源碼如下(kernel/time.c): asmlinkage long sys_gettimeofday(struct timeval *tv, struct timezone *tz) if (tv) struct timeval ktv; do_gettimeofday(&k

10、tv); if (copy_to_user(tv, &ktv, sizeof(ktv) return -EFAULT; if (tz) if (copy_to_user(tz, &sys_tz, sizeof(sys_tz) return -EFAULT; return 0; 顯然,函數(shù)的實現(xiàn)主要分成兩個大的方面: (1)如果 tv 指針有效,則說明用戶要以 timeval 格式來檢索系統(tǒng)當前時間。為此,先調(diào)用do_gettimeofday()函數(shù)來檢索系統(tǒng)當前時間并保存到局部變量 ktv 中。然后再調(diào)用copy_to_user()宏將保存在內(nèi)核空間中的當前時間信息拷貝到由參數(shù)

11、指針 tv 所指向的用戶空間緩沖區(qū)中。 (2)如果 tz 指針有效,則說明用戶要檢索當前時區(qū)信息,因此調(diào)用 copy_to_user()宏將全局變量 sys_tz 中的時區(qū)信息拷貝到參數(shù)指針 tz 所指向的用戶空間緩沖區(qū)中。 (3)最后,返回 0 表示成功。 函數(shù) do_gettimeofday()的源碼如下(arch/i386/kernel/time.c): /* * This version of gettimeofday has microsecond resolution * and better than microsecond precision on fast x86 machi

12、nes with TSC. */ void do_gettimeofday(struct timeval *tv) unsigned long flags; unsigned long usec, sec; read_lock_irqsave(&xtime_lock, flags); usec = do_gettimeoffset(); unsigned long lost = jiffies - wall_jiffies; if (lost) usec += lost * (1000000 / HZ); sec = xtime.tv_sec; usec += xtime.tv_use

13、c; read_unlock_irqrestore(&xtime_lock, flags); while (usec = 1000000) usec -= 1000000; sec+; tv-tv_sec = sec; tv-tv_usec = usec; 該函數(shù)的完成實際的當前時間檢索工作。由于 gettimeofday()系統(tǒng)調(diào)用要求時間精度要達到微秒級,因此 do_gettimeofday()函數(shù)不能簡單地返回 xtime 中的值即可,而必須精確地確定自從時鐘驅(qū)動的 Bottom Half 上一次更新 xtime 的那個時刻到 do_gettimeofday()函數(shù)的當前執(zhí)行時刻

14、之間的具體時間間隔長度,以便精確地修正 xtime 的值.假定被 do_gettimeofday()用來修正 xtime 的時間間隔為 fixed_usec,而從 wall_jiffies 到 jiffies之間的時間間隔是 lost_usec,而從 jiffies 到 do_gettimeofday()函數(shù)的執(zhí)行時刻的時間間隔是offset_usec。則下列三個等式成立: fixed_usec(lost_usecoffset_usec) lost_usec(jiffieswall_jiffies)TICK_SIZE(jiffieswall_jiffies)(1000000HZ) 由于全局變量

15、 last_tsc_low 表示上一次時鐘中斷服務(wù)函數(shù) timer_interrupt()執(zhí)行時刻的 CPU TSC 寄存器的值,因此我們可以用 X86 CPU 的 TSC 寄存器來計算 offset_usec 的值。也即: offset_usec=delay_at_last_interrupt(current_tsc_lowlast_tsc_low)fast_gettimeoffset_quotient 其中,delay_at_last_interrupt 是從上一次發(fā)生時鐘中斷到 timer_interrupt()服務(wù)函數(shù)真正執(zhí)行時刻之間的時間延遲間隔。每一次 timer_interrup

16、t()被執(zhí)行時都會計算這一間隔,并利用 TSC的當前值更新 last_tsc_low 變量(可以參見 7.4 節(jié)) 。假定 current_tsc_low 是 do_gettimeofday()函數(shù)執(zhí)行時刻 TSC 的當前值,全局變量 fast_gettimeoffset_quotient 則表示 TSC 寄存器每增加1 所代表的時間間隔值,它是由 time_init()函數(shù)所計算的。 根據(jù)上述原理分析,do_gettimeofday()函數(shù)的執(zhí)行步驟如下: (1)調(diào)用函數(shù) do_gettimeoffset()計算從上一次時鐘中斷發(fā)生到執(zhí)行 do_gettimeofday()函數(shù)的當前時刻之間

17、的時間間隔 offset_usec。 (2)通過 wall_jiffies 和 jiffies 計算 lost_usec 的值。 (3)然后,令 sec=xtime.tv_sec,usec=xtime.tv_usec+lost_usec+offset_usec。顯然,sec 表示系統(tǒng)當前時間在秒數(shù)量級上的值,而 usec 表示系統(tǒng)當前時間在微秒量級上的值。 (4)用一個 while循環(huán)來判斷 usec 是否已經(jīng)溢出而超過 106us1 秒。如果溢出,則將usec 減去 106us 并相應(yīng)地將 sec 增加 1,直到 usec 不溢出為止。 (5)最后,用 sec 和 usec 分別更新參數(shù)指針

18、所指向的 timeval 結(jié)構(gòu)變量。至此,整個查詢過程結(jié)束。 函數(shù) do_gettimeoffset()根據(jù) CPU 是否配置有 TSC 寄存器這一條件分別有不同的實現(xiàn)。其定義如下(arch/i386/kernel/time.c): #ifndef CONFIG_X86_TSC static unsigned long do_slow_gettimeoffset(void) static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; #else #define do_gettimeoffset() do_fas

19、t_gettimeoffset() #endif 顯然,在配置有 TSC 寄存器的 i386 平臺上,do_gettimeoffset()函數(shù)實際上就是do_fast_gettimeoffset()函數(shù)。它通過 TSC 寄存器來計算 do_fast_gettimeoffset()函數(shù)被執(zhí)行的時刻到上一次時鐘中斷發(fā)生時的時間間隔值。其源碼如下(arch/i386/kernel/time.c): static inline unsigned long do_fast_gettimeoffset(void) register unsigned long eax, edx; /* Read the T

20、ime Stamp Counter */ rdtsc(eax,edx); /* . relative to previous jiffy (32 bits is enough) */ eax -= last_tsc_low; /* tsc_low delta */ /* * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient * = (tsc_low delta) * (usecs_per_clock) * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy) * *

21、 Using a mull instead of a divl saves up to 31 clock cycles * in the critical path. */ _asm_(mull %2 :=a (eax), =d (edx) :rm (fast_gettimeoffset_quotient), 0 (eax); /* our adjusted time offset in microseconds */ return delay_at_last_interrupt + edx; 對該函數(shù)的注釋如下: (1)先調(diào)用 rdtsc()函數(shù)讀取當前時刻 TSC 寄存器的值,并將其高 3

22、2 位保存在 edx 局部變量中,低 32 位保存在局部變量 eax 中。 (2)讓局部變量 eaxtsc_loweaxlast_tsc_low;也即計算當前時刻的 TSC 值與上一次時鐘中斷服務(wù)函數(shù) timer_interrupt()執(zhí)行時的 TSC 值之間的差值。 (3)顯然,從上一次 timer_interrupt()到當前時刻的時間間隔就是(tsc_lowfast_gettimeoffset_quotient) 。因此用一條 mul 指令來計算這個乘法表達式的值。 (4)返回值 delay_at_last_interrupt(tsc_lowfast_gettimeoffset_quot

23、ient)就是從上一次時鐘中斷發(fā)生時到當前時刻之間的時間偏移間隔值。2.1.3Linux 信號 signal 處理機制信號 signal 機制是進程之間相互傳遞消息的一種方法,全稱為軟中斷信號。系統(tǒng)調(diào)用signal 用來設(shè)定某個信號的處理方法,其調(diào)用聲明的格式如下: void (*signal(int signum, void (*handler)(int)(int); 成功則返回該信號以前的處理配置,出錯則返回 SIG_ERR。在使用該調(diào)用的進程中加入以下頭文件:幾個常見信號:SIGINT: 當用戶按某些終端鍵時, 引發(fā)終端產(chǎn)生的信號. 如 Ctrl+C 鍵, 這將產(chǎn)生中斷信號(SIGINT

24、),它將停止一個已失去控制的程序。SIGSEGV: 由硬件異常(除數(shù)為 0, 無效的內(nèi)存引用等等)產(chǎn)生的信號。這些條件通常由硬件檢測到, 并將其通知內(nèi)核,然后內(nèi)核為該條件發(fā)生時正在運行的進程產(chǎn)生該信號。SIGURG: 在網(wǎng)絡(luò)連接上傳來帶外數(shù)據(jù)時產(chǎn)生。SIGPIPE: 在管道的讀進程已終止后, 一個進程寫此管道時產(chǎn)生,當類型為SOCK_STREAM 的 socket 已不再連接時, 進程寫到該 socket 也產(chǎn)生此信號。SIGALRM: 進程所設(shè)置的鬧鐘時鐘超時的時候產(chǎn)生。SIGABRT: 進程調(diào)用 abort 函數(shù)時產(chǎn)生此信號, 進程異常終止。SIGCHLD: 在一個進程終止或停止時, 它將

25、把該信號發(fā)送給其父進程。 按系統(tǒng)默認, 將忽略此信號,如果父進程希望被告知其子進程的這種狀態(tài)改變, 則應(yīng)該捕捉此信號。通常是用 wait 系列函數(shù)捕捉, 如果不 wait 的話, 子進程將成為一個僵尸進程。SIGIO: 此信號指示一個異步 I/O 事件。SIGSYS: 該信號指示一個無效的系統(tǒng)調(diào)用。SIGTSTP: 交互式停止信號. Ctrl+Z, 按下時, 終端將產(chǎn)生此信號, 進程被掛起。2.1.4 多線程編程多線程是計算機同時運行多個執(zhí)行線程的能力(這些線程可以是同一程序的組成部分,或者也可以是完全不同的程序) 。Linux 系統(tǒng)下的多線程遵循 POSIX 線程接口,稱為pthread。編

26、寫 Linux 下的多線程程序,需要使用頭文件 pthread.h,連接時需要使用庫libpthread.a。而 Linux 下 pthread 的實現(xiàn)是通過系統(tǒng)調(diào)用 clone()來實現(xiàn)的。clone()是Linux 所特有的系統(tǒng)調(diào)用,它的使用方式類似 fork。下面展示多線程程序部分 050119.c。/* 050119.c */#include #include void thread(void)int i;for(i=0;i3;i+)printf(This is a pthread.n);int pthread (void)pthread_t id;int i,ret;ret=pthr

27、ead_create(&id,NULL,(void *) thread,NULL);if(ret!=0)printf (Create pthread error!n);exit (1);for(i=0;i3;i+)printf(This is the main process.n);pthread_join(id,NULL);return (0);我們編譯此程序:運行 050119.out,我們得到如下結(jié)果:This is the main process.This is a pthread.This is the main process.This is the main proce

28、ss.This is a pthread.This is a pthread.再次運行,我們可能得到如下結(jié)果:This is a pthread.This is the main process.This is a pthread.This is the main process.This is a pthread.This is the main process.前后兩次結(jié)果不一樣,這是兩個線程爭奪 CPU 資源的結(jié)果。上面的示例中,我們使用到了兩個函數(shù),pthread_create 和 pthread_join,并聲明了一個 pthread_t 型的變量。pthread_t 在頭文件/us

29、r/include/bits/pthreadtypes.h 中定義:typedef unsigned long int pthread_t;它是一個線程的標識符。函數(shù) pthread_create 用來創(chuàng)建一個線程,它的原型為:extern int pthread_create _P (pthread_t *_thread, _const pthread_attr_t *_attr,void *(*_start_routine) (void *), void *_arg);第一個參數(shù)為指向線程標識符的指針,第二個參數(shù)用來設(shè)置線程屬性,第三個參數(shù)是線程運行函數(shù)的起始地址,最后一個參數(shù)是運行函數(shù)的

30、參數(shù)。這里,我們的函 數(shù) thread 不需要參數(shù),所以最后一個參數(shù)設(shè)為空指針。第二個參數(shù)我們也設(shè)為空指針,這樣將生成默認屬性的線程。對線程屬性的設(shè)定和修改我們將在下一節(jié) 闡述。當創(chuàng)建線程成功時,函數(shù)返回 0,若不為 0 則說明創(chuàng)建線程失敗,常見的錯誤返回代碼為 EAGAIN 和 EINVAL。前者表示系統(tǒng)限制創(chuàng)建新的線程,例如線程數(shù)目過多了;后者表示第二個參數(shù)代表的線程屬性值非法。創(chuàng)建線程成功后,新創(chuàng)建的線程則運行參數(shù)三和參數(shù)四確定的函數(shù),原來的線程則繼續(xù)運行下一行代碼。函數(shù) pthread_join 用來等待一個線程的結(jié)束。函數(shù)原型為:extern int pthread_join _P

31、(pthread_t _th, void *_thread_return);第一個參數(shù)為被等待的線程標識符,第二個參數(shù)為一個用戶定義的指針,它可以用來存儲被等待線程的返回值。這個函數(shù)是一個線程阻塞的函數(shù),調(diào)用它的函數(shù)將 一直等待到被等待的線程結(jié)束為止,當函數(shù)返回時,被等待線程的資源被收回。一個線程的結(jié)束有兩種途徑,一種是象我們上面的例子一樣,函數(shù)結(jié)束了,調(diào)用它的 線程也就結(jié)束了;另一種方式是通過函數(shù) pthread_exit 來實現(xiàn)。它的函數(shù)原型為:extern void pthread_exit _P (void *_retval) _attribute_ (_noreturn_);唯一的參

32、數(shù)是函數(shù)的返回代碼,只要 pthread_join 中的第二個參數(shù) thread_return 不是NULL,這個值將被傳遞給 thread_return。最后要說明的是,一個線程不能被多個線程等待,否則第一個接收到信號的線程成功返回,其余調(diào)用 pthread_join 的線 程則返回錯誤代碼ESRCH。2.1.5 內(nèi)核定時器機制的實現(xiàn).1 動態(tài)定時器機制的初始化 函數(shù) init_timervecs()實現(xiàn)對動態(tài)定時器機制的初始化。該函數(shù)僅被 sched_init()初始化例程所調(diào)用。動態(tài)定時器機制初始化過程的主要任務(wù)就是將 tv1、tv2、tv5 這 5 個結(jié)構(gòu)變量中的定時器向量指針數(shù)組 v

33、ec初始化為 NULL。如下所示(kernel/timer.c): void init_timervecs (void) int i; for (i = 0; i TVN_SIZE; i+) INIT_LIST_HEAD(tv5.vec + i); INIT_LIST_HEAD(tv4.vec + i); INIT_LIST_HEAD(tv3.vec + i); INIT_LIST_HEAD(tv2.vec + i); for (i = 0; i expires; unsigned long idx = expires - timer_jiffies; struct list_head * v

34、ec; if (idx TVR_SIZE) int i = expires & TVR_MASK; vec = tv1.vec + i; else if (idx 1 TVR_BITS) & TVN_MASK; vec = tv2.vec + i; else if (idx 1 (TVR_BITS + TVN_BITS) & TVN_MASK; vec = tv3.vec + i; else if (idx 1 (TVR_BITS + 2 * TVN_BITS) & TVN_MASK; vec = tv4.vec + i; else if (signed lon

35、g) idx 0) /* can happen if you add a timer with expires = jiffies, * or you set a timer to go off in the past */ vec = tv1.vec + tv1.index; else if (idx (TVR_BITS + 3 * TVN_BITS) & TVN_MASK; vec = tv5.vec + i; else /* Can only get here on architectures with 64-bit jiffies */ INIT_LIST_HEAD(&

36、timer-list); return; /* * Timers are FIFO! */ list_add(&timer-list, vec-prev); 對該函數(shù)的注釋如下: (1)首先,計算定時器的 expires 值與 timer_jiffies 的插值(注意!這里應(yīng)該使用動態(tài)定時器自己的時間基準) ,這個差值就表示這個定時器相對于上一次運行定時器機制的那個時刻還需要多長時間間隔才到期。局部變量 idx 保存這個差值。 (2)根據(jù) idx 的值確定這個定時器應(yīng)被插入到哪一個定時器向量中。其具體的確定方法我們在節(jié)已經(jīng)說過了,這里不再詳述。最后,定時器向量的頭部指針 vec 表示這

37、個定時器應(yīng)該所處的定時器向量鏈表頭部。 (3)最后,調(diào)用 list_add()函數(shù)將定時器插入到 vec 指針所指向的定時器隊列的尾部。 .3 修改一個定時器的 expires 值 當一個定時器已經(jīng)被插入到內(nèi)核動態(tài)定時器鏈表中后,我們還可以修改該定時器的 expires值。函數(shù) mod_timer()實現(xiàn)這一點。如下所示(kernel/timer.c): int mod_timer(struct timer_list *timer, unsigned long expires) int ret; unsigned long flags; spin_lock_irqsave(&timer

38、list_lock, flags); timer-expires = expires; ret = detach_timer(timer); internal_add_timer(timer); spin_unlock_irqrestore(&timerlist_lock, flags); return ret; 該函數(shù)首先根據(jù)參數(shù) expires 值更新定時器的 expires 成員。然后調(diào)用 detach_timer()函數(shù)將該定時器從它原來所屬的鏈表中刪除。最后調(diào)用 internal_add_timer()函數(shù)將該定時器根據(jù)它新的 expires 值重新插入到相應(yīng)的鏈表中。 函數(shù)

39、 detach_timer()首先調(diào)用 timer_pending()來判斷指定的定時器是否已經(jīng)處于某個鏈表中,如果定時器原來就不處于任何鏈表中,則 detach_timer()函數(shù)什么也不做,直接返回 0值,表示失敗。否則,就調(diào)用 list_del()函數(shù)將定時器從它原來所處的鏈表中摘除。如下所示(kernel/timer.c): static inline int detach_timer (struct timer_list *timer) if (!timer_pending(timer) return 0; list_del(&timer-list); return 1; 2

40、.2.系統(tǒng)平臺:系統(tǒng)平臺:一臺 Linux 主機且有超級用戶權(quán)限2.3. 編程工具:編程工具:VI 編輯器,Gedit 編輯器3數(shù)據(jù)結(jié)構(gòu)與模塊說明(功能與流程圖)數(shù)據(jù)結(jié)構(gòu)與模塊說明(功能與流程圖)3.1定時器使用:int gettimeofday(struct timeval *tv,struct timezone *tz); strut timevallong tv_sec; /*秒數(shù)*/ long tv_usec; /*微秒數(shù)*/ ;這個 syscall 用來供用戶獲取 timeval 格式的當前時間信息(精確度為微秒級) ,以及系統(tǒng)的當前時區(qū)信息(timezone) 。結(jié)構(gòu)類型 time

41、val 的指針參數(shù) tv 指向接受時間信息的用戶空間緩沖區(qū),參數(shù) tz 是一個 timezone 結(jié)構(gòu)類型的指針,指向接收時區(qū)信息的用戶空間緩沖區(qū)。這兩個參數(shù)均為輸出參數(shù),返回值 0 表示成功,返回負值表示出錯。實現(xiàn)過程如下:main() struct timeval tpstart,tpend; /*申請 struct timeval 的變量,tv_sec 返回的是秒數(shù),tv_usec 返回的是微秒數(shù)*/float timeuse; gettimeofday(&tpstart,NULL); pthread(); gettimeofday(&tpend,NULL); timeu

42、se=1000000*(tpend.tv_sec-tpstart.tv_sec)+ tpend.tv_usec-tpstart.tv_usec; timeuse/=1000000; printf(Used Time:%f secn,timeuse); exit(0); 3.2 多線程程序:進行多線程程序設(shè)計時,我們使用到了兩個函數(shù),pthread_create 和 pthread_join,并聲明了一個 pthread_t 型的變量。pthread_t 在頭文件/usr/include/bits/pthreadtypes.h 中定義,它是一個線程的標識符。函數(shù) pthread_create 用

43、來創(chuàng)建一個線程,函數(shù) pthread_join 用來等待一個線程的結(jié)束。實現(xiàn)過程如下:int pthread_create(&id,NULL,(void *) thread,NULL);pthread_join(id,NULL);void thread(void)int i;for(i=0;i3;i+)printf(This is a pthread.n);int pthread(void)pthread_t id; /* 聲明了一個 pthread_t 型的變量*/int i,ret;ret=pthread_create(&id,NULL,(void *) thread,NU

44、LL);if(ret!=0)printf(Create pthread error!n);exit(1);for(i=0;i3;i+)printf(This is the main process.n);pthread_join(id,NULL);return(0);3.3 程序流程圖:獲取進程開始時間獲取進程結(jié)束時間開始計算使用時間功能函數(shù)結(jié)束4.4. 源程序:源程序: #include #include #include int gettimeofday(struct timeval *tv,struct timezone *tz); int pthread_create(&id,

45、NULL,(void *) thread,NULL);/pthread_join(id,NULL);strut timevallong tv_sec; /*秒數(shù)*/ long tv_usec; /*微秒數(shù)*/ ;void thread(void)int i;for(i=0;i3;i+)printf(This is a pthread.n);int pthread(void)pthread_t id; /* 聲明了一個pthread_t型的變量*/int i,ret;ret=pthread_create(&id,NULL,(void *) thread,NULL);if(ret!=0)p

46、rintf(Create pthread error!n);exit(1);for(i=0;i3;i+)printf(This is the main process.n);pthread_join(id,NULL);return(0);main() struct timeval tpstart,tpend; /*申請struct timeval的變量,tv_sec返回的是秒數(shù),tv_usec返回的是微秒數(shù)*/float timeuse; gettimeofday(&tpstart,NULL); pthread(); gettimeofday(&tpend,NULL); timeuse=1000000*(tpend.tv_s

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論