설명 DEFINE_PER_CPU(struct runqueue, runqueues);거대하다

우선,arch/i386/kernel/vmlinux.lds
  /* will be freed after init */

  . = ALIGN(4096);		/* Init code and data */

  __init_begin = .;



  /*  :) */

  

  . = ALIGN(32);

  __per_cpu_start = .;

  .data.percpu  : { *(.data.percpu) }

  __per_cpu_end = .;

  . = ALIGN(4096);

  __init_end = .;

  /* freed after init ends here */




이 설명은 __per_cpu_start 및__per_cpu_end 표식.data.percpu 이 섹션의 시작과 끝
그리고 전체.data.percpu 이 섹션은 모두 __init_begin 및 __init_end 사이,
즉, 이 섹션이 차지하는 메모리는 시스템이 시작된 후에 방출(free)된다는 것이다
있다
#define DEFINE_PER_CPU(type, name)\
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
그래서
static DEFINE_PER_CPU(struct runqueue, runqueues);
확장됩니다.
__attribute__((__section__(".data.percpu"))) __typeof__(struct runqueue) per_cpu__runqueues;
바로data.percpu 이 섹션에서 변수per_를 정의했습니다.cpu__runqueues,
그 유형은structrunqueue입니다.사실 여기 이른바 변수per_cpu__runqueues,
사실은 이 변수의 주소를 표시하는 편이량이다.
--------------------
그 다음, 시스템이 시작되면 start_kernel () 에서 다음 함수를 호출합니다.
unsigned long __per_cpu_offset[NR_CPUS];



static void __init setup_per_cpu_areas(void)

{

	unsigned long size, i;

	char *ptr;

	/* Created by linker magic */

	extern char __per_cpu_start[], __per_cpu_end[];



	/* Copy section for each CPU (we discard the original) */

	size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);

#ifdef CONFIG_MODULES

	if (size < PERCPU_ENOUGH_ROOM)

		size = PERCPU_ENOUGH_ROOM;

#endif



	ptr = alloc_bootmem(size * NR_CPUS);



	for (i = 0; i < NR_CPUS; i++, ptr += size) {

		__per_cpu_offset[i] = ptr - __per_cpu_start;

		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);

	}

}




이 함수에서 각 CPU에 전용 데이터 영역을 할당하고data.percpu의 데이터를 복사합니다.
CPU마다 하나씩 있습니다.데이터로부터__per_cpu_start에서 각 CPU 자체의 전용 데이터 영역으로 옮겼습니다.
따라서 그 변수를 액세스하면 원래의 값을 사용할 수 없습니다. 예를 들어 액세스per_cpu__runqueues
per_를 더 이상 사용할 수 없습니다.cpu__runqueues입니다. 편이량 조정이 필요합니다.
각 CPU에 고유한 전용 데이터 영역의 첫 번째 주소를 추가해야 함__per_cpu_start 오프셋
여기서 바로 __per_cpu_offset[i], CPU i의 전용 데이터 영역은
__per_cpu_start 오프셋은 __per_cpu_offset[i].
이렇게 하면 전유 데이터 구역의 각 변수의 새로운 주소를 편리하게 계산할 수 있다. 예를 들어per_cpu_runqueues,
새 주소가per_cpu_runqueues+__per_cpu_offset[i].
이런 처리를 거쳐서..data.percpu 이 섹션은 시스템을 초기화한 후에 방출할 수 있습니다.
--------------------
퍼cpu의 변수를 어떻게 저장하는지 다시 봅시다
/* This macro obfuscates arithmetic on a variable address so that gcc

   shouldn't recognize the original var, and make assumptions about it */

#define RELOC_HIDE(ptr, off)					\

  ({ unsigned long __ptr;					\

    __asm__ ("" : "=g"(__ptr) : "0"(ptr));		\

    (typeof(ptr)) (__ptr + (off)); })



/* var is in discarded region: offset to particular copy we want */

#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))

#define __get_cpu_var(var) per_cpu(var, smp_processor_id())



#define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); }))




__get_cpu_var (runqueues), 등효적으로 확장
__per_cpu_offset[smp_processor_id()] + per_cpu__runqueues
그리고 lvalue입니다. 즉, 값을 부여할 수 있다는 것입니다.
이게 바로 상술per_cpu__runqueues 변수는 CPU의 전용 데이터 영역에 있는 새 주소입니다.
서로 다른per cpu 변수는 서로 다른 편이량을 가지고 서로 다른 CPU는 전용 데이터 구역의 첫 번째 주소가 다르기 때문에
따라서 __를 통해get_cpu_var () 는 다른 변수에 액세스합니다.
--END

좋은 웹페이지 즐겨찾기