日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Linux內(nèi)核中斷函數(shù)的上半部分詳解 (linux中斷函數(shù)上半部分)

Linux內(nèi)核中斷函數(shù)的上半部分是指中斷處理的之一部分,也是最關(guān)鍵的部分。在這一部分中,內(nèi)核必須立即響應(yīng)中斷請求,并在處理完中斷請求后盡快恢復(fù)中斷,以確保系統(tǒng)的穩(wěn)定性和可靠性。因此,了解Linux內(nèi)核中斷函數(shù)的上半部分是非常重要的。

成都創(chuàng)新互聯(lián)是專業(yè)的衡東網(wǎng)站建設(shè)公司,衡東接單;提供成都網(wǎng)站設(shè)計、網(wǎng)站制作,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行衡東網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

中斷是計算機硬件和軟件之間的一種通信機制。當(dāng)硬件設(shè)備需要向計算機主機發(fā)出通知時,它會發(fā)送一個中斷請求信號(IRQ)。這個IRQ信號被傳送到計算機的中斷控制器中,中斷控制器將它轉(zhuǎn)換為一個中斷向量(中斷號)。然后,內(nèi)核的中斷處理程序?qū)⒈徽{(diào)用,對中斷進(jìn)行響應(yīng)。

Linux內(nèi)核的中斷處理是分為兩個部分的:上半部分和下半部分。上半部分處理的是中斷的執(zhí)行過程,而下半部分處理的是中斷的清理過程。

在Linux內(nèi)核的中斷處理程序中,上半部分是最重要的部分。上半部分是處理中斷請求的之一部分,并且必須在最短時間內(nèi)執(zhí)行。它必須能夠盡可能快地完成中斷請求并快速釋放中斷,并將控制返回到應(yīng)用程序。

下面是Linux內(nèi)核中斷函數(shù)上半部分的主要任務(wù):

1.中斷處理程序的進(jìn)入

當(dāng)中斷請求被激活時,控制權(quán)將從用戶空間轉(zhuǎn)移到內(nèi)核空間。然后,內(nèi)核開始執(zhí)行中斷處理程序。中斷處理程序負(fù)責(zé)檢查中斷請求,并響應(yīng)中斷。在進(jìn)入中斷處理程序之前,內(nèi)核必須保存當(dāng)前的處理器狀態(tài),并確保處理器的狀態(tài)正確。

2.中斷請求的分配

當(dāng)中斷處理程序進(jìn)入時,內(nèi)核必須分配一個中斷號。這樣,中斷控制器就可以將中斷請求轉(zhuǎn)發(fā)到正確的中斷處理程序。為了選擇正確的中斷號,內(nèi)核必須檢查中斷請求的來源,例如一個設(shè)備或驅(qū)動程序。

3.中斷的響應(yīng)

一旦確認(rèn)了中斷請求來源并分配了中斷號,內(nèi)核就開始響應(yīng)中斷請求。這一步通常涉及到處理中斷請求數(shù)據(jù)、確定中斷請求時的事件和中斷的形式、并向設(shè)備驅(qū)動程序發(fā)送中斷請求(通常是下半部分的處理)。

4.中斷的處理

在執(zhí)行中斷請求時,內(nèi)核必須執(zhí)行相應(yīng)的中斷處理程序。這本質(zhì)上就是執(zhí)行打斷原來的操作,但是內(nèi)核必須確保進(jìn)程能夠正確地恢復(fù)并繼續(xù)運行。

5.中斷的返回

當(dāng)內(nèi)核完成中斷處理時,控制權(quán)將返回到應(yīng)用程序。但是,內(nèi)核仍然需要確保狀態(tài)正確并清理中斷函數(shù)內(nèi)部的其他操作。這通常需要釋放鎖定資源,并確保系統(tǒng)狀態(tài)穩(wěn)定。

了解Linux內(nèi)核中斷函數(shù)的上半部分是非常重要的。上半部分是整個中斷處理程序的關(guān)鍵部分,負(fù)責(zé)響應(yīng)中斷并進(jìn)行快速、穩(wěn)定的處理。在理解Linux內(nèi)核中斷函數(shù)的上半部分之后,下半部分的理解和處理將變得更加容易。

相關(guān)問題拓展閱讀:

  • 關(guān)于linux注冊的中斷函數(shù)
  • 如何在linux下開啟napi

關(guān)于linux注冊的中斷函數(shù)

我也不完全理解,但是比你知道的多點。

Linux中,分內(nèi)核態(tài)和用戶態(tài)。

你寫的所有的驅(qū)動,都是出于內(nèi)核態(tài)->可以直接使用內(nèi)核相關(guān)資源;

應(yīng)用層,都是用戶態(tài)->無法直接操作底層的東西 -> 想要操作,比如獲得權(quán)限,切換到內(nèi)核態(tài),然后才能操作。

你這里的需求,我的理解是:

對應(yīng)你這句

“在中斷服務(wù)程序中操作另一個外設(shè)”

不知道你的目的和打算用的手段是啥

一般的,ISR中,操作別的設(shè)備,常見的是:

設(shè)置對應(yīng)的(比如該硬件本身,或者別的設(shè)備B的)寄存器的對應(yīng)的位,以便通知其某種事情發(fā)送或狀態(tài)變化了。

然后設(shè)備B會:

要么是由于(被修改了寄存器而)發(fā)生了中斷,然后可以接著處理其所要做的事情;

要么是一直輪訓(xùn),檢測對應(yīng)的某種資源釋放變化,比如上面被改的寄存器的對應(yīng)的位,發(fā)現(xiàn)變化了,再去調(diào)用你的函數(shù),做對應(yīng)的處理。

注意:

中斷,不論是哪個設(shè)備的中斷,都不應(yīng)該占用(CPU)太長時間

-> 導(dǎo)致別的中斷或服務(wù)無法及時運行

僅供參考。

從內(nèi)核空間返回用戶空間時,kernel檢查是否有pending signal,如果有,執(zhí)行。

如何在linux下開啟napi

天重點對linux網(wǎng)絡(luò)

數(shù)據(jù)包

的處理做下分析,但是并不關(guān)系到上層協(xié)議,僅僅到鏈路層。

之前轉(zhuǎn)載過一篇文章,對NAPI做了比較詳盡的分析,本文結(jié)合Linux內(nèi)核源代碼,對當(dāng)前網(wǎng)絡(luò)數(shù)據(jù)包的處理進(jìn)行梳理。根據(jù)NAPI的處理特性,對設(shè)備提出一定的要求

1、設(shè)備需要有足夠的緩沖區(qū),保存多個數(shù)據(jù)分組

2、可以禁用當(dāng)前設(shè)備中斷,然而不影響其他的操作。

當(dāng)前大部分的設(shè)備都支持NAPI,但是為了對之前的保持兼容,內(nèi)核還是對之前中斷方式提供了兼容。我們先看下NAPI具體的處理方式。我們都知道中斷分為中斷上半部和下半部,上半部完成的任務(wù)很是簡單,僅僅負(fù)責(zé)把數(shù)據(jù)保存下來;而下半部負(fù)責(zé)具體的處理。為了處理下半部,每個CPU有維護(hù)一個softnet_data結(jié)構(gòu)。我們不對此結(jié)構(gòu)做詳細(xì)介紹,僅僅描述和NAPI相關(guān)的部分。結(jié)構(gòu)中有一個poll_list字段,連接所有的輪詢設(shè)備。還 維護(hù)了兩個隊列input_pkt_queue和process_queue。這兩個用戶傳統(tǒng)不支持NAPI方式的處理。前者由中斷上半部的處理函數(shù)吧數(shù)據(jù)包入隊,在具體的處理時,使用后者做中轉(zhuǎn),相當(dāng)于前者負(fù)責(zé)接收,后者負(fù)責(zé)處理。最后是一個napi_struct的backlog,代表一個虛擬設(shè)備供輪詢使用。在支持NAPI的設(shè)備下,每個設(shè)備具備一個緩沖隊列,存放到來數(shù)據(jù)。每個設(shè)備對應(yīng)一個napi_struct結(jié)構(gòu),該結(jié)構(gòu)代表該設(shè)備存放在poll_list中被輪詢。而設(shè)備還需要提供一個poll函數(shù),在設(shè)備被輪詢到后,會調(diào)用poll函數(shù)對數(shù)據(jù)進(jìn)行處理?;具壿嬀褪沁@樣,下面看下具體流程。

中斷上半部:

非NAPI:

非NAPI對應(yīng)的上半部函數(shù)為netif_rx,位于Dev.,c中

int netif_rx(struct sk_buff *skb)

{

int ret;

/* if netpoll wants it, pretend we never saw it */

/*如果是net_poll想要的,則不作處理*/

if (netpoll_rx(skb))

return NET_RX_DROP;

/*檢查時間戳*/

net_timestamp_check(netdev_tstamp_prequeue, skb);

trace_netif_rx(skb);

#ifdef CONFIG_RPS

if (static_key_false(&rps_needed)) {

struct rps_dev_flow voidflow, *rflow = &voidflow;

int cpu;

/*禁用搶占*/

preempt_disable();

rcu_read_lock();

cpu = get_rps_cpu(skb->dev, skb, &rflow);

if (cpu last_qtail);

rcu_read_unlock();

preempt_enable();

} else

#endif

{

unsigned int

qtail;

ret = enqueue_to_backlog(skb, get_cpu(), &qtail);

put_cpu();

}

return ret;

}

中間RPS暫時不關(guān)心,這里直接調(diào)用enqueue_to_backlog放入CPU的全局隊列input_pkt_queue

static int enqueue_to_backlog(struct sk_buff *skb, int cpu,

unsigned int *qtail)

{

struct softnet_data *sd;

unsigned long flags;

/*獲取cpu相關(guān)的softnet_data變量*/

sd = &per_cpu(softnet_data, cpu);

/*關(guān)中斷*/

local_irq_save(flags);

rps_lock(sd);

/*如果input_pkt_queue的長度小于更大限制,則符合條件*/

if (skb_queue_len(&sd->input_pkt_queue) input_pkt_queue)) {

enqueue:

__skb_queue_tail(&sd->input_pkt_queue, skb);

input_queue_tail_incr_save(sd, qtail);

rps_unlock(sd);

local_irq_restore(flags);

return NET_RX_SUCCESS;

}

/* Schedule NAPI for backlog device

* We can use non atomic operation since we own the queue lock

*/

/*否則需要調(diào)度backlog 即虛擬設(shè)備,然后再入隊。napi_struct結(jié)構(gòu)中的state字段如果標(biāo)記了NAPI_STATE_SCHED,則表明該設(shè)備已經(jīng)在調(diào)度,不需要再次調(diào)度*/

if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) {

if (!rps_ipi_queued(sd))

____napi_schedule(sd, &sd->backlog);

}

