[轉]QNX的中斷控制方式-中斷方法應用

如果你認爲本系列文章對你有所幫助,請大家有錢的捧個錢場,點擊此處贊助,贊助額0.1元起步,多少隨意

聲明:本文只用於個人學習交流,若不慎造成侵權,請及時聯繫我,立即予以改正

鋒影

email:[email protected]

 

學習目的: 
1.qnx微內核怎樣操作硬件中斷? 
2.我們怎樣用代碼操作中斷? 
3.不同的中斷操作策略

學習概要 
1.中斷的概念 
2.中斷服務子程序中的進程間通信 
3.程序架構

1.中斷的概念 


可搶佔中斷調度: 


不可搶佔中斷調度: 


中斷有下特性: 
1.它的優先級比任何的線程都高 
2.可被高優先級中斷搶佔(需要平臺支持) 
3.能被用戶空間程序操作(驅動被動態加載,而不是存在內核空間) 
4.被內核調用(有內核特權)

中斷潛在時間: 
 
影響因素: 
1.中斷失能花費的時間 
2.相同或更高優先級中斷服務程序花費時間 
3.中斷其他的服務程序花費時間 
4.特定屏蔽中斷花費時間(通常是共享中斷和InterruptAttachEvent())

調度潛在時間: 
 
影響因素: 
1.花費在其他中斷服務程序的時間 
2.被調度的線程優先級高低 
3.花費在已經處於READY狀態的更高優先級線程的時間 
因爲中斷的優先級比線程高,所以,花費在中斷服務程序的時間直接影響到線程調度。

中斷調度和中斷操作策略 
中斷相關函數調用:

id = InterruptAttach (int intr,
struct sigevent *(*handler)(void *, int),
void *area, int size, unsigned flags);

id = InterruptAttachEvent (int intr, struct sigevent *event,
unsigned flags);

InterruptDetach (int id);

InterruptWait (int flags, uint64_t *reserved);

InterruptMask (int intr, int id);

InterruptUnmask (int intr, int id);

InterruptLock (struct intrspin *spinlock);

InterruptUnlock (struct intrspin *spinlock);

注:在調用以上函數之前,必須要先調用ThreadCtl(_NTO_TCTL_IO, 0),以取得I/O特權。 
InterruptEnable (void); 
InterruptDisable (void); 
以上兩個函數只用於non-SMP系統,所以並不通用,我們以該使用先兩個函數: 
InterruptLock(); 
InterruptUnlock();

一個簡單的例子

struct sigevent event;
main ()
{
    ThreadCtl (_NTO_TCTL_IO, 0);
    SIGEV_INTR_INIT (&event);
    id = InterruptAttachEvent (intnum, &event, ...);
    for (;;) 
    {
        InterruptWait (0, NULL);
        // do the interrupt work here, at thread priority
        InterruptUnmask (intnum, id);
    }
}

注:當內核控制時, 它將屏蔽掉中斷,並且使用event來處理適當的調度。在本例中,因爲使用的是SIGEV_INTR,所以 InterruptWait()將不會阻塞。

怎樣將中斷和event相聯繫:

 
一旦一個event和中斷相關聯後,內核將自動對中斷解除屏蔽。 
傳遞給 InterruptAttachEvent()的參數是返回的真實event。 
當中斷產生以及內核調用時,內核將在線程調度之前自動屏蔽中斷,以保證它在的安全性。

例子:

struct sigevent event; //創建一個event

const struct sigevent *
handler (void *not_used, int id) //返回一個實際的event
{
    if (check_status_register()) // place-holder for hw code
    {
        return (&event);
    }
    else
    {
        return (NULL);
    }

}

main ()
{
    ThreadCtl (_NTO_TCTL_IO, 0);
    SIGEV_INTR_INIT (&event);
    id = InterruptAttach (intnum, handler, NULL, 0, ...);
    for (;;) 
    {
        InterruptWait (0, NULL);
        // do some or all of the work here
    }
}

注:在本例中,這是一個用戶提供的中斷程序。將有一個work必須在timing reasons中斷優先級被完成。中斷程序和線程將共享這個work。中斷將完成時間關鍵任務(the time-critical work),然後線程將被喚醒去做非時間關鍵任務(the non-time-critical work)(數據分析,並傳遞給其他線程)。///參考linux的底半部,頂半部 
在以上的中斷程序中, check_status_register() 是去檢查硬件的各種狀態寄存器,檢查硬件是否產生了中斷,或者清除中斷源。這些在level-sensitive architectures上都是需要的,因爲中斷將被共享,並且內核將在中斷鏈的最後產生一個EOI(外部中斷的中斷結束命令),所以我們必須在返回之前清除中斷。這也就是爲什麼在使用InterruptAttachEvent()時,內核要在線程調度前進行中斷屏蔽。

怎樣將中斷服務程序handle和中斷向量相聯繫? 
 
注:一旦一個handler和中斷相關聯,內核就將對中斷解除屏蔽。 
area的好處是它可以被傳遞給你的中斷服務程序的第一個參數。它讓一箇中斷程序處理多箇中斷。 
並且它避免了使用全局變量。

logical interrupt中斷號是: 
在啓動時就定義了,在板子的buildfile中。bulid file在QNX-TATGET/cpu/boot/build中。

例如:
# Interrupt Assignments
# ---------------------
#
# vector: 0 (PPC800_INTR_IRQ0)
# trigger: falling edge
# device: unassigned
...
# vector: 15 (PPC800_INTR_LVL7)
# trigger: N/A
# device: Programmable Interval Timer interrupt (system timer)
...
# vector: 0x8001001e (PPC800_INTR_CPMSCC1)
# trigger: N/A
# device: CPM SCC1

