<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > linux驅(qū)動(dòng)之內(nèi)核定時(shí)器驅(qū)動(dòng)設(shè)計(jì)

          linux驅(qū)動(dòng)之內(nèi)核定時(shí)器驅(qū)動(dòng)設(shè)計(jì)

          作者: 時(shí)間:2016-12-01 來(lái)源:網(wǎng)絡(luò) 收藏
          我的環(huán)境:
          Fedora 14 內(nèi)核版本為2.6.38.1
          開(kāi)發(fā)板:ARM9 TQ2440
          移植內(nèi)核版本:linux-2.6.30.4
          定時(shí)器在linux內(nèi)核中主要是采用一個(gè)結(jié)構(gòu)體實(shí)現(xiàn)的。但是需要注意定時(shí)器是一個(gè)只運(yùn)行一次的對(duì)象,也就是當(dāng)一個(gè)定時(shí)器結(jié)束以后,還需要重現(xiàn)添加定時(shí)器。但是可以采用mod_timer()函數(shù)動(dòng)態(tài)的改變定時(shí)器到達(dá)時(shí)間。
          這個(gè)驅(qū)動(dòng)主要實(shí)現(xiàn)內(nèi)核定時(shí)器的基本操作。內(nèi)核定時(shí)器主要是是通過(guò)下面的結(jié)構(gòu)體struct timer_list實(shí)現(xiàn)。需要的頭文件包括#include,但是在實(shí)際開(kāi)發(fā)過(guò)程中不需要包含該頭文件,因?yàn)樵趕ched.h中包含了該頭文件。
          struct timer_list {
          struct list_head entry;
          unsigned long expires;
          void (*function)(unsigned long);
          unsigned long data;
          struct tvec_base *base;
          #ifdef CONFIG_TIMER_STATS
          void *start_site;
          char start_comm[16];
          int start_pid;
          #endif
          #ifdef CONFIG_LOCKDEP
          struct lockdep_map lockdep_map;
          #endif
          };
          定時(shí)器的實(shí)現(xiàn)主要是該結(jié)構(gòu)體的填充和部分函數(shù)的配合即可完成。其中紅色的部分是最主要的幾個(gè)元素,1、expires主要是用來(lái)定義定時(shí)器到期的時(shí)間,通常采用jiffies這個(gè)全局變量和HZ這個(gè)全局變量配合設(shè)置該元素的值。比如expires = jiffies + n*HZ,其中jiffies是自啟動(dòng)以來(lái)的滴答數(shù),HZ是一秒種的滴答數(shù)。
          2、function可以知道是一個(gè)函數(shù)指針,該函數(shù)就是定時(shí)器的處理函數(shù),類(lèi)似我們?cè)谥袛嘀械闹袛嗪瘮?shù),其實(shí)定時(shí)器和中斷有很大的相似性。定時(shí)器處理函數(shù)是自己定義的函數(shù)。
          3、data通常是實(shí)現(xiàn)參數(shù)的傳遞,從function的參數(shù)類(lèi)型可以知道,data可以作為定時(shí)器處理函數(shù)的參數(shù)。
          其他的元素可以通過(guò)內(nèi)核的函數(shù)來(lái)初始化。
          初始化函數(shù)為:
          init_timer(struct timer_list * timer);
          或者直接DEFINE_TIMER宏實(shí)現(xiàn)定義和初始化操作。
          #define DEFINE_TIMER(_name, _function, _expires, _data)
          struct timer_list _name =
          TIMER_INITIALIZER(_function, _expires, _data)
          添加定時(shí)器到內(nèi)核的函數(shù):
          void add_timer(struct timer_list *timer)
          {
          BUG_ON(timer_pending(timer));
          mod_timer(timer, timer->expires);
          }
          刪除定時(shí)器函數(shù),如果定時(shí)器的定時(shí)時(shí)間還沒(méi)有到達(dá),那么才可以刪除定時(shí)器:
          int del_timer(struct timer_list *timer)
          修改定時(shí)器的到達(dá)時(shí)間,該函數(shù)的特點(diǎn)是,不管定時(shí)器是否到達(dá)時(shí)間,都會(huì)重現(xiàn)添加一個(gè)定時(shí)器到內(nèi)核。所以可以在定時(shí)處理函數(shù)中可以調(diào)用該函數(shù)修改需要重新定義的到達(dá)時(shí)間。
          int mode_timer(struct timer_list *timer,unsigned long expires)
          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->expires == expires && timer_pending(timer))
          return 1;
          /*注意調(diào)用的條件,也就是說(shuō)明當(dāng)前的定時(shí)器為鏈表的最后一個(gè)*/
          return __mod_timer(timer, expires, false);
          }
          static inline int
          __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
          {
          struct tvec_base *base, *new_base;
          unsigned long flags;
          int ret;
          ret = 0;
          timer_stats_timer_set_start_info(timer);
          BUG_ON(!timer->function);
          base = lock_timer_base(timer, &flags);
          if (timer_pending(timer)) {
          detach_timer(timer, 0);
          ret = 1;
          } else {
          if (pending_only)
          goto out_unlock;
          }
          debug_timer_activate(timer);
          new_base = __get_cpu_var(tvec_bases);
          if (base != new_base) {
          /*
          * We are trying to schedule the timer on the local CPU.
          * However we cant change timers base while it is running,
          * otherwise del_timer_sync() cant detect that the timers
          * handler yet has not finished. This also guarantees that
          * the timer is serialized wrt itself.
          */
          if (likely(base->running_timer != timer)) {
          /* See the comment in lock_timer_base() */
          timer_set_base(timer, NULL);
          spin_unlock(&base->lock);
          base = new_base;
          spin_lock(&base->lock);
          timer_set_base(timer, base);
          }
          }
          timer->expires = expires;
          internal_add_timer(base, timer);
          out_unlock:
          spin_unlock_irqrestore(&base->lock, flags);
          return ret;
          }
          static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
          {
          unsigned long expires = timer->expires;
          unsigned long idx = expires - base->timer_jiffies;
          struct list_head *vec;
          if (idx < TVR_SIZE) {
          int i = expires & TVR_MASK;
          vec = base->tv1.vec + i;
          } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
          int i = (expires >> TVR_BITS) & TVN_MASK;
          vec = base->tv2.vec + i;
          } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
          int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
          vec = base->tv3.vec + i;
          } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
          int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
          vec = base->tv4.vec + i;
          } else if ((signed long) idx < 0) {
          /*
          * Can happen if you add a timer with expires == jiffies,
          * or you set a timer to go off in the past
          */
          vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
          } else {
          int i;
          /* If the timeout is larger than 0xffffffff on 64-bit
          * architectures then we use the maximum timeout:
          */
          if (idx > 0xffffffffUL) {
          idx = 0xffffffffUL;
          expires = idx + base->timer_jiffies;
          }
          i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
          vec = base->tv5.vec + i;
          }
          /*
          * Timers are FIFO:
          */
          /*添加到鏈表的最后,這說(shuō)明mod_timer實(shí)現(xiàn)了重新注冊(cè)一個(gè)定時(shí)器的操作*/
          list_add_tail(&timer->entry, vec);
          }
          從上面的分析可以看出,mod_timer的實(shí)現(xiàn)過(guò)程比較復(fù)雜,但是基本上說(shuō)明了mod_timer函數(shù)重新注冊(cè)定時(shí)器的操作過(guò)程。
          一般而言定時(shí)器的基本操作主要是上面的幾個(gè)函數(shù)。
          我的基于內(nèi)核定時(shí)器的驅(qū)動(dòng)函數(shù)如下,參考了宋寶華的Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)詳解(第二版)。
          上一頁(yè) 1 2 下一頁(yè)

          評(píng)論


          技術(shù)專(zhuān)區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();