goto enqueue;

}

/*到這里緩沖區(qū)已經(jīng)不足了,必須丟棄*/

sd->dropped++;

rps_unlock(sd);

local_irq_restore(flags);

atomic_long_inc(&skb->dev->rx_dropped);

kfree_skb(skb);

return NET_RX_DROP;

}

該函數(shù)邏輯也比較簡單,主要注意的是設(shè)備必須先添加調(diào)度然后才能接受數(shù)據(jù),添加調(diào)度調(diào)用了____napi_schedule函數(shù),該函數(shù)把設(shè)備對應(yīng)的napi_struct結(jié)構(gòu)插入到softnet_data的poll_list

鏈表

尾部,然后喚醒軟中斷,這樣在下次軟中斷得到處理時,中斷下半部就會得到處理。不妨看下源碼

static inline void ____napi_schedule(struct softnet_data *sd,

struct napi_struct *napi)

{

list_add_tail(&napi->poll_list, &sd->poll_list);

__raise_softirq_irqoff(NET_RX_SOFTIRQ);

}

NAPI方式

NAPI的方式相對于非NAPI要簡單許多,看下e100網(wǎng)卡的中斷處理函數(shù)e100_intr,核心部分

if (likely(napi_schedule_prep(&nic->napi))) {

e100_disable_irq(nic);//屏蔽當(dāng)前中斷

__napi_schedule(&nic->napi);//把設(shè)備加入到輪訓(xùn)隊列

}

