青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天下

記錄修行的印記

[原]linux中斷處理(2)下半部機制:tasklet

[原]linux中斷處理(2)下半部機制:tasklet
1.softirq 
適用于性能敏感的子系統

2.tasklet
建立在softirq之上,使用更簡單
softirq的不同實例可運行在不同的處理器上,而tasklet則不允許
必須使用define DECLARE_TASKLET 聲明tasklet
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

void short_do_tasklet(unsigned long);
DECLARE_TASKLET(short_do_tasklet,short_tasklet,0);

3. 工作隊列(work queue)
struct work_struct my_work;      //定義一個工作隊列
void my_work_func(unsigned long); //定義一個處理函數



頭文件
#include <linux/interrupt.h>
/* Tasklets --- multithreaded analogue of BHs.

Main feature differing them of generic softirqs: tasklet
is running only on one CPU simultaneously.

Main feature differing them of BHs: different tasklets
may be run simultaneously on different CPUs.

Properties:
* If tasklet_schedule() is called, then tasklet is guaranteed
to be executed on some cpu at least once after this.
* If the tasklet is already scheduled, but its excecution is still not
started, it will be executed only once.
* If this tasklet is already running on another CPU (or schedule is called
from tasklet itself), it is rescheduled for later.
* Tasklet is strictly serialized wrt itself, but not
wrt another tasklets. If client needs some intertask synchronization,
he makes it with spinlocks.
*/

struct tasklet_struct
{
    struct tasklet_struct *next;
    unsigned long state;
    atomic_t count;
    void (*func)(unsigned long);
    unsigned long data;
};

#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }


使用示例:
static atomic_t fpstatues;
static atomic_t has_image = {0};

static void gc0303_vsync_do_tasklet(ulong data)
{
    ulong curr = gettickcount();
    debug("curr:%lu",curr);

    if (atomic_read(&fpstatues)==0)
    {
        s3c2410_dma_ctrl(DMACH_XD0, S3C2410_DMAOP_FLUSH);
        gc0303_dma_buf.dma_addr = img_phys;
        gc0303_dma_buf.size = bmp_w*bmp_h;
        s3c2410_dma_enqueue(DMACH_XD0, 
            (void *)&gc0303_dma_buf, 
            gc0303_dma_buf.dma_addr, 
            gc0303_dma_buf.size);
        atomic_set(&fpstatues,1);
    }
}

DECLARE_TASKLET(gc0303_vsync_tasklet,gc0303_vsync_do_tasklet,0);

static irqreturn_t gc0303_vsync_handler(int irq,void* dev_id)
{
    if (atomic_read(&fpstatues)==1)
    {
        s3c2410_dma_ctrl(DMACH_XD0, S3C2410_DMAOP_START);
    }
    //調度gc0303_vsync_tasklet
    tasklet_schedule(&gc0303_vsync_tasklet);
    return IRQ_HANDLED;
}






tasklet是作為中斷下半部的一個很好的選擇,它在性能和易用性之間有著很好的平衡。較之于softirq,tasklet不需要考慮SMP下的并行問題,而又比workqueues有著更好的性能。
tasklet通常作為硬中斷的下半部來使用,在硬中斷中調用tasklet_schedule(t)。每次硬中斷都會觸發一次tasklet_schedule(t),但是每次中斷它只會向其中的一個CPU注冊,而不是所有的CPU。完成注冊后的tasklet由tasklet_action()來執行,在SMP環境下,它保證同一時刻,同一個tasklet只有一個副本在運行,這樣就避免了使用softirq所要考慮的互斥的問題。再者,tasklet在執行tasklet->func()前,再一次允許tasklet可調度(注冊),但是在該tasklet已有一個副本在其他CPU上運行的情況下,它只能退后執行。總之,同一個硬中斷引起的一個tasklet_schedule()動作只會使一個tasklet被注冊,而不同中斷引起的tasklet則可能在不同的時刻被注冊而多次被執行。

