# 제6장: Xenomai의 커널 공간 프로그래밍

#### 실시간 인터럽트 핸들러 구현

실시간 시스템에서 인터럽트는 매우 중요한 역할을 한다. Xenomai에서는 실시간 성능을 위해 커널 공간에서 효율적인 인터럽트 핸들링을 제공한다. 이 장에서는 Xenomai의 커널 공간에서 실시간 인터럽트 핸들러를 구현하는 방법을 살펴보겠다.

**인터럽트 핸들러 개요**

인터럽트 핸들러는 하드웨어 이벤트에 대응하기 위해 실행되는 함수이다. Xenomai에서는 일반 리눅스 커널과 실시간 인터럽트 핸들러를 구분하여 프로세스가 일정 시간 내에 응답할 수 있도록 한다. 이를 통해 시스템은 높은 응답성을 유지하게 된다.

**인터럽트 핸들러 등록**

Xenomai의 인터럽트 핸들러를 등록하기 위해 `rtdm_irq_request` 함수를 사용한다. 이 함수는 다음과 같은 매개 변수를 취한다.

```c
int rtdm_irq_request(rtdm_irq_t *irq_handle, 
                     unsigned int irq_num, 
                     rtdm_irq_handler_t handler, 
                     unsigned int flags, 
                     const char *device_name, 
                     void *arg);
```

* `irq_handle`: 인터럽트 핸들러 객체의 포인터
* `irq_num`: 인터럽트 요청 번호 (IRQ 번호)
* `handler`: 인터럽트 핸들러 함수
* `flags`: 인터럽트 요청 플래그
* `device_name`: 디바이스 이름
* `arg`: 핸들러 함수로 전달될 인자

**인터럽트 핸들러 함수 구현**

인터럽트 핸들러 함수는 다음과 같은 형태로 정의된다.

```c
int my_irq_handler(rtdm_irq_t *irq_handle) {
    /* 인터럽트 핸들링 코드 */
    return RTDM_IRQ_HANDLED;  // 핸들러가 인터럽트를 처리했음을 리턴
}
```

핸들러 함수의 반환 값은 다음과 같이 정의될 수 있다.

* `RTDM_IRQ_HANDLED`: 인터럽트가 성공적으로 처리되었음을 의미
* `RTDM_IRQ_NONE`: 처리되지 않은 인터럽트를 의미

예제 코드를 통해 인터럽트 핸들러를 등록하는 방법을 살펴보겠다.

```c
#include <rtdm/driver.h>

rtdm_irq_t my_irq;
int irq_number = 5;  // 예시로 사용하는 IRQ 번호

int my_irq_handler(rtdm_irq_t *irq_handle) {
    // 실제 처리 코드
    printk("Interrupt handled!\n");
    return RTDM_IRQ_HANDLED;
}

int init_module(void) {
    int ret;
    ret = rtdm_irq_request(&my_irq, irq_number, my_irq_handler, 0, "my_device", NULL);
    if (ret) {
        printk("Failed to request IRQ\n");
        return ret;
    }
    printk("IRQ requested successfully\n");
    return 0;
}

void cleanup_module(void) {
    rtdm_irq_free(&my_irq);
}
```

**인터럽트 핸들러 철회**

모듈이 언로드되거나 더 이상 인터럽트를 처리할 필요가 없을 때는 인터럽트 핸들러를 철회해야 한다. 이를 위해 `rtdm_irq_free` 함수를 사용한다.

```c
void cleanup_module(void) {
    rtdm_irq_free(&my_irq);
}
```

**실시간 특성 보장**

Xenomai의 인터럽트 핸들러는 RTDM(Real-Time Device Model) 아키텍처에 기반하여 높은 실시간 성능을 보장한다. RTDM 인터페이스는 디바이스 드라이버와 커널 모듈에 실시간 제약 조건을 부여하여 인터럽트 지연을 최소화하고, 예측 가능한 응답 시간을 제공한다.

#### 디버깅 및 최적화