if條件檢查當(dāng)前設(shè)備是否 可被調(diào)度,主要檢查兩個方面:1、是否已經(jīng)在調(diào)度 2、是否禁止了napi pending.如果符合條件,就關(guān)閉當(dāng)前設(shè)備的中斷,調(diào)用__napi_schedule函數(shù)把設(shè)備假如到輪訓(xùn)列表,從而開啟輪詢模式。

分析:結(jié)合上面兩種方式,還是可以發(fā)現(xiàn)兩種方式的異同。其中softnet_data作為主導(dǎo)結(jié)構(gòu),在NAPI的處理方式下,主要維護(hù)輪詢鏈表。NAPI設(shè)備均對應(yīng)一個napi_struct結(jié)構(gòu),添加到鏈表中;非NAPI沒有對應(yīng)的napi_struct結(jié)構(gòu),為了使用NAPI的處理流程,使用了softnet_data結(jié)構(gòu)中的back_log作為一個虛擬設(shè)備添加到輪詢鏈表。同時由于非NAPI設(shè)備沒有各自的接收隊列,所以利用了softnet_data結(jié)構(gòu)的input_pkt_queue作為全局的接收隊列。這樣就處理而言,可以和NAPI的設(shè)備進(jìn)行兼容。但是還有一個重要區(qū)別,在NAPI的方式下,首次數(shù)據(jù)包的接收使用中斷的方式,而后續(xù)的數(shù)據(jù)包就會使用輪詢處理了;而非NAPI每次都是通過中斷通知。

