Linux RT (2) - 하 드 실시 간 Linux (RT - Preempt Patch) 의 중단 스 레 드 화

바닥 부분: 스 레 드 화 IRQ
스 레 드 인 터 럽 트 지원 은 2009 년 에 Linux 공식 커 널 에 들 어 갔 습 니 다. Thomas Gleixner 의 patch 를 참조 하 십시오.
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3aa551c9b4c40018f0e261a178e3d25478dc04a9
이 패 치 는 구동 이 통과 할 수 있 는 능력 을 제공 합 니 다.
int request_threaded_irq(unsigned int irq, irq_handler_t <strong>handler</strong>,
                         irq_handler_t <strong>thread_fn</strong>, unsigned long irqflags,
                         const char *devname, void *dev_id)
스 레 드 화 된 IRQ 를 신청 합 니 다. kernel 은 인 터 럽 트 된 기본 버 전에 irq /% d -% s 라 는 스 레 드 를 만 들 고% d 는 인 터 럽 트 번호 에 대응 합 니 다.그 중 절반 (하 드 인 터 럽 트)
handler 는 필요 한 처리 작업 을 마치 고 IRQ 로 돌아 갑 니 다.WAKE_THREAD, 이후 kernel 은 irq /% d -% s 스 레 드 를 깨 우 고 이 kernel 스 레 드 는 호출 됩 니 다.
thread_fn 함수, 따라서 이 스 레 드 는 바닥 부분 이 됩 니 다.후속 유지보수 과정 에서 필 자 는 이 기능 을 더욱 보완 하 는 토론 에 참 여 했 고 후속 패 치 는 nested, oneshot 등의 지원 을 포함 하 며 상세 한 것 은 패 치 를 보십시오.
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=399b5da29b9f851eb7b96e2882097127f003e87c
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=70aedd24d20e75198f5a0b11750faabbb56924e2
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b25c340c195447afb1860da580fe2a85a6b652c5
이 기 제 는 현재 kernel 에서 매우 광범 위 하 게 사용 되 고 있 으 며, softirq (tasklet 포함) 와 work quue 에 이 어 또 하나의 중간 부분 을 부 러 뜨리 는 방식 이 라 고 볼 수 있다.
상단: 강제 스 레 드 화
Linux RT - Preempt 을 사용 하면 기본적으로 request 를 강제로 통과 합 니 다.irq () 가 신청 한 IRQ 의 상단 함수 가 스 레 드 에서 실 행 됩 니 다. requestirq 의 원형 은:
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
            const char *name, void *dev)
{                        
        return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}      
이 는 request 를 통 해irq () 가 신청 한 IRQ 는 Rt - Preepmt 가 없 는 상태 에서 kernel 은 irq 스 레 드 를 만 들 지 않 습 니 다. 마지막 으로 request 를 호출 하기 때 문 입 니 다.threaded_irq () 때 전 달 했 어 요.
thread_fn
NULL。
RT - Preempt Patch 를 사용 할 수 있 는 경우, 그 중의 genirq - force - threading. patch 는 ARM 에 threaded irq 를 강제로 사용 합 니 다.
Index: linux-stable/arch/arm/Kconfig
===================================================================
--- linux-stable.orig/arch/arm/Kconfig
+++ linux-stable/arch/arm/Kconfig
@@ -40,6 +40,7 @@ config ARM
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select HARDIRQS_SW_RESEND
+       select IRQ_FORCED_THREADING
        select CPU_PM if (SUSPEND || CPU_IDLE)
        select GENERIC_PCI_IOMAP
        select HAVE_BPF_JIT
RT - Preempt Patch 에서 사용 할 수 있 는 IRQFORCED_THREADING 의 경우 스 레 드 화 IRQ 가 없 었 던 이 케이스 를 강제 스 레 드 화 합 니 다. 코드 는 참조setup_irq():
 887 static int
 888 __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 889 {
 890         ...
 903 
 904         /*
 905          * Check whether the interrupt nests into another interrupt
 906          * thread.
 907          */
 908         nested = irq_settings_is_nested_thread(desc);
 909         if (nested) {
 910                 ...
 920         } else {
 921                 if (irq_settings_can_thread(desc))
 922                         irq_setup_forced_threading(new);
 923         }
 925         /*
 926          * Create a handler thread when a thread function is supplied
 927          * and the interrupt does not nest into another interrupt
 928          * thread.
 929          */
 930         if (new->thread_fn && !nested) {
 931                 struct task_struct *t;
 932 
 933                 t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
 934                                    new->name);
 935                 ...
 939                 /*
 940                  * We keep the reference to the task struct even if
 941                  * the thread dies to avoid that the interrupt code
 942                  * references an already freed task_struct.
 943                  */
 944                 get_task_struct(t);
 945                 new->thread = t;
 946         }
그 중의 921 줄 을 중점적으로 살 펴 보 자.
 867 static void irq_setup_forced_threading(struct irqaction *new)
 868 {
 869         if (!force_irqthreads)
 870                 return;
 871         if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
 872                 return;
 873 
 874         new->flags |= IRQF_ONESHOT;
 875 
 876         if (!new->thread_fn) {
 877                 set_bit(IRQTF_FORCED_THREAD, &new->thread_flags);
 878                 new->thread_fn = new->handler;
 879                 new->handler = irq_default_primary_handler;
 880         }
 881 }
878 줄 과 879 줄 은 원래 의
handler 복사
thread_fn, 그리고 강제로 원래 의
handler 변경
irq_default_primary_handler (), 이 함 수 는 사실 신 마 는 하지 않 고 IRQ 로 돌아 갑 니 다.WAKE_THREAD:
 613 /*
 614  * Default primary interrupt handler for threaded interrupts. Is
 615  * assigned as primary handler when request_threaded_irq is called
 616  * with handler == NULL. Useful for oneshot interrupts.
 617  */
 618 static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
 619 {
 620         return IRQ_WAKE_THREAD;
 621 }