tasklet的互斥。由于同一個tasklet不能有多個副本同時運行,所以不需要在多CPU之間互斥。在tasklet運行的過程中,它會被硬中斷打斷(這也是軟中斷的優點),所以如果tasklet和其他中斷之間的互斥有可能存在。
中斷服務程序一般都是在中斷請求關閉的條件下執行的,以避免嵌套而使中斷控制復雜化。但是,中斷是一個隨機事件,它隨時會到來,如果關中斷的時間太長,CPU就不能及時響應其他的中斷請求,從而造成中斷的丟失。因此,Linux內核的目標就是盡可能快的處理完中斷請求,盡其所能把更多的處理向后推遲。例如,假設一個數據塊已經達到了網線,當中斷控制器接受到這個中斷請求信號時,Linux內核只是簡單地標志數據到來了,然后讓處理器恢復到它以前運行的狀態,其余的處理稍后再進行(如把數據移入一個緩沖區,接受數據的進程就可以在緩沖區找到數據)。因此,內核把中斷處理分為兩部分:上半部(tophalf)和下半部(bottomhalf),上半部(就是中斷服務程序)內核立即執行,而下半部(就是一些內核函數)留著稍后處理,

首先,一個快速的“上半部”來處理硬件發出的請求,它必須在一個新的中斷產生之前終止。通常,除了在設備和一些內存緩沖區(如果你的設備用到了DMA,就不止這些)之間移動或傳送數據,確定硬件是否處于健全的狀態之外,這一部分做的工作很少。

下半部運行時是允許中斷請求的,而上半部運行時是關中斷的,這是二者之間的主要區別。

但是,內核到底什時候執行下半部,以何種方式組織下半部?這就是我們要討論的下半部實現機制,這種機制在內核的演變過程中不斷得到改進,在以前的內核中,這個機制叫做bottomhalf(簡稱bh),在2.4以后的版本中有了新的發展和改進,改進的目標使下半部可以在多處理機上并行執行,并有助于驅動程序的開發者進行驅動程序的開發。下面主要介紹常用的小任務(Tasklet)機制及2.6內核中的工作隊列機制。

這里的小任務是指對要推遲執行的函數進行組織的一種機制。其數據結構為tasklet_struct,每個結構代表一個獨立的小任務,其定義如下:
structtasklet_struct {
    structtasklet_struct *next;         /*指向鏈表中的下一個結構*/
    unsignedlong state;                 /* 小任務的狀態*/
    atomic_t count;                        /* 引用計數器*/
    void(*func) (unsigned long);        /* 要調用的函數*/
    unsignedlong data;                  /* 傳遞給函數的參數*/
};
結構中的func域就是下半部中要推遲執行的函數,data是它唯一的參數。
state域的取值為TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任務已被調度,正準備投入運行,TASKLET_STATE_RUN表示小任務正在運行。TASKLET_STATE_RUN只有在多處理器系統上才使用,單處理器系統什么時候都清楚一個小任務是不是正在運行(它要么就是當前正在執行的代碼,要么不是)。
count 域是小任務的引用計數器。如果它不為0,則小任務被禁止,不允許執行;只有當它為零,小任務才被激活,并且在被設置為掛起時,小任務才能夠執行。
1. 聲明和使用小任務大多數情況下,為了控制一個尋常的硬件設備,小任務機制是實現下半部的最佳選擇。小任務可以動態創建,使用方便,執行起來也比較快。
我們既可以靜態地創建小任務,也可以動態地創建它。選擇那種方式取決于到底是想要對小任務進行直接引用還是一個間接引用。如果準備靜態地創建一個小任務(也就是對它直接引用),使用下面兩個宏中的一個:
DECLARE_TASKLET(name,func, data)
DECLARE_TASKLET_DISABLED(name,func, data)
這兩個宏都能根據給定的名字靜態地創建一個tasklet_struct結構。當該小任務被調度以后,給定的函數func會被執行,它的參數由data給出。這兩個宏之間的區別在于引用計數器的初始值設置不同。第一個宏把創建的小任務的引用計數器設置為0,因此,該小任務處于激活狀態。另一個把引用計數器設置為1,所以該小任務處于禁止狀態。例如:
DECLARE_TASKLET(my_tasklet,my_tasklet_handler, dev);
這行代碼其實等價于
struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),tasklet_handler,dev};
這樣就創建了一個名為my_tasklet的小任務,其處理程序為tasklet_handler,并且已被激活。當處理程序被調用的時候,dev就會被傳遞給它。
2.  編寫自己的小任務處理程序小任務處理程序必須符合如下的函數類型:
void tasklet_handler(unsigned long data)
由于小任務不能睡眠,因此不能在小任務中使用信號量或者其它產生阻塞的函數。但是小任務運行時可以響應中斷。
3. 調度自己的小任務通過調用tasklet_schedule()函數并傳遞給它相應的tasklt_struct指針,該小任務就會被調度以便適當的時候執行:
tasklet_schedule(&my_tasklet);        /*把my_tasklet標記為掛起 */
在小任務被調度以后,只要有機會它就會盡可能早的運行。在它還沒有得到運行機會之前,如果一個相同的小任務又被調度了,那么它仍然只會運行一次。
可以調用tasklet_disable()函數來禁止某個指定的小任務。如果該小任務當前正在執行,這個函數會等到它執行完畢再返回。調用tasklet_enable()函數可以激活一個小任務,如果希望把以DECLARE_TASKLET_DISABLED()創建的小任務激活,也得調用這個函數,如:
tasklet_disable(&my_tasklet);        /*小任務現在被禁止,這個小任務不能運行*/
tasklet_enable(&my_tasklet);        /*  小任務現在被激活*/
也可以調用tasklet_kill()函數從掛起的隊列中去掉一個小任務。該函數的參數是一個指向某個小任務的tasklet_struct的長指針。在小任務重新調度它自身的時候,從掛起的隊列中移去已調度的小任務會很有用。這個函數首先等待該小任務執行完畢,然后再將它移去。
4.tasklet的簡單用法
下面是tasklet的一個簡單應用,以模塊的形成加載。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>