下半部:

下半部的處理函數(shù),之前提到,網(wǎng)絡(luò)數(shù)據(jù)包的接發(fā)對應(yīng)兩個不同的軟中斷,接收軟中斷NET_RX_SOFTIRQ的處理函數(shù)對應(yīng)net_rx_action

static void net_rx_action(struct softirq_action *h)

{

struct softnet_data *sd = &__get_cpu_var(softnet_data);

unsigned long time_limit = jiffies + 2;

int budget = netdev_budget;

void *have;

local_irq_disable();

/*遍歷輪詢表*/

while (!list_empty(&sd->poll_list)) {

struct napi_struct *n;

int work, weight;

/* If softirq window is exhuasted then punt.

* Allow this to run for 2 jiffies since which will allow

* an average latency of 1.5/HZ.

*/

/*如果開支用完了或者時間用完了*/

if (unlikely(budget poll()

* calls can remove this head entry from the list.

*/

/*獲取鏈表中首個設(shè)備*/

n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list);

have = netpoll_poll_lock(n);

weight = n->weight;

/* This NAPI_STATE_SCHED test is for avoiding a race

* with netpoll’s poll_napi(). Only the entity which

* obtains the lock and sees NAPI_STATE_SCHED set will

* actually make the ->poll() call. Therefore we avoid

* accidentally calling ->poll() when NAPI is not scheduled.

*/

work = 0;

/*如果被設(shè)備已經(jīng)被調(diào)度,則調(diào)用其處理函數(shù)poll函數(shù)*/

if (test_bit(NAPI_STATE_SCHED, &n->state)) {

work = n->poll(n, weight);//后面weight指定了一個額度

trace_napi_poll(n);

}

WARN_ON_ONCE(work > weight);

/*總額度遞減*/

budget -= work;

local_irq_disable();

/* Drivers must not modify the NAPI state if they

* consume the entire weight. In such cases this code

* still “owns” the NAPI instance and therefore can

* move the instance around on the list at-will.

*/

/*如果work=weight的話。任務(wù)就完成了,把設(shè)備從輪詢鏈表刪除*/

if (unlikely(work == weight)) {

if (unlikely(napi_disable_pending(n))) {

local_irq_enable();

napi_complete(n);

local_irq_disable();

} else {

if (n->gro_list) {

/* flush too old packets

* If HZ = 1000);

local_irq_disable();

}

/*每次處理完就把設(shè)備移動到列表尾部*/

list_move_tail(&n->poll_list, &sd->poll_list);

}

}

netpoll_poll_unlock(have);

}

out:

net_rps_action_and_irq_enable(sd);

#ifdef CONFIG_NET_DMA

/*

* There may not be any more sk_buffs coming right now, so push

* any pending DMA copies to hardware

*/

dma_issue_pending_all();

#endif

return;

softnet_break:

sd->time_squeeze++;

__raise_softirq_irqoff(NET_RX_SOFTIRQ);

goto out;

}

這里有處理方式比較直觀,直接遍歷poll_list鏈表,處理之前設(shè)置了兩個限制:budget和time_limit。前者限制本次處理數(shù)據(jù)包的總量,后者限制本次處理總時間。只有二者均有剩余的情況下,才會繼續(xù)處理。處理期間同樣是開中斷的,每次總是從鏈表表頭取設(shè)備進(jìn)行處理,如果設(shè)備被調(diào)度,其實就是檢查NAPI_STATE_SCHED位,則調(diào)用 napi_struct的poll函數(shù),處理結(jié)束如果沒有處理完,則把設(shè)備移動到鏈表尾部,否則從鏈表刪除。NAPI設(shè)備對應(yīng)的poll函數(shù)會同樣會調(diào)用__netif_receive_skb函數(shù)上傳協(xié)議棧,這里就不做分析了,感興趣可以參考e100的poll函數(shù)e100_poll。

而非NAPI對應(yīng)poll函數(shù)為process_backlog。

static int process_backlog(struct napi_struct *napi, int quota)

{

int work = 0;

struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);

#ifdef CONFIG_RPS

/* Check if we have pending ipi, its better to send them now,

* not waiting net_rx_action() end.

*/

if (sd->rps_ipi_list) {

local_irq_disable();

net_rps_action_and_irq_enable(sd);

}

#endif

napi->weight = weight_p;

local_irq_disable();

while (work process_queue))) {

local_irq_enable();

/*進(jìn)入?yún)f(xié)議棧*/

__netif_receive_skb(skb);

local_irq_disable();

input_queue_head_incr(sd);

if (++work >= quota) {

local_irq_enable();

return work;

}

}

