커널 타이머와 local_irq_disable() 비활성화 문제

tms320c5x의 이미지

디바이스 드라이버의 커널타이머도 타이머 인터럽트에 의해 동작하는걸로 이해하고 있고, local_irq_disable()은 인터럽트를 비활성시키는 함수로 아는데요. 아래 질문 요지는 local_irq_disable을 했는데 왜 커널타이머 루틴이 계속 수행하는지 입니다.

커널타이머는 1초마다 카운터 증가값을 찍는데, 응용에서 특정 저수준함수를 실행하면 그에 따른 드라이버 함수에서 local_irq_disable()을 실행하고 그다음에 약간의 지연루틴을 첨가합니다. 지연루틴 이유는 local_irq_disable 후에 지연동안 dmesg명령으로 커널타이머 카운트값이 계속 찍히는지 보려고 넣은거고 함수 끝엔 일부러 local_irq_enable()을 삭제한 상태입니다.
결과는 지연상태에서 dmesg명령을 2,3번 하면 타이머 카운터는 계속 증가해요. 하물며 함수 끝에 local_irq_enable()을 하지 않고 리턴된 후에 다른 루틴서 dmesg해도 계속 증가해요.

원래 최초 의도는, 유영창님 디바이스드라이버 책을 보며 외부인터럽트 시험을 하면서 local_irq_disable() 동작여부를 확인하려던 것이었는데, 외부인터럽트를 위해선 노트북에선 안되고 장비가 필요하므로 짱구 굴린게 커널타이머 핸들러 안에서 해당 외부인터럽트 서비스 함수를 호출하는 것인데 생각해보니 커널타이머도 결국 타이머인터럽트이니 local_irq_disable로 커널타이머 인터럽트를 활성/비활성해도 결국 인터럽트 활성/비활성을 확인하는 거지 싶어 그렇게 한건데요. 그런데 잘 안되는데 커널버전 차이인가 싶지만 local_irq_disable()은 지금도 쓰이고 있어 문제가 있진 않을거 같은데. 아니면 다른 인터럽트는 local_irq_disable이 동작하지만 커널타이머라 안되는건지...

[응용]

main()
{
dev = open("/dev/polldev", O_RDWR );
buff[0] = 0xff;
write(dev,buff,1 );//write 수행 후 바로 드라이버 실행 터미널에서 dmesg 여러차례 실행
....
}

[드라이버]
void cbktimer(struct timer_list *t)//커널타이머
{
_pKernelTimer *pstktdata = from_timer(pstktdata, t, timer);
pstktdata->tcnt++;
if(pstktdata->tcnt>=15)
{
pstktdata->tcnt=0;
poll_interrupt(POLL_IRQ, NULL);//커널타이머에서 인터럽트 함수 호출, 인터럽트를 외부에서의 입력 모사위해 인터럽트 핸들러 호출
}

timer_setup(&(pstKernelTimer->timer), cbktimer, (unsigned int)0);
pstKernelTimer->timer.expires=get_jiffies_64()+TIME_STEP;
add_timer(&(pstKernelTimer->timer));
}

irqreturn_t poll_interrupt(int irq, void *dev_id)//, struct pt_regs *regs)//인터럽트 핸들러
{
unsigned long flags;

local_save_flags(flags);
local_irq_disable();

if( ReadQCount < MAX_QUEUE_CNT )
{
Cirbuffer[ReadQHead]=127-ReadQHead;
ReadQHead = ( ReadQHead + 1 ) % MAX_QUEUE_CNT;
ReadQCount++;
}
local_irq_restore(flags);

wake_up_interruptible( &WaitQueue_Read );

return IRQ_HANDLED;
}

int poll_open (struct inode *inode, struct file *filp)
{
int i=-1;
//인터럽트 셋업
if( !request_irq( POLL_IRQ , poll_interrupt, IRQF_TRIGGER_FALLING, POLL_DEV_NAME, NULL) )
{
//outb( POLL_IRQ_ENABLE_MASK, POLL_CTRL_ADDR );
}
//커널타이머 셋업
pstKernelTimer=kmalloc(sizeof(_pKernelTimer), GFP_KERNEL);
timer_setup(&(pstKernelTimer->timer), cbktimer, (unsigned int)0);
pstKernelTimer->timer.expires=get_jiffies_64()+TIME_STEP;
add_timer(&(pstKernelTimer->timer));

return 0;
}

ssize_t poll_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
unsigned char status;
int loop;
unsigned long delaytime=0;
unsigned long flags;

local_save_flags(flags);
local_irq_disable();//인터럽트 비활성
//시간지연===>아래 코드 수행 중 터미널에서 dmesg실행하여 cbktimer 타이머핸들러가 계속 동작하는지 확인
delaytime=get_jiffies_64()+100*HZ/10;//about 10 seconds
while(jiffies schedule();

//local_irq_restore(flags);
return count;
}

unsigned int poll_poll( struct file *filp, poll_table *wait )
{
unsigned int mask = 0;

poll_wait( filp, &WaitQueue_Read, wait );

if( ReadQCount > 0 )
mask |= POLLIN | POLLRDNORM;

return mask;
}

int poll_release (struct inode *inode, struct file *filp)
{ ..}
struct file_operations poll_fops =
{ ..}
int poll_init(void)
{ ..}
void poll_exit(void)
{ ..}

module_init(poll_init);
module_exit(poll_exit);

MODULE_LICENSE("Dual BSD/GPL");

furmuwon의 이미지

