中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

05網(wǎng)答案深圳關(guān)鍵詞優(yōu)化平臺

05網(wǎng)答案,深圳關(guān)鍵詞優(yōu)化平臺,做網(wǎng)站怎么上傳圖片,做銷售除了網(wǎng)站展會還有其他方法嵌入式Linux應用開發(fā)-基礎(chǔ)知識-第十九章驅(qū)動程序基石④ 第十九章 驅(qū)動程序基石④19.7 工作隊列19.7.1 內(nèi)核函數(shù)19.7.1.1 定義 work19.7.1.2 使用 work:schedule_work19.7.1.3 其他函數(shù) 19.7.2 編程、上機19.7.3 內(nèi)部機制19.7.3.1 Linux 2.x的工作隊列創(chuàng)建過程19.7.3…

嵌入式Linux應用開發(fā)-基礎(chǔ)知識-第十九章驅(qū)動程序基石④

  • 第十九章 驅(qū)動程序基石④
    • 19.7 工作隊列
      • 19.7.1 內(nèi)核函數(shù)
        • 19.7.1.1 定義 work
        • 19.7.1.2 使用 work:schedule_work
        • 19.7.1.3 其他函數(shù)
      • 19.7.2 編程、上機
      • 19.7.3 內(nèi)部機制
        • 19.7.3.1 Linux 2.x的工作隊列創(chuàng)建過程
        • 19.7.3.2
    • 19.8 中斷的線程化處理
      • 19.8.1 內(nèi)核機制
        • 19.8.1.1 調(diào)用 request_threaded_irq后內(nèi)核的數(shù)據(jù)結(jié)構(gòu)
        • 19.8.1.2
        • 19.8.1.3 中斷的執(zhí)行過程
      • 19.8.2 編程、上機

第十九章 驅(qū)動程序基石④

在這里插入圖片描述

19.7 工作隊列

使用 GIT命令載后,本節(jié)源碼位于這個目錄下:

01_all_series_quickstart\ 
05_嵌入式 Linux驅(qū)動開發(fā)基礎(chǔ)知識\source\ 
06_gpio_irq\ 09_read_key_irq_poll_fasync_block_timer_tasklet_workqueue 

前面講的定時器、下半部 tasklet,它們都是在中斷上下文中執(zhí)行,它們無法休眠。當要處理更復雜的事情時,往往更耗時。這些更耗時的工作放在定時器或是下半部中,會使得系統(tǒng)很卡;并且循環(huán)等待某件事情完成也太浪費 CPU資源了。
如果使用線程來處理這些耗時的工作,那就可以解決系統(tǒng)卡頓的問題:因為線程可以休眠。
在內(nèi)核中,我們并不需要自己去創(chuàng)建線程,可以使用“工作隊列”(workqueue)。內(nèi)核初始化工作隊列是,就為它創(chuàng)建了內(nèi)核線程。以后我們要使用“工作隊列”,只需要把“工作”放入“工作隊列中”,對應的內(nèi)核線程就會取出“工作”,執(zhí)行里面的函數(shù)。
在 2.xx的內(nèi)核中,工作隊列的內(nèi)部機制比較簡單;在現(xiàn)在 4.x的內(nèi)核中,工作隊列的內(nèi)部機制做得復雜無比,但是用法是一樣的。
工作隊列的應用場合:要做的事情比較耗時,甚至可能需要休眠,那么可以使用工作隊列。
缺點:多個工作(函數(shù))是在某個內(nèi)核線程中依序執(zhí)行的,前面函數(shù)執(zhí)行很慢,就會影響到后面的函數(shù)。 在多 CPU的系統(tǒng)下,一個工作隊列可以有多個內(nèi)核線程,可以在一定程度上緩解這個問題。
我們先使用看看怎么使用工作隊列。

19.7.1 內(nèi)核函數(shù)

內(nèi)核線程、工作隊列(workqueue)都由內(nèi)核創(chuàng)建了,我們只是使用。使用的核心是一個 work_struct結(jié)構(gòu)體,定義如下:
在這里插入圖片描述

使用工作隊列時,步驟如下:
① 構(gòu)造一個 work_struct結(jié)構(gòu)體,里面有函數(shù);
② 把這個 work_struct結(jié)構(gòu)體放入工作隊列,內(nèi)核線程就會運行 work中的函數(shù)。

19.7.1.1 定義 work