rps_lock(sd);

qlen = skb_queue_len(&sd->input_pkt_queue);

if (qlen)

skb_queue_splice_tail_init(&sd->input_pkt_queue,

&sd->process_queue);

if (qlen poll_list);

napi->state = 0;

quota = work + qlen;

}

rps_unlock(sd);

}

local_irq_enable();

return work;

}

函數(shù)還是比較簡單的,需要注意的每次處理都攜帶一個配額,即本次只能處理quota個數(shù)據(jù)包,如果超額了,即使沒處理完也要返回,這是為了保證處理器的公平使用。處理在一個while循環(huán)中完成,循環(huán)條件正是work = quota時,就要返回。當(dāng)work還有剩余額度,但是process_queue中數(shù)據(jù)處理完了,就需要檢查input_pkt_queue,因為在具體處理期間是開中斷的,那么期間就有可能有新的數(shù)據(jù)包到來,如果input_pkt_queue不為空,則調(diào)用skb_queue_splice_tail_init函數(shù)把數(shù)據(jù)包遷移到process_queue。如果剩余額度足夠處理完這些數(shù)據(jù)包,那么就把虛擬設(shè)備移除輪詢隊列。這里有些疑惑就是最后為何要增加額度,剩下的額度已經(jīng)足夠處理這些數(shù)據(jù)了呀?根據(jù)此流程不難發(fā)現(xiàn),其實執(zhí)行的是在兩個隊列之間移動數(shù)據(jù)包,然后再做處理。

關(guān)于linux中斷函數(shù)上半部分的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。

成都服務(wù)器托管選創(chuàng)新互聯(lián),先上架開通再付費。
創(chuàng)新互聯(lián)(www.cdcxhl.com)專業(yè)-網(wǎng)站建設(shè),軟件開發(fā)老牌服務(wù)商!微信小程序開發(fā),APP開發(fā),網(wǎng)站制作,網(wǎng)站營銷推廣服務(wù)眾多企業(yè)。電話:028-86922220


分享題目:Linux內(nèi)核中斷函數(shù)的上半部分詳解 (linux中斷函數(shù)上半部分)
本文地址:http://www.5511xx.com/article/cogdgej.html