[自制简单操作系统] 4、计时器(线性表实现优化中断)
?
?
1、第一版:數組方式[09d]
>_<" 在bootpack.h里面的timer.c的聲明和結構體:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500個定時器 3 struct TIMER{ 4 unsigned int flags;//flags記錄各個寄存器狀態 5 unsigned int timeout;//用來記錄離超時還有多長時間,一旦這個剩余時間為0,程序就往FIFO緩沖區里發送數據,定時器就是用這種方法通知HariMain時間到了 6 struct FIFO8 *fifo;//消息隊列 7 unsigned char data;//該定時器標志,用來向消息隊列寫的標志信息 8 }; 9 struct TIMERCTL{ 10 unsigned int count;//計數 11 struct TIMER timer[MAX_TIMER]; 12 }; 13 extern struct TIMERCTL timerctl; 14 void init_pit(void);//定時器初始化100hz 15 struct TIMER *timer_alloc(void);//分配定時器,遍歷所有找到第一個沒有使用的分配 16 void timer_free(struct TIMER *timer);//釋放定時器 17 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data);//初始化定時器,fifo和標志符data 18 void timer_settime(struct TIMER *timer, unsigned int timeout);//定時器設置,設定剩余時間 19 void inthandler20(int *esp);//定時器中斷函數 20 //void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data);//設置定時器 1 /* PIT 定時器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//計數器結構體實例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置狀態 11 #define TIMER_FLAGS_USING 2 //定時器運行中 12 13 / 14 //功能:定時器初始化,要3次OUT指令,(0x34->0x34)(中斷周期低8位->0x40)(高8位->0x40) 15 //參數: 16 //附加:設置結果為主頻/設置數,這里中斷周期設置為0x2e9c,大約為100hz,具體搜:IRQ0中斷周期變更PIT 17 void init_pit(void) 18 { 19 int i; 20 io_out8(PIT_CTRL, 0x34); 21 io_out8(PIT_CNT0, 0x9c); 22 io_out8(PIT_CNT0, 0x2e); 23 timerctl.count=0;//初始化計數為0 24 // timerctl.timeout=0;//剩余時間為0 25 for(i=0;i<MAX_TIMER;i++){//初始化所有定時器未使用 26 timerctl.timer[i].flags=0;//未使用 27 } 28 return; 29 } 30 / 31 //功能:分配定時器 32 //參數: 33 struct TIMER *timer_alloc(void) 34 { 35 int i; 36 for (i = 0; i < MAX_TIMER; i++) {//從開始開始找沒有使用的定時器,找到后設置為分配狀態,反回 37 if (timerctl.timer[i].flags == 0) { 38 timerctl.timer[i].flags = TIMER_FLAGS_ALLOC; 39 return &timerctl.timer[i]; 40 } 41 } 42 return 0; /* 沒有找到 */ 43 } 44 / 45 //功能:釋放定時器,直接把標志位設為0即可 46 //參數: 47 void timer_free(struct TIMER *timer) 48 { 49 timer->flags = 0; /* 未使用 */ 50 return; 51 } 52 / 53 //功能:初始化定時器,賦值fifo,設置標志位 54 //參數: 55 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data) 56 { 57 timer->fifo = fifo; 58 timer->data = data; 59 return; 60 } 61 / 62 //功能:設置timer 63 //參數:輸入剩余時間 64 void timer_settime(struct TIMER *timer, unsigned int timeout) 65 { 66 timer->timeout = timeout; 67 timer->flags = TIMER_FLAGS_USING; 68 return; 69 } 70 71 72 / 73 //功能:定時器中斷處理程序,和鍵盤鼠標中斷類似 74 //參數: 75 void inthandler20(int *esp) 76 { 77 int i; 78 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信號接受完了的信息通知給PIC */ 79 timerctl.count++;//計數 80 for (i = 0; i < MAX_TIMER; i++) {//遍歷所有的定時器 81 if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {//有正在使用的就剩余時間-- 82 timerctl.timer[i].timeout--; 83 if (timerctl.timer[i].timeout == 0) {//剩余時間為0就直接將標志位改為非使用,將消息寫進隊列 84 timerctl.timer[i].flags = TIMER_FLAGS_ALLOC; 85 fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);////剩余時間為0就向緩沖區寫數據,用這種方法通知main函數 86 } 87 } 88 } 89 return; 90 } 91 / 92 //功能:定時器設置,因為沒有設置好就發生中斷就會混亂,所以先關閉中斷,然后恢復中斷 93 //參數:初始剩余時間,fifo,標志data(向緩沖區寫的數據) 94 //void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data) 95 //{ 96 // int eflags; 97 // eflags = io_load_eflags(); 98 // io_cli(); 99 // timerctl.timeout = timeout; 100 // timerctl.fifo = fifo; 101 // timerctl.data = data; 102 // io_store_eflags(eflags); 103 // return; 104 //} timer.c>_<" 這里定義一個計時器結構體和一個管理計時器的結構體,其中TIMERCTL中含有一個timer的數組,用來實現最多MAX_TIMER個計時器的管理。這里:
-
初始化的時候只是將所有的定時器的flags賦值為0
-
分配定時器函數是從開始遍歷所有定時器,一旦有未使用的就置標志為TIMER_FLAGS_ALLOC,然后返回~
-
釋放計時器只是簡單的把標志置0,恢復未使用狀態
-
計時器初始化函數是給計時器的fifo,和定時器標志賦值,這里的計時器標志是等計時器計時完畢時向fifo發送的消息,用來區分不同的計時器
-
設置定時器就是給定時器設定一個時間,然后置flags為正在使用
-
中斷處理函數每次count++實現時間累加,然后遍歷所有正在使用的定時器,讓他們的剩余時間--,如果發現剩余時間為0,就向fifo發送對應消息~
PS: 很顯然,這種處理速度是很慢很慢的!接下來要一步步的優化~
?
2、有序數組[09g] ? ? ? ? ?? ?
>_<" 在bootpack.h里面的timer.c的聲明和結構體:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500個定時器 3 struct TIMER{ 4 unsigned int flags;//flags記錄各個寄存器狀態 5 unsigned int timeout;//用來記錄離超時還有多長時間,一旦這個剩余時間為0,程序就往FIFO緩沖區里發送數據,定時器就是用這種方法通知HariMain時間到了 6 struct FIFO8 *fifo;//消息隊列 7 unsigned char data;//該定時器標志,用來向消息隊列寫的標志信息 8 }; 9 struct TIMERCTL { 10 unsigned int count, next, using;//using表示有幾個定時器處于活動中,next是下一個設定時間點,count是累加時間軸 11 struct TIMER *timers[MAX_TIMER];//記錄按照某種順序存好的定時器地址 12 struct TIMER timers0[MAX_TIMER]; 13 }; 14 extern struct TIMERCTL timerctl; 15 void init_pit(void);//定時器初始化100hz 16 struct TIMER *timer_alloc(void);//分配定時器,遍歷所有找到第一個沒有使用的分配 17 void timer_free(struct TIMER *timer);//釋放定時器 18 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data);//初始化定時器,fifo和標志符data 19 void timer_settime(struct TIMER *timer, unsigned int timeout);//定時器設置,設定剩余時間 20 void inthandler20(int *esp);//定時器中斷函數 21 //void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data);//設置定時器 1 /* PIT 定時器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//計數器結構體實例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置狀態 11 #define TIMER_FLAGS_USING 2 //定時器運行中 12 13 / 14 //功能:定時器初始化,要3次OUT指令,(0x34->0x34)(中斷周期低8位->0x40)(高8位->0x40) 15 //參數: 16 //附加:設置結果為主頻/設置數,這里中斷周期設置為0x2e9c,大約為100hz,具體搜:IRQ0中斷周期變更PIT 17 void init_pit(void) 18 { 19 int i; 20 io_out8(PIT_CTRL, 0x34); 21 io_out8(PIT_CNT0, 0x9c); 22 io_out8(PIT_CNT0, 0x2e); 23 timerctl.count=0;//初始化計數為0 24 timerctl.next=0xffffffff;//初始時沒有計時器所以下一個為無窮大 25 timerctl.using=0;//正在使用的定時器為0 26 27 for(i=0;i<MAX_TIMER;i++){//初始化所有定時器未使用 28 timerctl.timers0[i].flags=0;//未使用 29 } 30 return; 31 } 32 / 33 //功能:分配定時器 34 //參數: 35 struct TIMER *timer_alloc(void) 36 { 37 int i; 38 for (i = 0; i < MAX_TIMER; i++) {//從開始開始找沒有使用的定時器,找到后設置為分配狀態,反回 39 if (timerctl.timers0[i].flags == 0) { 40 timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; 41 return &timerctl.timers0[i]; 42 } 43 } 44 return 0; /* 沒有找到 */ 45 } 46 / 47 //功能:釋放定時器,直接把標志位設為0即可 48 //參數: 49 void timer_free(struct TIMER *timer) 50 { 51 timer->flags = 0; /* 未使用 */ 52 return; 53 } 54 / 55 //功能:初始化定時器,賦值fifo,設置標志位 56 //參數: 57 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data) 58 { 59 timer->fifo = fifo; 60 timer->data = data; 61 return; 62 } 63 / 64 //功能:設置timer 65 //參數:輸入定時時間 66 void timer_settime(struct TIMER *timer, unsigned int timeout) 67 { 68 int e, i, j; 69 timer->timeout = timeout + timerctl.count;//當前時間+定時器定時時間 70 timer->flags = TIMER_FLAGS_USING;//設置成正在使用 71 e = io_load_eflags();//保存寄存器,關中斷 72 io_cli(); 73 /* 搜索注冊位置 */ 74 for (i = 0; i < timerctl.using; i++) {//把所有timeout從小到大排列,找出新建的定時器插入位置 75 if (timerctl.timers[i]->timeout >= timer->timeout) { 76 break; 77 } 78 } 79 /* i之后的全部后移1位 */ 80 for (j = timerctl.using; j > i; j--) { 81 timerctl.timers[j] = timerctl.timers[j - 1]; 82 } 83 timerctl.using++; 84 /* 插入到空位上 */ 85 timerctl.timers[i] = timer; 86 timerctl.next = timerctl.timers[0]->timeout; 87 io_store_eflags(e);//恢復寄存器 88 return; 89 } 90 91 92 / 93 //功能:定時器中斷處理程序,和鍵盤鼠標中斷類似 94 //參數: 95 void inthandler20(int *esp) 96 { 97 int i,j; 98 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信號接受完了的信息通知給PIC */ 99 timerctl.count++;//計數 100 if(timerctl.next>timerctl.count){//如果下一個還沒計數完畢就直接返回 101 return; 102 } 103 for(i=0;i<timerctl.using;i++){ 104 if(timerctl.timers[i]->timeout>timerctl.count){ 105 break; 106 }//從前往后遍歷,一旦發現有計時未完成的計時器就跳出循環 107 /*除了上面的情況,都是定時已達的定時器*/ 108 timerctl.timers[i]->flags = TIMER_FLAGS_ALLOC; 109 fifo8_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data); 110 } 111 /*從上面循環結束后,i的值就是前面有幾個超時的定時器*/ 112 timerctl.using-=i;//所以減去超時的定時器 113 for(j=0;j<timerctl.using;j++){//將后面的定時器前移 114 timerctl.timers[j]=timerctl.timers[i+j]; 115 } 116 if(timerctl.using>0){//判斷是否還有正在使用的定時器,有就用下一個剩余時間更新next 117 timerctl.next=timerctl.timers[0]->timeout; 118 }else{//沒有,就直接設為無窮大 119 timerctl.next=0xffffffff; 120 } 121 return; 122 } timer.c>_<" 這里和上一個的最大的不同之處是:上一個采用暴力遍歷每一個的情況,而這個則采用插入和刪除等操作時就事先調整好數組。此外為了方便實現這一數據結構,TIMERCTL里除了用timers0[]數組保存計時器外,還聲明一個timers[]數組用來記錄按照某種順序排好的定時器,這里的using是出于活動中的定時器數,next是下一個設定的時間:
-
初始化函數改變比較少,只是加了個using=0,next=0xffffffff等初始化賦值操作
-
分配定時器基本無變化
-
設定時間函數則從前往后遍歷查找該新的定時器要插入的位置,因為這里是有序排列的,而且只遍歷正在使用中的定時器,所以比上一個純暴力要快
-
中斷函數,是將當前前面的已經超時的定時器發送消息及取消使用狀態,然后從有序列表里面刪除這些(具體做法就是前移后面的部分覆蓋這部分超時的部分)
?
3、線性表[10h] ? ? ? ? ? ? ? ? ??
>_<" 在bootpack.h里面的timer.c的聲明和結構體:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500個定時器 3 struct TIMER{ 4 struct TIMER *next;//用來指下一個即將超時的定時器地址 5 unsigned int flags;//flags記錄各個寄存器狀態 6 unsigned int timeout;//用來記錄離超時還有多長時間,一旦這個剩余時間為0,程序就往FIFO緩沖區里發送數據,定時器就是用這種方法通知HariMain時間到了 7 struct FIFO32 *fifo;//消息隊列 8 int data;//該定時器標志,用來向消息隊列寫的標志信息 9 }; 10 struct TIMERCTL { 11 unsigned int count, next, using;//using表示有幾個定時器處于活動中,next是下一個設定時間點,count是累加時間軸 12 struct TIMER *t0;//記錄按照某種順序存好的定時器地址,頭指針 13 struct TIMER timers0[MAX_TIMER]; 14 }; 15 extern struct TIMERCTL timerctl; 16 void init_pit(void);//定時器初始化100hz 17 struct TIMER *timer_alloc(void);//分配定時器,遍歷所有找到第一個沒有使用的分配 18 void timer_free(struct TIMER *timer);//釋放定時器 19 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data);//初始化定時器,fifo和標志符data 20 void timer_settime(struct TIMER *timer, unsigned int timeout);//定時器設置,設定剩余時間 21 void inthandler20(int *esp);//定時器中斷函數 1 /* PIT 定時器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//計數器結構體實例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置狀態 11 #define TIMER_FLAGS_USING 2 //定時器運行中 12 13 / 14 //功能:定時器初始化,要3次OUT指令,(0x34->0x34)(中斷周期低8位->0x40)(高8位->0x40) 15 //參數: 16 //附加:設置結果為主頻/設置數,這里中斷周期設置為0x2e9c,大約為100hz,具體搜:IRQ0中斷周期變更PIT 17 void init_pit(void) 18 { 19 int i; 20 io_out8(PIT_CTRL, 0x34); 21 io_out8(PIT_CNT0, 0x9c); 22 io_out8(PIT_CNT0, 0x2e); 23 timerctl.count=0;//初始化計數為0 24 timerctl.next=0xffffffff;//初始時沒有計時器所以下一個為無窮大 25 timerctl.using=0;//正在使用的定時器為0 26 27 for(i=0;i<MAX_TIMER;i++){//初始化所有定時器未使用 28 timerctl.timers0[i].flags=0;//未使用 29 } 30 return; 31 } 32 / 33 //功能:分配定時器 34 //參數: 35 struct TIMER *timer_alloc(void) 36 { 37 int i; 38 for (i = 0; i < MAX_TIMER; i++) {//從開始開始找沒有使用的定時器,找到后設置為分配狀態,反回 39 if (timerctl.timers0[i].flags == 0) { 40 timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; 41 return &timerctl.timers0[i]; 42 } 43 } 44 return 0; /* 沒有找到 */ 45 } 46 / 47 //功能:釋放定時器,直接把標志位設為0即可 48 //參數: 49 void timer_free(struct TIMER *timer) 50 { 51 timer->flags = 0; /* 未使用 */ 52 return; 53 } 54 / 55 //功能:初始化定時器,賦值fifo,設置標志位 56 //參數: 57 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) 58 { 59 timer->fifo = fifo; 60 timer->data = data; 61 return; 62 } 63 / 64 //功能:設置timer 65 //參數:輸入定時時間 66 void timer_settime(struct TIMER *timer, unsigned int timeout) 67 { 68 int e; 69 struct TIMER *t,*s; 70 timer->timeout = timeout + timerctl.count;//當前時間+定時器定時時間 71 timer->flags = TIMER_FLAGS_USING;//設置成正在使用 72 e = io_load_eflags();//保存寄存器,關中斷 73 io_cli(); 74 75 timerctl.using++; 76 if (timerctl.using == 1) { 77 /* 處于運行狀態的只有一個 */ 78 timerctl.t0 = timer; 79 timer->next = 0; /* 沒有下一個 */ 80 timerctl.next = timer->timeout; 81 io_store_eflags(e); 82 return; 83 } 84 t = timerctl.t0; 85 if (timer->timeout <= t->timeout) { 86 /* 插入最前面 */ 87 timerctl.t0 = timer; 88 timer->next = t; /* 下面是t */ 89 timerctl.next = timer->timeout; 90 io_store_eflags(e); 91 return; 92 } 93 /* 搜尋插入位置 */ 94 for (;;) { 95 s = t; 96 t = t->next; 97 if (t == 0) { 98 break; /* 最后面 */ 99 } 100 if (timer->timeout <= t->timeout) { 101 /* 插入到s和t之間 */ 102 s->next = timer; /* s的先一個是timer */ 103 timer->next = t; /* timer的下一個是t */ 104 io_store_eflags(e); 105 return; 106 } 107 } 108 /* 插入最后面的情況 */ 109 s->next = timer; 110 timer->next = 0; 111 io_store_eflags(e); 112 return; 113 } 114 115 / 116 //功能:定時器中斷處理程序,和鍵盤鼠標中斷類似 117 //參數: 118 void inthandler20(int *esp) 119 { 120 int i,j; 121 struct TIMER *timer; 122 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信號接受完了的信息通知給PIC */ 123 timerctl.count++;//計數 124 if(timerctl.next>timerctl.count){//如果下一個還沒計數完畢就直接返回 125 return; 126 } 127 timer=timerctl.t0;//把最前面的地址賦址給timer 128 for(i=0;i<timerctl.using;i++){ 129 if(timer->timeout>timerctl.count){ 130 break; 131 }//從前往后遍歷,一旦發現有計時未完成的計時器就跳出循環 132 /*除了上面的情況,都是定時已達的定時器*/ 133 timer->flags = TIMER_FLAGS_ALLOC; 134 fifo32_put(timer->fifo, timer->data); 135 timer=timer->next;//下一個定時器的地址賦址給timer 136 } 137 /*從上面循環結束后,i的值就是前面有幾個超時的定時器*/ 138 timerctl.using-=i;//所以減去超時的定時器 139 timerctl.t0=timer;//新移位 140 //timectl.next設定 141 if(timerctl.using>0){//判斷是否還有正在使用的定時器,有就用下一個剩余時間更新next 142 timerctl.next=timerctl.t0->timeout; 143 }else{//沒有,就直接設為無窮大 144 timerctl.next=0xffffffff; 145 } 146 return; 147 } timer.c>_<" 通過上面2個優化的實例發現,用數組避免不了大量數據的前移和后移,于是我們就想到了用指針來構成線性表,這樣交換插入都可以在幾步之能完成!這里在結構體TIMER里加入了*next指針,用來存放下一個即將超時的定時器地址。
-
這里中斷處理函數只是把上面數組實現的有序數組改成用指針實現的有序鏈表,這樣交換和插入數據就不用一塊一塊的移位了,直接切換一下指針就能夠完成了,所以能夠優化中斷處理能力!
-
這里的settimer函數也類似,這里不做詳細介紹,直接看代碼就能理解啦!
PS: 在使用線性表之后發現TIMERCTR結構體里的TIMER數組可以只要一個首地址就行了,于是也簡化為*t0
?
4、使用“哨兵”簡化程序[10i]
>_<" 在bootpack.h里面的timer.c的聲明和結構體:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500個定時器 3 struct TIMER{ 4 struct TIMER *next;//用來指下一個即將超時的定時器地址 5 unsigned int flags;//flags記錄各個寄存器狀態 6 unsigned int timeout;//用來記錄離超時還有多長時間,一旦這個剩余時間為0,程序就往FIFO緩沖區里發送數據,定時器就是用這種方法通知HariMain時間到了 7 struct FIFO32 *fifo;//消息隊列 8 int data;//該定時器標志,用來向消息隊列寫的標志信息 9 }; 10 struct TIMERCTL { 11 unsigned int count, next;//next是下一個設定時間點,count是累加時間軸 12 struct TIMER *t0;//記錄按照某種順序存好的定時器地址,頭指針 13 struct TIMER timers0[MAX_TIMER]; 14 }; 15 extern struct TIMERCTL timerctl; 16 void init_pit(void);//定時器初始化100hz 17 struct TIMER *timer_alloc(void);//分配定時器,遍歷所有找到第一個沒有使用的分配 18 void timer_free(struct TIMER *timer);//釋放定時器 19 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data);//初始化定時器,fifo和標志符data 20 void timer_settime(struct TIMER *timer, unsigned int timeout);//定時器設置,設定剩余時間 21 void inthandler20(int *esp);//定時器中斷函數 1 /* PIT 定時器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//計數器結構體實例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置狀態 11 #define TIMER_FLAGS_USING 2 //定時器運行中 12 13 / 14 //功能:定時器初始化,要3次OUT指令,(0x34->0x34)(中斷周期低8位->0x40)(高8位->0x40) 15 //參數: 16 //附加:設置結果為主頻/設置數,這里中斷周期設置為0x2e9c,大約為100hz,具體搜:IRQ0中斷周期變更PIT 17 void init_pit(void) 18 { 19 int i; 20 struct TIMER *t; 21 io_out8(PIT_CTRL, 0x34); 22 io_out8(PIT_CNT0, 0x9c); 23 io_out8(PIT_CNT0, 0x2e); 24 timerctl.count=0;//初始化計數為0 25 for(i=0;i<MAX_TIMER;i++){//初始化所有定時器未使用 26 timerctl.timers0[i].flags=0;//未使用 27 } 28 t=timer_alloc();//取得一個 29 t->timeout=0xffffffff; 30 t->flags=TIMER_FLAGS_USING; 31 t->next=0;//末尾 32 timerctl.t0=t;//現在就一個 33 timerctl.next=0xffffffff;//下一個計時器為哨兵,所以下一個為無窮大 34 return; 35 } 36 / 37 //功能:分配定時器 38 //參數: 39 struct TIMER *timer_alloc(void) 40 { 41 int i; 42 for (i = 0; i < MAX_TIMER; i++) {//從開始開始找沒有使用的定時器,找到后設置為分配狀態,反回 43 if (timerctl.timers0[i].flags == 0) { 44 timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; 45 return &timerctl.timers0[i]; 46 } 47 } 48 return 0; /* 沒有找到 */ 49 } 50 / 51 //功能:釋放定時器,直接把標志位設為0即可 52 //參數: 53 void timer_free(struct TIMER *timer) 54 { 55 timer->flags = 0; /* 未使用 */ 56 return; 57 } 58 / 59 //功能:初始化定時器,賦值fifo,設置標志位 60 //參數: 61 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) 62 { 63 timer->fifo = fifo; 64 timer->data = data; 65 return; 66 } 67 / 68 //功能:設置timer 69 //參數:輸入定時時間 70 void timer_settime(struct TIMER *timer, unsigned int timeout) 71 { 72 int e; 73 struct TIMER *t,*s; 74 timer->timeout = timeout + timerctl.count;//當前時間+定時器定時時間 75 timer->flags = TIMER_FLAGS_USING;//設置成正在使用 76 e = io_load_eflags();//保存寄存器,關中斷 77 io_cli(); 78 79 t=timerctl.t0; 80 if (timer->timeout <= t->timeout) { 81 /* 插入最前面的情況 */ 82 timerctl.t0 = timer; 83 timer->next = t; /* 下面是設定t */ 84 timerctl.next = timer->timeout; 85 io_store_eflags(e); 86 return; 87 } 88 /* 搜尋插入位置 */ 89 for (;;) { 90 s = t; 91 t = t->next; 92 if (timer->timeout <= t->timeout) { 93 /* 插入s和t之間 */ 94 s->next = timer; /* s下一個是timer */ 95 timer->next = t; /* timer下一個是t */ 96 io_store_eflags(e); 97 return; 98 } 99 } 100 return; 101 } 102 103 / 104 //功能:定時器中斷處理程序,和鍵盤鼠標中斷類似 105 //參數: 106 void inthandler20(int *esp) 107 { 108 struct TIMER *timer; 109 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信號接受完了的信息通知給PIC */ 110 timerctl.count++; 111 if (timerctl.next > timerctl.count) {//如果下一個還沒計數完畢就直接返回 112 return; 113 } 114 timer = timerctl.t0; //把最前面的地址賦址給timer 115 for (;;) { 116 if (timer->timeout > timerctl.count) { 117 break; 118 }//從前往后遍歷,一旦發現有計時未完成的計時器就跳出循環 119 /*除了上面的情況,都是定時已達的定時器*/ 120 timer->flags = TIMER_FLAGS_ALLOC; 121 fifo32_put(timer->fifo, timer->data); 122 timer = timer->next;//下一個定時器的地址賦址給timer 123 } 124 timerctl.t0 = timer;//新移位 125 timerctl.next = timer->timeout;//timectl.next設定 126 return; 127 } timer.c>_<" “哨兵”聽起來高大上,其實就是在10g的線性表的基礎上多加一個空結點,這樣就能把插入結點時的判斷條件減少很多,用來達到精簡代碼的目的~其實由于多了一個空結點,這種處理雖然代碼精簡了,但是其速度就沒有上面純的線性表快了~這里就不仔細介紹細節的東西了,相信大家一看就懂~
?
5、工程代碼鏈接: ? ? ? ?
包含上面項目工程的所有代碼:http://pan.baidu.com/s/1bnEkjWN
LZ主頁:http://www.cnblogs.com/zjutlitao/
1 /* 2 同一占用一個fifo,這里: 3 0~1 光標閃爍用定時器 4 3 3秒定時器 5 10 10秒定時器 6 256~511 鍵盤輸入(從鍵盤控制器讀入的值再加上256) 7 512~767 鼠標輸入(從鍵盤控制器讀入的值再加上512) 8 */?
轉載于:https://www.cnblogs.com/zjutlitao/p/3983279.html
總結
以上是生活随笔為你收集整理的[自制简单操作系统] 4、计时器(线性表实现优化中断)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新开activity并且新旧窗口之间传值
- 下一篇: 阿里云ECS部署node.js及防火墙8