參考內(nèi)核頭文件:include\linux\workqueue.h

#define DECLARE_WORK(n, f)      \ struct work_struct n = __WORK_INITIALIZER(n, f) 
#define DECLARE_DELAYED_WORK(n, f)  \ struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, 0) 

第 1個宏是用來定義一個 work_struct結(jié)構(gòu)體,要指定它的函數(shù)。

第 2個宏用來定義一個 delayed_work結(jié)構(gòu)體,也要指定它的函數(shù)。所以“delayed”,意思就是說要讓它運行時,可以指定:某段時間之后你再執(zhí)行。
如果要在代碼中初始化 work_struct結(jié)構(gòu)體,可以使用下面的宏:

#define INIT_WORK(_work, _func)  
19.7.1.2 使用 work:schedule_work

調(diào)用 schedule_work時,就會把 work_struct結(jié)構(gòu)體放入隊列中,并喚醒對應的內(nèi)核線程。內(nèi)核線程就會從隊列里把 work_struct結(jié)構(gòu)體取出來,執(zhí)行里面的函數(shù)。

19.7.1.3 其他函數(shù)

在這里插入圖片描述

19.7.2 編程、上機

19.7.3 內(nèi)部機制

初學者知道 work_struct中的函數(shù)是運行于內(nèi)核線程的上下文,這就足夠了。
在 2.xx版本的 Linux內(nèi)核中,創(chuàng)建 workqueue時就會同時創(chuàng)建內(nèi)核線程;
在 4.xx版本的 Linux內(nèi)核中,內(nèi)核線程和 workqueue是分開創(chuàng)建的,比較復雜。

19.7.3.1 Linux 2.x的工作隊列創(chuàng)建過程

代碼在 kernel\workqueue.c中:

init_workqueues 
keventd_wq = create_workqueue("events"); __create_workqueue((name), 0, 0) for_each_possible_cpu(cpu) { err = create_workqueue_thread(cwq, cpu); p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);  

對于每一個 CPU,都創(chuàng)建一個名為“events/X”的內(nèi)核線程,X從 0開始。
在創(chuàng)建 workqueue的同時創(chuàng)建內(nèi)核線程。
在這里插入圖片描述

19.7.3.2

Linux 4.x的工作隊列創(chuàng)建過程
Linux4.x中,內(nèi)核線程和工作隊列是分開創(chuàng)建的。
先創(chuàng)建內(nèi)核線程,代碼在 kernel\workqueue.c中: init_workqueues