874 번 째 IRQF원 스 핫 은 우리 가 앞에서 말 한 원 샷 기능 을 사용 했다.
그래서 RT - prempt 는 실제 적 으로 원래 의 윗부분 과 밑부분 을 녹 였 는데 지금 은 가짜 윗부분 을 위 조 했 습 니 다. 이것 은 IRQ 로 직접 돌아 갈 뿐 입 니 다.WAKE_THREAD 태그 일 뿐 이 야.
인 터 럽 트 가 발생 한 후 리 눅 스 RT - prempt 가 처리 하 는 전 과정 을 살 펴 보 겠 습 니 다. 먼저 넘 어 갑 니 다.
arch/arm/kernel/entry-armv.S arch/arm/include/asm/entry-macro-multi.S
어 셈 블 리 입구, arm / kernel / irq. c 아래 asmdo_IRQ 、handle_IRQ, 이후 generic handleirq_event_percpu () 호출 됨:
133 handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
134 {
135         irqreturn_t retval = IRQ_NONE;
136         unsigned int flags = 0, irq = desc->irq_data.irq;
137 
138         do {
139                 irqreturn_t res;
140 
141                 trace_irq_handler_entry(irq, action);
142                 res = action->handler(irq, action->dev_id);
143                 trace_irq_handler_exit(irq, action, res);
144 
145                 if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts
", 146 irq, action->handler)) 147 local_irq_disable(); 148 149 switch (res) { 150 case IRQ_WAKE_THREAD: 151 /* 152 * Catch drivers which return WAKE_THREAD but 153 * did not set up a thread function 154 */ 155 if (unlikely(!action->thread_fn)) { 156 warn_no_thread(irq, action); 157 break; 158 } 159 160 irq_wake_thread(desc, action); 161 162 /* Fall through to add to randomness */ 163 case IRQ_HANDLED: 164 flags |= action->flags; 165 break; 166 167 default:
우 리 는 그 중의 142 번 째 줄 에 관심 을 가지 는데 본질 적 으로 irq 를 호출 하 는 것 이다.default_primary_handler (), 150 줄 받 았 습 니 다. irq 때문에default_primary_handler () 가 IRQ 를 되 돌려 주 었 습 니 다.WAKE_THREAD, 따라서 generic 의 중단 처리 절 차 는 irq 를 실행 합 니 다.wake_thread(desc, action);앞의 irq /% d -% s 스 레 드 를 깨 우 십시오. 이 스 레 드 의 코드 는?
789 static int irq_thread(void *data)
 790 {
 791         static const struct sched_param param = {
 792                 .sched_priority = MAX_USER_RT_PRIO/2,
 793         };
 794         struct irqaction *action = data;
 795         struct irq_desc *desc = irq_to_desc(action->irq);
 796         irqreturn_t (*handler_fn)(struct irq_desc *desc,
 797                         struct irqaction *action);
 798 
 799         if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD,
 800                                         &action->thread_flags))
 801                 handler_fn = irq_forced_thread_fn;
 802         else
 803                 handler_fn = irq_thread_fn;
 804 
 805         sched_setscheduler(current, SCHED_FIFO, ¶m);
 806         current->irq_thread = 1;
 807 
 808         while (!irq_wait_for_interrupt(action)) {
 809                 irqreturn_t action_ret;
 810 
 811                 irq_thread_check_affinity(desc, action);
 812 
<strong> 813                 action_ret = handler_fn(desc, action);</strong>
 814                 if (!noirqdebug)
 815                         note_interrupt(action->irq, desc, action_ret);
 816 
 817                 wake_threads_waitq(desc);
 818         }
 819 
 820         /*
 821          * This is the regular exit path. __fr

그 중 813 길드 는 최종 할당 값 을 thread 에 호출 합 니 다.fn 의 원래 handler, 이렇게 원래 중단 의 절반 은 irq 에 있 습 니 다.thread 에서 실행 되 었 습 니 다. 이른바 상단 의 스 레 드 화 를 실현 하 였 습 니 다.
정상 반 부 를 돌아 가 는 스 레 드 화 는 물론 RT - Preempt 을 할 수 있 는 상황 에서 우 리 는 정상 반 부 를 돌아 가 는 스 레 드 화 과정 을 통 해 앞의 강력 한 변경 을 피 할 수 있 습 니 다. 중단 을 신청 할 때 IRQ 를 설정 할 수 있 습 니 다.NOTHREAD 로고, 예 를 들 어 patch:
Subject: arm: Mark pmu interupt IRQF_NO_THREAD
From: Thomas Gleixner <[email protected]>
Date: Wed, 16 Mar 2011 14:45:31 +0100

PMU interrupt must not be threaded. Remove IRQF_DISABLED while at it
as we run all handlers with interrupts disabled anyway.

Signed-off-by: Thomas Gleixner <[email protected]>
---
 arch/arm/kernel/perf_event.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-stable/arch/arm/kernel/perf_event.c
===================================================================
--- linux-stable.orig/arch/arm/kernel/perf_event.c
+++ linux-stable/arch/arm/kernel/perf_event.c
@@ -430,7 +430,7 @@ armpmu_reserve_hardware(struct arm_pmu *
                }   
 
                err = request_irq(irq, handle_irq,
-                                 IRQF_DISABLED | IRQF_NOBALANCING,
+                                 IRQF_NOBALANCING | IRQF_NO_THREAD,
                                  "arm-pmu", armpmu);
                if (err) {
                        r_err("unable to request IRQ%d for ARM PMU counters
",

좋은 웹페이지 즐겨찾기