멀티 코어 CPU 라 모든 Core 에서 인터럽트 발생합니다.
(cat /proc/interrupt 로 타이머 인터럽트 발생하는 것을 확인해 보세요)
local_irq.... 는 해당 코드 실행하는 core 만 인터럽트를 막습니다.

tms320c5x의 이미지

댓글 감사합니다.
제가 잘 이해한건지 모르겠는데요.
local_irq..가 실행하는 코어만 막을 수 있다면, 어쨋든 디바이스드라이버 프로그램이 돌고 있는 코어의 타이머가 disable 되어야 하는거 아닌가요?
아니면 드라이버가 실행되고 있는 코어의 커널타이머가 disable 되더라도 다른 코어의 타이머 인터럽트가 발생한다는 뜻인가요? 그래서 다른 코어의 타이머인터럽트가 발생해서 디바이스드라이버의 타이머 핸들러가 실행되어 카운터값을 계속 찍는다는 뜻인가요? 그렇다면 요즘 죄다 멀티코어인데, local_irq_disable()을 못쓴다는 얘기로 들리는데. 리눅스를 그렇게 만들진 않았을텐데.. 아래에서 poll_dev는 제가 등록한거구(외부인터럽트). 제가 timer_set(), add_timer()로 설정한, 그리고 비활성하려는 커널타이머가 LOC local timer interrupt 인가요? local_irq_disable() 해도 cpu0, cpu1 비활성화 된건 없고 둘다 계속 변해요. 펌웨어에서 인터럽트 핸들러 안에서 인터럽트 활성/비활성은 늘상 있는건데 리눅스에서 하려니 어렵네
CPU0 CPU1
0: 739520 0 IO-APIC 2-edge timer
1: 5095 0 IO-APIC 1-edge i8042
7: 0 0 IO-APIC 7-edge polldev
8: 0 1 IO-APIC 8-edge rtc0
9: 0 593 IO-APIC 9-fasteoi acpi
12: 0 96782 IO-APIC 12-edge i8042
16: 74203 42438 IO-APIC 16-fasteoi uhci_hcd:usb3, i915, ath9k
18: 0 0 IO-APIC 18-fasteoi uhci_hcd:usb8
19: 41 0 IO-APIC 19-fasteoi ehci_hcd:usb1, uhci_hcd:usb5, uhci_hcd:usb7, i801_smbus
21: 0 0 IO-APIC 21-fasteoi uhci_hcd:usb4
23: 0 449457 IO-APIC 23-fasteoi ehci_hcd:usb2, uhci_hcd:usb6
24: 1 0 PCI-MSI 2097152-edge enp4s0
25: 909 56036 PCI-MSI 512000-edge ahci[0000:00:1f.2]
26: 1310 0 PCI-MSI 442368-edge snd_hda_intel:card0
NMI: 353 352 Non-maskable interrupts
LOC: 124271 653180 Local timer interrupts
SPU: 0 0 Spurious interrupts

furmuwon의 이미지

이 후 추측하신 것이 맞다고 저도 생각합니다.
다른 core 에서 timer 가 count 되어서.... timer call back 수행 된다고 추측 합니다.
(저도 확인해본 사항은 아니고 아마도 그럴 것이다 라고 추측 합니다.)

local_irq_disable() 사용관련해서는... 저는 사용한 적이 한번도 없습니다.
리눅스 커널 소스에서 driver 디렉토리 밑에서 local_irq_disable 한번 검색해 보시면
제가 count 한 것으로는 82개 나오고 다른 종류 spin_lock_irq 로 검색해보니 14787 개가 나오네요.
요즘 대부분 멀티 코어이다 보니, 잘 사용되지 않는다는 것을 개수로 표현 하고 싶었고요
싱글코어에서는 local_irq_disable 만 쓰더라도 보호하고자 하는 자원이 보호 되는데
멀티코에어서는 불가능 하니 spin_lock_irq 종류가 있다는 것도 은연중에 표현하고 있습니다.

tms320c5x의 이미지

댓글 감사합니다. 다행히 님 말씀은 이해 잘 한 거군요.
제가 비 리눅스로 개발하다 리눅스 접한지 얼마 안됐는데 이번참에 리눅스로도 진출해볼려고 하니라, 학생수준처럼 공부하는게 아니라 개발실무선에서 이해하려고 하는데요.

님 말씀은 이해했지만 리눅스를 이해할 수 없네요. 펌웨어에서 인터럽트 처리시 핸들러 진입에서 os함수를 쓰던 cli 같은 어셈블을 쓰던 비활성하고 마지막에 활성하고 리턴하는건 일반적인데. 프로세스, 전역변수 동기화 등 때문에 말이죠. 이건 리눅스 공부할때도(유영창 리눅스디바이스드라이버) 해당되더군요. 그러니 제가 local_irq_disable, local_irq_save 등을 알테니까요.
그런데 드라이버 프로그램이 실행되고 있는 cpu 인터럽트를 잠시 막기위한 리눅스함수 local_irq_..가 다른 코어영향으로 프로그램 자체가 원하는 동작이 안된다는게 어렵네요. 이건 선택이 아니라 위에 이유처럼 때에 따라 해야만 하는 것인데 말이죠.
지금 이 연습은 노트북으로 하니 멀티코어때문에 그렇다면, 궁극적으론 x86이 아닌 임베디드 리눅스를 생각하고 있고, 그쪽은 싱글코어가 대부분이니 어쨋든 기억해야겠고, 근데 역시나 납득이 안되네요.
spin_lock_irq... 이건 책에 없던 거네. 이것도 공부해볼께요 뭔지..

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.