**디버깅 인터럽트 핸들러**

Xenomai에서 디버깅은 다양한 도구의 사용을 통해 이루어진다. 일반적인 디버깅 도구로는 printk, Xenomai의 tracing 기능, 그리고 external 하드웨어 분석 도구 등이 있다.

* `printk` 함수로 간단한 디버깅 로그를 남길 수 있다.
* Xenomai는 `xeno_trace`를 통해 실행 중에 발생하는 이벤트를 추적할 수 있도록 한다.

```c
int my_irq_handler(rtdm_irq_t *irq_handle) {
    // 실제 처리 코드
    printk("Interrupt handled! Count: %d\n", irq_count);
    irq_count++;
    return RTDM_IRQ_HANDLED;
}
```

**성능 최적화**

인터럽트 핸들러의 성능을 최적화하는 것은 리소스 사용의 효율성을 높이고, 실시간 응답성을 개선하는 데 매우 중요하다. 다음은 몇 가지 최적화 전략이다.

1. **코드 최소화**: 인터럽트 핸들러는 빠르게 실행되어야 하므로, 가능한 한 코드의 양을 최소화해야 한다.
2. **작업 분산**: 긴 작업은 인터럽트 핸들러 외부에서 처리하도록 설계한다. 이를 위해 상위 반 처리(top half)와 하위 반 처리(bottom half)를 분산시킬 수 있다.
3. **부동 소수점 사용 피하기**: 부동 소수점 연산은 일반적으로 싱글 사이클 정수 연산보다 훨씬 느리다. 실시간 인터럽트 핸들러에서는 부동 소수점 사용을 피하는 것이 좋다.
4. **캐시 일치성 유지**: 캐시 일치성 문제를 최소화하기 위해 메모리 접근을 최적화한다.

#### 실습 예제

다음 예제는 간단한 GPIO 인터럽트 핸들러를 설정하고, LED를 토글하는 기능을 구현하는 예제이다. 이 예제는 BeagleBone Black과 같은 SBC(Single Board Computer)를 사용할 때 유용하다.

```c
#include <rtdm/driver.h>

#define GPIO_NUMBER  48   // GPIO1_16
#define IRQ_NUMBER   32   // Example IRQ for GPIO

static rtdm_irq_t my_irq;
static volatile int led_state = 0;

int gpio_irq_handler(rtdm_irq_t *irq_handle) {
    // GPIO 핀 상태 반전
    if (led_state) {
        // Turn LED off
    } else {
        // Turn LED on
    }
    led_state = !led_state;

    // Clear the interrupt (specific to the hardware)
    // gpio_clear_interrupt(GPIO_NUMBER);

    return RTDM_IRQ_HANDLED;
}

int __init init_module(void) {
    int ret;

    // GPIO 초기화 코드 (보드 및 설정에 따라 다름)
    // gpio_request(GPIO_NUMBER);
    // gpio_direction_input(GPIO_NUMBER);

    ret = rtdm_irq_request(&my_irq, IRQ_NUMBER, gpio_irq_handler, 0, "gpio_device", NULL);
    if (ret) {
        printk("Failed to request IRQ\n");
        return ret;
    }
    printk("GPIO IRQ requested successfully\n");

    return 0;
}

void __exit cleanup_module(void) {
    rtdm_irq_free(&my_irq);
    // GPIO 해제 코드
    // gpio_free(GPIO_NUMBER);
}

module_init(init_module);
module_exit(cleanup_module);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple GPIO IRQ handler example");
```

***

이 장에서는 Xenomai를 사용하여 커널 공간에서 실시간 인터럽트 핸들러를 구현하는 방법을 설명하였다. 인터럽트 핸들러는 실시간 시스템에서 매우 중요한 요소이며, 높은 응답성과 효율을 유지하기 위해 다양한 최적화 기법을 적용할 수 있다. 실시간 인터럽트 핸들링을 통해 더 예측 가능하고 빠른 응답성을 지닌 시스템을 구축할 수 있다.
