2017-10-06 13 views
1

다른 코어의 특정 지점에서 실행중인 스레드를 확인해야하는 커널 드라이버를 작성 중입니다. 드라이버는 코어 당 하나의 커널 스레드를 실행하며 특정 작업을 수행하기 위해 때때로 스레드 중 일부를 동기화해야합니다. 디버깅 로그에서 관찰 할 수있는 것은 때때로 한 스레드가 다른 스레드를 너무 많이 기다리는 경우입니다. 나는 다른 코어에 __preempt_count을 저장하여 softirq/hardirq 또는 preemption disabled가 스레드를 지연시키는 지 확인하는 패치를 작성했습니다. 또한 FTRACE를 사용하여 irqsoff 및 preemptirqsoff를 검사하여 IRQ의 최대 지속 시간을 해제하고 선매를 사용하지 않도록 설정했습니다.SMP 기반 Linux 시스템에서 다른 CPU의 "current_task"포인터에 액세스

지금까지 20 밀리 초 이하의 인터럽트를 비활성화하는 kerneloops 스레드를 발견 할 수 있었는데, 너무 오래 발견되었습니다. systemctl disable kerneloops을 신고이 문제를 해결했습니다.

이제 일부 선매 해제 된 창을 처리하는 것처럼 보입니다. 나중에이 드라이버를 분석하기 위해 다른 코어에서 특정 시점에 어떤 스레드가 실행되고 있는지 파악하는 방법이 필요합니다. 나는 IRQ entry/exit 이벤트와 함께 FTRACE를 주로 사용하려고 노력하고 있는데, trace_printk을 사용하여 ftrace 버퍼의 일부 디버그 로그를 하나의 로그 등에 넣을 수 있습니다.

(current ptr) current_task 구조에 액세스하여 작업 이름 (또는 pid 값)을 제공하는 comm 필드를 인쇄하십시오. 하지만이 일을 처리하는 데 어려움을 겪고 있습니다.

__preempt_count 위해 나는 아무 문제가 없었다 :

int *p = per_cpu_ptr(&__preempt_count,cpu); 
pr_info("Preempt count of cpu%u is 0x%08x\n",cpu,*p); 

지금까지 내가 선언 또는 CPU 변수에 따라 접근 아무 문제가 없었다,하지만 액세스하려고 할 때 어떤 이유로 current_task 포인터가 페이지 오류를 트리거합니다.

char buf[10]; 
struct task_struct *task = per_cpu_ptr(current_task,cpu); 
snprintf(buf,8,"%s",task->comm); 
pr_info("Task name: %s",buf); 

위의 코드는 항상 페이지 오류, NULL ptr bla bla를 트리거합니다. 지금까지 그 이유를 찾지 못했습니다. task에 대한 포인터 값을 인쇄하려했는데 같은 페이지 오류가 발생했습니다.

다른 코어가 주소에 액세스 할 수 없기 때문에 이럴 수 있습니까? 커널 공간에서 afaik 경우가 아니어야합니다. 나는 또한 핵심 변수마다 지금까지 아무런 문제도 없었으며 이것으로 많은 것을 해냈다.

결론 : 다른 코어의 current_task에 액세스하고 comm/pid 필드를 인쇄하는 올바른 방법은 무엇입니까?

많은 감사,

다니엘

답변

0

나는 마지막으로 잘못 알아 냈어. __preempt_countcurrent_task의 차이점은 첫 번째 변수는 int 변수로 정의되고 두 번째 변수는 구조체에 대한 포인터로 정의된다는 것입니다. 즉, 첫 번째 변수는 변수로 정의되고 두 번째 변수는 포인터로 정의됩니다.

이제 CPU 당 변수를 자세히 살펴보면 배열과 같이 별도의 메모리 위치에 컴파일러가 할당 한 변수 일뿐입니다. 변수 Foo에 대한 per_cpu_ptr이 호출되면 매크로는 Foo[cpu]과 같은 값을 계산하지만, per_cpu_ptr은 변수의 실제 기본 주소가 필요합니다. 즉, &을 의미하므로 여기에서 시작하여 상대 주소 값을 계산할 수 있습니다.

선언 : foo = per_cpu_ptr(&__preempt_count,cpu),이 주소는 이미 = 주어진다 &__preempt_count

선언 다음 & 여기없는 것처럼 bar = per_cpu_ptr(current_task,cpu),이 주소는 제공되지 않습니다. current_task는 포인터이지만 current_task 배열의 기본 주소는 아닙니다.

위의 두 가지 경우 모두 per_cpu_ptr에 대한 인수가 포인터이지만 여기에 대한 이해가 잘못되었지만 실제로 전달해야하는 변수의 포인터가 무엇인지 분명하지 않았습니다. 이제는 분명합니다. 변수의 기본 주소 (var 또는 포인터는 중요하지 않음). 그러면 매크로가 해당 CPU의 상대 주소를 계산할 수 있습니다.

따라서 오른쪽 일 있다는 접근 : *per_cpu_var(&current_task,cpu)

또는 직접

bar = *per_cpu_var(&current_task,cpu);

로 변환

bar = per_cpu(current_task,cpu)