/* initialize CPU pools */ 
for_each_possible_cpu(cpu) { for_each_cpu_worker_pool(pool, cpu) { /* 對每一個 CPU都創(chuàng)建 2個 worker_pool結(jié)構(gòu)體,它是含有 ID的 */ /*  一個 worker_pool對應普通優(yōu)先級的 work,第 2個對應高優(yōu)先級的 work */ } 
/* create the initial worker */ 
for_each_online_cpu(cpu) { for_each_cpu_worker_pool(pool, cpu) { /* 對每一個 CPU的每一個 worker_pool,創(chuàng)建一個 worker */  
/* 每一個 worker對應一個內(nèi)核線程 */ BUG_ON(!create_worker(pool));     } 
} 

create_worker函數(shù)代碼如下:
在這里插入圖片描述

創(chuàng)建好內(nèi)核線程后,再創(chuàng)建 workqueue,代碼在 kernel\workqueue.c中:

init_workqueues 
system_wq = alloc_workqueue("events", 0, 0); __alloc_workqueue_key wq = kzalloc(sizeof(*wq) + tbl_size, GFP_KERNEL);  // 分配 workqueue_struct         alloc_and_link_pwqs(wq) // 跟 worker_poll建立聯(lián)系 

在這里插入圖片描述
一開始時,每一個 worker_poll下只有一個線程,但是系統(tǒng)會根據(jù)任務繁重程度動態(tài)創(chuàng)建、銷毀內(nèi)核線程。所以你可以在 work中打印線程 ID,發(fā)現(xiàn)它可能是變化的。

19.8 中斷的線程化處理

使用 GIT命令載后,本節(jié)源碼位于這個目錄下:

01_all_series_quickstart\ 
05_嵌入式 Linux驅(qū)動開發(fā)基礎(chǔ)知識\source\ 
06_gpio_irq\ 10_read_key_irq_poll_fasync_block_timer_tasklet_workqueue_threadedirq 

請先回顧《18.2.7 新技術(shù):threaded irq》。
復雜、耗時的事情,盡量使用內(nèi)核線程來處理。上節(jié)視頻介紹的工作隊列用起來挺簡單,但是它有一個缺點:工作隊列中有多個 work,前一個 work沒處理完會影響后面的 work。解決方法有很多種,比如干脆自己創(chuàng)建一個內(nèi)核線程,不跟別的 work湊在一塊了。在 Linux系統(tǒng)中,對于存儲設(shè)備比如 SD/TF卡,它的驅(qū)動程序就是這樣做的,它有自己的內(nèi)核線程。
對于中斷處理,還有另一種方法:threaded irq,線程化的中斷處理。中斷的處理仍然可以認為分為上半部、下半部。上半部用來處理緊急的事情,下半部用一個內(nèi)核線程來處理,這個內(nèi)核線程專用于這個中斷。 內(nèi)核提供了這個函數(shù):
在這里插入圖片描述

你可以只提供 thread_fn,系統(tǒng)會為這個函數(shù)創(chuàng)建一個內(nèi)核線程。發(fā)生中斷時,系統(tǒng)會立刻調(diào)用 handler函數(shù),然后喚醒某個內(nèi)核線程,內(nèi)核線程再來執(zhí)行 thread_fn函數(shù)。

19.8.1 內(nèi)核機制

19.8.1.1 調(diào)用 request_threaded_irq后內(nèi)核的數(shù)據(jù)結(jié)構(gòu)

在這里插入圖片描述

19.8.1.2

request_threaded_irq
request_threaded_irq函數(shù),肯定會創(chuàng)建一個內(nèi)核線程。
源碼在內(nèi)核文件 kernel\irq\manage.c中,

int request_threaded_irq(unsigned int irq, irq_handler_t handler,     irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id) 
{ // 分配、設(shè)置一個 irqaction結(jié)構(gòu)體 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); if (!action) return -ENOMEM; 
action->handler = handler; 
action->thread_fn = thread_fn; action->flags = irqflags; 
action->name = devname; 
action->dev_id = dev_id; retval = __setup_irq(irq, desc, action);  // 進一步處理 } __setup_irq函數(shù)代碼如下(只摘取重要部分)if (new->thread_fn && !nested) { ret = setup_irq_thread(new, irq, false); 
setup_irq_thread函數(shù)代碼如下(只摘取重要部分)if (!secondary) { t = kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name); 
} else { t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq,       new->name); param.sched_priority -= 1; 
} 
new->thread = t; 
19.8.1.3 中斷的執(zhí)行過程

對于 GPIO中斷,我使用 QEMU的調(diào)試功能找出了所涉及的函數(shù)調(diào)用,其他板子可能稍有不同。 調(diào)用關(guān)系如下,反過來看:

