timer_pending( )作用及实现机制

本文详细解释了Linux内核中的定时器机制,重点介绍了timer_pending和add_timer的功能及其实现原理,阐述了定时器对象的状态变化及其管理队列中的调度执行过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转:http://blog.chinaunix.net/uid-7332782-id-3219565.html

源码如下:

int mod_timer(struct timer_list *timer, unsigned long expires)
{
    /*
     * This is a common optimization triggered by the
     * networking code - if the timer is re-modified
     * to be the same thing then just return:
     */
    if (timer_pending(timer) && timer->expires == expires)
        return 1;

    return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
}

(timer_pending(timer)   《深入Linux设备驱动程序内核机制》第八章 <时间管理>关于定时器部分的叙述:


一个处于pending状态的定时器是处在处理器的定时器管理队列中正等待被调度执行的定时器对象。如果一个要被del_timer函数删除的timer对象已经被调度执行了(内核源码称这种定时器状态为inactive),函数将直接返回0,否则函数将通过detach_timer将该定时器对象从队列中删除掉。在多处理器的SMP系统中,del_timer_sync函数要完成的任务除了同del_timer一样从定时器队列中删除一个定时器对象外,它还会确保当函数返回时系统中没有任何处理器正在执行定时器对象上的定时器函数,而如果只是调用del_timer,那么当del_timer函数返回时,被删除的定时器对象的定时器函数可能正在其他处理器上运行。”

所以timer_pending是用来判断一个处在定时器管理队列中的定时器对象是否已经被调度执行add_timer只是把一个定时器对象加入到内核的管理队列,但是何时执行实际上由时钟中断(更确切地,是内核在时钟中断的softirq部分才开始扫描定时器管理队列)一个定时器对象pending意味着它的回调函数尚未被调度执行,而一旦一个定时器对象被调度执行,之后它将被从定时器管理队列中摘除,除非它再次被提交。




在这个代码上增加一个功能叫闹钟,进入功能数码管显示0000,K1按键按一开始正计时(计时1分钟);K2按键按一下进行位选用小数点来控;K3按键按一进行段选,每按一下加一;K4按键按一下清零(重新进入闹钟功能)。K4按键连选双按一下切换功能;功能顺序是计算器,秒表,定时器。下载程序到单片机里面,一开始功能是计算器功能。工作流程:以按一下K2进行位选用小数点控制,K3进行段选,按一下加1→ K1按一下确认 显示0000进入运算符选择→ 按一下K1,显示运算符(加号显示1111,减号显示2222,乘号显示3333,除号显示44444) → K2确认显示0000 → 输入第二个数 → K4确认 → 显示结果,K4在按一下重新计算。双击一下K4,进入秒表功能,数码管显示0001,按一下K1正计时以一秒的形式加一,按一下K2到计时以一秒的形式加一,按一下K3暂停,按一下K4清0。在双击一下K4按键,进入定时器功能,数码管显示000.0,按一下K2进行位选用小数点来控,K3进行段选,按一下加1(例如:我输入了2010,意思是20分钟10秒)→按一下K1开始以一秒的形式开始倒计时会显示(20.10),开始以一秒倒计时,在按一下K1清零,数码管显示00.00。在双击一下K4,进入闹钟模式,数码管显示000.0,按一下K2进行位选用小数点来控,K3进行段选,按一下加1(例如:我输入了0810,意思8点10分,代表开始的时间)→按一下K1开始计时,数码管显示0000,然后开始计时(0000→0001→0002…一直计时一分钟),一分钟过后,数码管开始显示08.11反复闪烁(相当于在个位加了一),按一下K4清零,重新输入。双击一下K4,又回到计算器功能,在代码中可以根改一下延迟函数。下面代码已经有计算器功能,秒表功能,定时器功能。代码符合以下程序。帮我重新写一份#include <REGX51.H> // 共阳数码管段码表(0-9) unsigned char cc[10] = {0Xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; // 状态定义 #define STATE_INPUT_NUM1 0 // 输入第一个数 #define STATE_SELECT_OP 1 // 选择运算符 #define STATE_INPUT_NUM2 2 // 输入第二个数 #define STATE_SHOW_RESULT 3 // 显示结果 // 模式定义 #define MODE_CALCULATOR 0 #define MODE_STOPWATCH 1 #define MODE_TIMER 2 // 全局变量 unsigned char current_mode = MODE_CALCULATOR; unsigned char current_state = STATE_INPUT_NUM1; unsigned char current_operator = 0; unsigned char current_digit = 0; unsigned char input_num[4] = {0,0,0,0}; unsigned long num1 = 0, num2 = 0; // 秒表相关变量 unsigned int stopwatch_time = 0; bit stopwatch_running = 0; bit stopwatch_dir = 0; // 0:正计时 1:倒计时 // 定时器相关变量 unsigned char timer_digits[4] = {0,0,0,0}; unsigned char timer_edit_pos = 0; unsigned int timer_remaining = 0; bit timer_running = 0; // 按键检测相关 volatile unsigned int ms_counter = 0; bit k4_pending = 0; unsigned int k4_pending_time = 0; void Delay(unsigned int xms) { while(xms–) { unsigned char i = 2, j = 239; do { while(–j); } while(–i); } } void timer0_init() { TMOD = 0x01; // 定时器0模式1 TH0 = 0x3C; // 50ms定时初值 TL0 = 0xB0; ET0 = 1; // 允许定时器0中断 EA = 1; // 开总中断 TR0 = 1; // 启动定时器 } void nn(unsigned char location, unsigned char num, bit show_dp) { P1 = 0xFF; switch(location) { case 1: P1_0 = 0; break; case 2: P1_1 = 0; break; case 3: P1_2 = 0; break; case 4: P1_3 = 0; break; } P2 = show_dp ? (cc[num] & 0x7F) : cc[num]; Delay(1); P2 = 0xFF; } void resetInput() { input_num[0] = input_num[1] = input_num[2] = input_num[3] = 0; current_digit = 0; } void handleCalculatorKeys() { // K1处理 if (!P3_4) { Delay(20); if (!P3_4) { if(current_state == STATE_SELECT_OP) { current_operator = (current_operator + 1) % 4; } while(!P3_4); } } // K2处理 if (!P3_5) { Delay(20); if (!P3_5) { if(current_state == STATE_SELECT_OP) { current_state = STATE_INPUT_NUM2; resetInput(); } else { current_digit = (current_digit + 1) % 4; } while(!P3_5); } } // K3处理 if (!P3_6) { Delay(20); if (!P3_6) { if(current_state != STATE_SHOW_RESULT) { input_num[3 - current_digit] = (input_num[3 - current_digit] + 1) % 10; } while(!P3_6); } } } void handleStopwatchKeys() { // K1: 正计时 if (!P3_4) { Delay(20); if (!P3_4) { stopwatch_dir = 0; stopwatch_running = 1; while(!P3_4); } } // K2: 倒计时 if (!P3_5) { Delay(20); if (!P3_5) { stopwatch_dir = 1; stopwatch_running = 1; while(!P3_5); } } // K3: 暂停/继续 if (!P3_6) { Delay(20); if (!P3_6) { stopwatch_running = !stopwatch_running; while(!P3_6); } } } void handleTimerKeys() { // K1: 开始/停止倒计时 if (!P3_4) { Delay(20); if (!P3_4) { if (!timer_running) { unsigned char minutes = timer_digits[0]*10 + timer_digits[1]; unsigned char seconds = timer_digits[2]*10 + timer_digits[3]; timer_remaining = minutes * 60 + seconds; if (timer_remaining > 0) timer_running = 1; } else { timer_running = 0; timer_remaining = 0; for(int i=0; i<4; i++) timer_digits[i] = 0; timer_edit_pos = 0; } while(!P3_4); } } // K2: 切换编辑位 if (!P3_5) { Delay(20); if (!P3_5) { timer_edit_pos = (timer_edit_pos + 1) % 4; while(!P3_5); } } // K3: 当前位加1 if (!P3_6) { Delay(20); if (!P3_6) { timer_digits[timer_edit_pos] = (timer_digits[timer_edit_pos] + 1) % 10; while(!P3_6); } } } void checkKeys() { // K4处理(模式切换) if (!P3_7) { Delay(20); if (!P3_7) { if(k4_pending) { k4_pending = 0; current_mode = (current_mode + 1) % 3; if(current_mode == MODE_STOPWATCH) { stopwatch_time = 0; stopwatch_running = 0; } else if(current_mode == MODE_CALCULATOR) { current_state = STATE_INPUT_NUM1; resetInput(); } else { for(int i=0;i<4;i++) timer_digits[i]=0; timer_edit_pos = timer_running = timer_remaining =0; } } else { k4_pending = 1; k4_pending_time = ms_counter; } while(!P3_7); } } switch(current_mode) { case MODE_CALCULATOR: handleCalculatorKeys(); break; case MODE_STOPWATCH: handleStopwatchKeys(); break; case MODE_TIMER: handleTimerKeys(); break; } } void displayCalculator() { switch(current_state) { case STATE_SELECT_OP: nn(1, current_operator+1, 0); nn(2, current_operator+1, 0); nn(3, current_operator+1, 0); nn(4, current_operator+1, 0); break; case STATE_SHOW_RESULT: nn(1, input_num[0], 0); nn(2, input_num[1], 0); nn(3, input_num[2], 0); nn(4, input_num[3], 0); break; default: nn(1, input_num[0], (current_digit==3)); nn(2, input_num[1], (current_digit==2)); nn(3, input_num[2], (current_digit==1)); nn(4, input_num[3], (current_digit==0)); } } void displayStopwatch() { unsigned char digits[4]; digits[0] = (stopwatch_time / 1000) % 10; digits[1] = (stopwatch_time / 100) % 10; digits[2] = (stopwatch_time / 10) % 10; digits[3] = stopwatch_time % 10; nn(1, digits[0], 0); nn(2, digits[1], 0); nn(3, digits[2], 0); nn(4, digits[3], 0); } void displayTimer() { if(timer_running) { unsigned char min = timer_remaining / 60; unsigned char sec = timer_remaining % 60; unsigned char d1 = min/10, d2 = min%10; unsigned char d3 = sec/10, d4 = sec%10; nn(1, d1, 0); nn(2, d2, 1); nn(3, d3, 0); nn(4, d4, 0); } else { nn(1, timer_digits[0], (timer_edit_pos==0)); nn(2, timer_digits[1], (timer_edit_pos==1)); nn(3, timer_digits[2], (timer_edit_pos==2)); nn(4, timer_digits[3], (timer_edit_pos==3)); } } void calculateResult() { unsigned long result = 0; switch(current_operator) { case 0: result = num1 + num2; break; case 1: result = (num1 > num2) ? num1 - num2 : 0; break; case 2: result = num1 * num2; break; case 3: result = (num2 != 0) ? num1 / num2 : 0; break; } input_num[3] = result % 10; input_num[2] = (result / 10) % 10; input_num[1] = (result / 100) % 10; input_num[0] = (result / 1000) % 10; } void timer0_isr() interrupt 1 { static unsigned int count = 0; TH0 = 0x3C; TL0 = 0xB0; count++; ms_counter += 50; if(count >= 20) { count = 0; if(current_mode == MODE_STOPWATCH && stopwatch_running) { if(stopwatch_dir) { if(stopwatch_time > 0) stopwatch_time--; else stopwatch_running = 0; } else stopwatch_time = (stopwatch_time +1) % 10000; } if(current_mode == MODE_TIMER && timer_running && timer_remaining >0) timer_remaining--; } if(k4_pending && (ms_counter - k4_pending_time >= 500)) { switch(current_mode) { case MODE_CALCULATOR: switch(current_state) { case STATE_INPUT_NUM1: num1 = input_num[0]*1000 + input_num[1]*100 + input_num[2]*10 + input_num[3]; resetInput(); current_state = STATE_SELECT_OP; break; case STATE_INPUT_NUM2: num2 = input_num[0]*1000 + input_num[1]*100 + input_num[2]*10 + input_num[3]; current_state = STATE_SHOW_RESULT; break; case STATE_SHOW_RESULT: resetInput(); current_state = STATE_INPUT_NUM1; break; } break; case MODE_STOPWATCH: stopwatch_time = 0; stopwatch_running = 0; break; case MODE_TIMER: for(int i=0;i<4;i++) timer_digits[i]=0; timer_edit_pos = timer_remaining = timer_running =0; break; } k4_pending = 0; } } void main() { timer0_init(); while(1) { checkKeys(); switch(current_mode) { case MODE_CALCULATOR: if(current_state == STATE_SHOW_RESULT) calculateResult(); displayCalculator(); break; case MODE_STOPWATCH: displayStopwatch(); break; case MODE_TIMER: displayTimer(); break; } } }
05-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值