interruptAttachEvent and InterruptAttach的flag參數: 
1._NTO_INTR_FLAGS_END 
內核包含了給每個中斷的處理函數和events的隊列。這個參數表示新的處理函數和event應該被添加在隊列的結尾而不是開頭。 
2._NTO_INTR_FLAGS_PROCESS 
將處理程序/event與進程向關聯。通常 它們將與綁定的線程相關聯。如果這個線程死了,這個處理程序也就取消綁定。但是如果有這個參數,即使線程死了,處理程序也不會被取消綁定。 
你應該使用進程中的event,如pulse或signal 
注:如果你使用了這個標誌,你的中斷handler將不會返回event.sigev_notify of _SIGEV_INTR,因爲它將去綁定的可能不再存在的線程。 
3._NTO_INTR_FLAGS_TRK_MSK 
這個參數指定了當應用app與中斷斷開綁定時,內核將使用合適的數字來取消中斷屏蔽,以保證中斷函數正常。通常使用這個flag。

控制中斷: 
1.使用InterruptMask() and InterruptUnmask() 來對中斷進行屏蔽和解屏蔽。 
2.爲了對一箇中斷解屏蔽,你必須使用與屏蔽相同的數字來操作。 
3.使用 InterruptLock() and InterruptUnlock() 來失能和使能中斷。在SMP中使用自旋鎖來同步中斷 
注:Mask/unmask是在PIC(Programmable Interrupt Controller)中進行 
Disable/enable 是在CPU中進行。

綁定和解除綁定Attach & Detach? 
 
註解:在開始時,內核屏蔽了所有中斷,來避免軟件不關心的硬件中斷開銷。 
當一箇中斷髮生時,內核將控制和決定是哪一個中斷。它將遍歷這個中斷的所有handlers和event。對於enent,它將event入隊。對於handler,它將準備MMU來啓動進程,然後調用handler。如果handler返回一個event,它將入隊。在所有的event和handler都完成時,內核將給PIC一個EOI。一旦所用中斷都完成時,內核將遍歷所有event隊列,然後發生調度,然後返回到最高的READY狀態的線程。 
 
註解:這個例子展示的內容對於支持共享中斷的bus(PCI)來說很有用。 
這兒有兩個主要的硬件中斷架構:edge-sensitive and level-sensitive. 
在edge-sensitive架構中,不論硬件中斷線狀態合適改變,中斷都將被註冊。存在問題:如果一個設備觸發一箇中斷,中斷服務服務程序(ISR)將被調用。如果另一個設備也觸發了這個中斷,在中斷服務程序復位了第一個中斷前,非額外中斷將被生成給系統,因爲當總線正在被第一個設備驅動時,這兒沒有第二個edge了。 
在level-sensitive架構中,當中斷線是激活狀態時,中斷也被當做激活。當內核產生一個EOI,如果還存在激活狀態的中斷線時,ISR將被立即再次調用來服務下一個設備。因此在此架構中,ISR必須要清理中斷源,或者在返回之前,屏蔽它。 
這種清理clear在process level不會被執行。屏蔽mask在InterruptAttachEvent()中是自動執行的。

應該綁定一個handler還是event? 
1.對於qnx系統,內核是一個單一故障點。 
綁定handler會增加單一故障點,event不會。 
2 . event的debug更簡單。(ISR不能單步debug) 
3 . 在線程中執行h/w操作時,有完整的系統功能。 
4.event比handler有更小的系統開銷。 
(使用event時,不需要MMU工作來取得進程空間操作權) 
5 . 爲每個中斷調度線程會產生更多的系統開銷 
6 . handler比線程調度有更小的latency。

2.中斷服務子程序中的進程間通信 
方法: 
1.SIGEV_INTR/InterruptWait() 
最簡單,最快速;必須服務一個線程;queue深度只有1 
2.pulse 
在頻道中能有多個線程來等待接收消息;能入隊;最複雜 
3.Signal 
使用一個signal handler是最費資源的,但是在使用sigwaitinfo()時,比pulse更快一點;能入隊

等待中斷髮生最簡單的方法:

InterruptWait (reserved, reserved);
1
等待線程必須是一開始綁定handler的線程。

使用pulse來通知:

#define INTR_PULSE _PULSE_CODE_MINAVAIL
struct sigevent event;
main ()
{
    ...
    chid = ChannelCreate( 0 );
    coid = ConnectAttach( ND_LOCAL_NODE, 0, chid, _NTO_SIDE_CHANNEL, 0 );
    SIGEV_PULSE_INIT( &event, coid, MyPriority, INTR_PULSE, 0 );
    InterruptAttach( intnum, handler, NULL, 0, _NTO_INTR_FLAGS_TRK_MSK );
    for (;;) 
    {
        rcvid = MsgReceive( chid, ... );
        if (rcvid == 0) 
        {
        // we got a pulse
        }
    }
}
const struct sigevent *
handler (void *area, int id) 
{
    // do whatever work is required
    return (&event); // wake up main thread
}

或者:

const struct sigevent *
intHandler (void *not_used, int id)
{
    ...
    if (nothing_to_report) 
    {
        return (NULL);
    } 
    else 
    {
        if (low_priority_event)
        {
            return (&lowpri_event);
        } 
        else
        {
            return (&highpri_event);
        }
    }
    ...
}
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章