static struct tasklet_struct my_tasklet;

static void tasklet_handler (unsigned long d ata)
{
    printk("tasklet_handler is running.\n");
}

static int __init test_init(void)
{
    tasklet_init(&my_tasklet,tasklet_handler,0);
    tasklet_schedule(&my_tasklet);
    return0;
}

static  void __exit test_exit(void)
{
    tasklet_kill(&tasklet);
    printk("test_exit is running.\n");
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);

從這個例子可以看出,所謂的小任務機制是為下半部函數的執行提供了一種執行機制,也就是說,推遲處理的事情是由tasklet_handler實現,何時執行,經由小任務機制封裝后交給內核去處理。

posted on 2013-04-10 15:29 天下 閱讀(2790) 評論(0)  編輯 收藏 引用 所屬分類: kernel & Driver

<2010年11月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

導航

統計

常用鏈接

留言簿(4)

隨筆分類(378)

隨筆檔案(329)

鏈接

最新隨筆

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲美女黄网| 亚洲国产网站| 亚洲欧美日韩网| 亚洲一区二区黄色| 红杏aⅴ成人免费视频| 亚洲国产成人在线播放| 欧美视频久久| 女人香蕉久久**毛片精品| 欧美天天综合网| 能在线观看的日韩av| 欧美日韩在线一区| 蜜桃av综合| 国产精品视频网站| 亚洲人成7777| 一区在线观看| 亚洲综合欧美日韩| 99在线精品视频| 久久久久五月天| 翔田千里一区二区| 欧美日韩18| 欧美激情1区2区3区| 国产农村妇女毛片精品久久莱园子 | 亚洲欧美第一页| 久久婷婷国产综合精品青草| 亚洲欧美国产精品专区久久| 欧美激情亚洲国产| 葵司免费一区二区三区四区五区| 国产精品久久999| 亚洲精品一区中文| 亚洲日本中文字幕区| 久久久久久一区二区| 久久狠狠久久综合桃花| 欧美亚州一区二区三区 | 亚洲专区国产精品| 六月婷婷一区| 久久网站免费| 国产亚洲精品激情久久| 亚洲一卡二卡三卡四卡五卡| av不卡在线观看| 六月天综合网| 欧美电影免费观看高清完整版| 国产日韩欧美亚洲| 午夜视黄欧洲亚洲| 欧美在线观看一区| 国产精品夜夜嗨| 亚洲一区日本| 欧美在线观看网站| 国产一级久久| 欧美在线高清| 老司机凹凸av亚洲导航| 精品二区视频| 美女在线一区二区| 亚洲高清视频一区二区| 亚洲欧洲综合另类在线| 欧美激情视频在线播放| 亚洲精品视频在线看| 亚洲视频一区二区在线观看 | 欧美成人在线免费观看| 在线观看日韩欧美| 欧美a级片网| 亚洲精品美女免费| 亚洲免费视频网站| 国产农村妇女精品一二区| 欧美在线看片a免费观看| 免费人成网站在线观看欧美高清| 在线电影院国产精品| 免费视频一区二区三区在线观看| 亚洲黄色免费网站| 亚洲一区二区三区四区五区黄| 国产精品视频午夜| 美脚丝袜一区二区三区在线观看 | 国产情人综合久久777777| 久久国产精品网站| 亚洲国产精品va在线看黑人动漫| 一本色道久久综合一区| 国产欧美日韩视频| 久久天天狠狠| 日韩一级精品| 久久久人成影片一区二区三区| 亚洲高清视频在线| 欧美日韩中文字幕| 久久精品国产久精国产爱| 亚洲国产成人久久综合一区| 亚洲欧美日韩在线| 亚洲国产欧美一区二区三区同亚洲 | 亚洲精品午夜精品| 国产精品人人做人人爽| 久久久噜噜噜久噜久久| 一本色道久久99精品综合| 久久精品av麻豆的观看方式| 亚洲激情视频在线播放| 国产精品综合网站| 欧美成人视屏| 欧美有码在线观看视频| 日韩视频免费看| 亚洲黄色天堂| 午夜伦欧美伦电影理论片| 欧美福利一区二区三区| 亚洲女优在线| 亚洲日本无吗高清不卡| 国产人成精品一区二区三| 欧美国产日韩a欧美在线观看| 亚洲自拍高清| 亚洲人成77777在线观看网| 久久久久欧美精品| 亚洲在线成人| 亚洲开发第一视频在线播放| 韩国一区二区三区在线观看| 欧美色道久久88综合亚洲精品| 美女91精品| 久久久7777| 午夜欧美精品| 在线视频精品一区| 亚洲国产精品电影在线观看| 久久久综合网站| 欧美一区二区高清| 亚洲在线网站| 一区二区冒白浆视频| 最新亚洲电影| 亚洲高清影视| 在线免费精品视频| 极品裸体白嫩激情啪啪国产精品| 国产精品尤物| 国产精品视频久久| 国产精品成人v| 欧美日韩一区二区三区四区在线观看 | 欧美色区777第一页| 欧美二区不卡| 欧美1级日本1级| 久久一区欧美| 久久久久久久高潮| 久久成人这里只有精品| 欧美一级电影久久| 香蕉成人伊视频在线观看| 亚洲一区二区三区视频播放| 一本色道88久久加勒比精品| 亚洲日韩欧美视频| 亚洲精品久久久久久久久久久久久| 欧美激情在线| 亚洲韩日在线| 亚洲另类在线一区| 99精品免费| 亚洲一区二区三区精品在线观看| 这里只有精品视频在线| 亚洲视频图片小说| 亚洲欧美成人在线| 欧美一级二区| 久久综合九色综合欧美就去吻| 老司机亚洲精品| 欧美激情一区二区| 欧美日韩专区在线| 国产农村妇女毛片精品久久麻豆 | 一本一本久久a久久精品综合妖精| 日韩亚洲欧美成人一区| 在线亚洲成人| 欧美亚洲色图校园春色| 久久久久久久综合狠狠综合| 欧美h视频在线| 欧美日韩综合不卡| 国产区在线观看成人精品| 在线观看一区| 一区二区三区成人| 欧美一区二区三区在线观看视频 | 国产精品人成在线观看免费| 国产一二精品视频| 亚洲日韩欧美一区二区在线| 在线一区二区三区四区五区| 一区二区激情小说| 宅男精品视频| 欧美日韩亚洲综合| 夜夜爽99久久国产综合精品女不卡| 中日韩美女免费视频网站在线观看| 亚洲免费在线| 老巨人导航500精品| 亚洲精品日韩综合观看成人91| 亚洲免费在线观看视频| 美国十次了思思久久精品导航| 欧美日韩视频专区在线播放| 国产日韩1区| 亚洲精品国产精品国产自| 午夜精品一区二区三区在线视| 免费观看欧美在线视频的网站| aa级大片欧美| 久久手机精品视频| 国产精品乱码久久久久久| 亚洲高清视频在线观看| 欧美一区二区三区免费在线看| 欧美激情一区二区三区不卡| 亚洲欧美日韩区| 欧美日韩a区| 亚洲国产日韩综合一区| 久久久蜜桃一区二区人| 亚洲伊人伊色伊影伊综合网| 欧美成人亚洲成人| 国产亚洲欧美日韩美女| 亚洲中无吗在线| 亚洲国产欧洲综合997久久| 欧美中文字幕在线视频| 国产精品色一区二区三区| 一区二区冒白浆视频|