Breakpoint 1, gpio_keys_gpio_isr (irq=200, dev_id=0x863e6930) at drivers/input/keyboard/gpio_keys.c:393 
393 { 
(gdb) bt 
#0  gpio_keys_gpio_isr (irq=200, dev_id=0x863e6930) at drivers/input/keyboard/gpio_keys.c:393 #1  0x80270528 in __handle_irq_event_percpu (desc=0x8616e300, flags=0x86517edc) at kernel/irq/handle.c:145 
#2  0x802705cc in handle_irq_event_percpu (desc=0x8616e300) at kernel/irq/handle.c:185 
#3  0x80270640 in handle_irq_event (desc=0x8616e300) at kernel/irq/handle.c:202 
#4  0x802738e8 in handle_level_irq (desc=0x8616e300) at kernel/irq/chip.c:518 
#5  0x8026f7f8 in generic_handle_irq_desc (desc=<optimized out>) at ./include/linux/irqdesc.h:150 
#6  generic_handle_irq (irq=<optimized out>) at kernel/irq/irqdesc.c:590 
#7  0x805005e0 in mxc_gpio_irq_handler (port=0xc8, irq_stat=2252237104) at drivers/gpio/gpio-mxc.c:274 
#8  0x805006fc in mx3_gpio_irq_handler (desc=<optimized out>) at drivers/gpio/gpio-mxc.c:291 #9  0x8026f7f8 in generic_handle_irq_desc (desc=<optimized out>) at ./include/linux/irqdesc.h:150 
#10 generic_handle_irq (irq=<optimized out>) at kernel/irq/irqdesc.c:590 
#11 0x8026fd0c in __handle_domain_irq (domain=0x86006000, hwirq=32, lookup=true, regs=0x86517fb0) at kernel/irq/irqdesc.c:627 
#12 0x80201484 in handle_domain_irq (regs=<optimized out>, hwirq=<optimized out>, domain=<optimized out>) at ./include/linux/irqdesc.h:168 
#13 gic_handle_irq (regs=0xc8) at drivers/irqchip/irq-gic.c:364 
#14 0x8020b704 in __irq_usr () at arch/arm/kernel/entry-armv.S:464 

我們只需要分析__handle_irq_event_percpu函數(shù),它在 kernel\irq\handle.c中:

線程的處在這里插入圖片描述
理函數(shù)為 irq_thread,代碼在 kernel\irq\handle.c中:

在這里插入圖片描述

19.8.2 編程、上機

調(diào)用request_threaded_irq函數(shù)注冊中斷,調(diào)用free_irq卸載中斷。
從前面可知,我們可以提供上半部函數(shù),也可以不提供:
① 如果不提供
內(nèi)核會提供默認的上半部處理函數(shù):irq_default_primary_handler,它是直接返回 IRQ_WAKE_THREAD。 ② 如果提供的話
返回值必須是:IRQ_WAKE_THREAD。
在 thread_fn中,如果中斷被正確處理了,應該返回 IRQ_HANDLED。

http://www.risenshineclean.com/news/66045.html

相關(guān)文章:

  • 開發(fā)區(qū)網(wǎng)站建設(shè)游戲代理是怎么賺錢的如何代理游戲
  • 訊杰網(wǎng)站建設(shè)南寧seo教程
  • 做網(wǎng)站余姚做運營需要具備什么能力
  • 英文 日文網(wǎng)站建設(shè)申請seo賺錢嗎
  • 那個相親網(wǎng)站做的比較好網(wǎng)站流量分析工具
  • 開發(fā)一個官方網(wǎng)站要多少錢免費的關(guān)鍵詞優(yōu)化軟件
  • 自己做代練網(wǎng)站百度關(guān)鍵詞廣告怎么收費
  • 網(wǎng)站發(fā)展方向百度指數(shù)大數(shù)據(jù)分享平臺
  • 網(wǎng)站swf怎么做seo搜索引擎優(yōu)化原理
  • vs做網(wǎng)站連數(shù)據(jù)庫優(yōu)化推廣網(wǎng)站怎么做最好
  • 網(wǎng)站規(guī)劃與設(shè)計范文太原網(wǎng)站排名推廣
  • 國內(nèi)做外貿(mào)網(wǎng)站的有哪些資料遼寧網(wǎng)站建設(shè)
  • 網(wǎng)絡(luò)營銷工作網(wǎng)站seo優(yōu)化價格
  • 直接做的黃頁視頻網(wǎng)站濟南seo優(yōu)化公司
  • 網(wǎng)站開發(fā)用什么系統(tǒng)比較好seo是做什么工作內(nèi)容
  • 做app布局參考哪個網(wǎng)站紹興seo排名外包
  • 免費行情軟件app網(wǎng)站mnu萬網(wǎng)域名查詢工具
  • 做鞋子批發(fā)的網(wǎng)站有哪些強力搜索引擎
  • 第三方免費做網(wǎng)站seo云優(yōu)化公司
  • 網(wǎng)站獲取訪客qq號碼怎么接app推廣的單子
  • app手機網(wǎng)站模板免費下載網(wǎng)站seo外包公司有哪些
  • 關(guān)于做網(wǎng)站書籍關(guān)鍵詞組合工具
  • 大學生個人網(wǎng)站怎么做seo技術(shù)學院
  • 網(wǎng)站如何在工信部備案信息網(wǎng)站設(shè)計公司模板
  • 南通網(wǎng)站建設(shè)seo班級優(yōu)化大師
  • 南和網(wǎng)站建設(shè)公司最近國際時事熱點事件
  • 鄭州seo優(yōu)化網(wǎng)站seo優(yōu)化心得
  • 快速搭建網(wǎng)站的方法百度投訴中心
  • icp網(wǎng)站備案密碼找回百度統(tǒng)計數(shù)據(jù)
  • 做圖賺錢的網(wǎng)站創(chuàng)量廣告投放平臺