2013-06-07 3 views
13

На многопроцессорной основе каждое ядро ​​может иметь свои собственные переменные. Я думал, что они разные переменные в разных адресах, хотя они находятся в одном процессе и имеют одно и то же имя.Как указатели percpu реализованы в ядре Linux?

Но мне интересно, как ядро ​​реализует это? Предоставляет ли он часть памяти для хранения всех указателей percpu и каждый раз, когда перенаправляет указатель на определенный адрес со сдвигом или что-то еще?

ответ

20

Нормальные глобальные переменные не относятся к процессору. Автоматические переменные находятся в стеке, а разные процессоры используют разные стеки, поэтому, естественно, они получают отдельные переменные.

Думаю, вы имеете в виду инфраструктуру переменных для каждого процессора Linux.
Большая часть магии здесь (asm-generic/percpu.h):

extern unsigned long __per_cpu_offset[NR_CPUS]; 

#define per_cpu_offset(x) (__per_cpu_offset[x]) 

/* Separate out the type, so (int[3], foo) works. */ 
#define DEFINE_PER_CPU(type, name) \ 
    __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name 

/* 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()) 

Макрос RELOC_HIDE(ptr, offset) просто продвигает ptr на заданное смещение в байтах (независимо от типа указателя).

Что это?

  1. При определении DEFINE_PER_CPU(int, x), целое __per_cpu_x создается в специальном .data.percpu разделе.
  2. Когда ядро ​​загружено, этот раздел загружается несколько раз - один раз на процессор (эта часть магии не находится в коде выше).
  3. Массив __per_cpu_offset заполнен расстояниями между копиями. Предположим, что используются 1000 байт данных за процессор, __per_cpu_offset[n] будет содержать 1000*n.
  4. Символ per_cpu__x будет перемещен во время загрузки на CPU 0's per_cpu__x.
  5. __get_cpu_var(x), при запуске на CPU 3, перейдет на *RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3]). Это начинается с CPU x, добавляет смещение между данными CPU 0 и CPU 3, и в конечном итоге разыгрывает результирующий указатель.
+0

Спасибо за ваш анссер, но у меня все еще есть некоторые вопросы, новые для smp, поэтому не обижайтесь на вашу идею. Во-первых, я думал, что один и тот же процесс должен иметь один и тот же стек, вот определение потоков в POSIX «... и автоматические переменные доступны для всех потоков в одном процессе». Автоматическая переменная совместно используется потоками. У другого процессора может быть другой регистр сегмента стека, но контент должен быть одинаковым. Во-вторых, можем ли мы сказать, что мы можем также получить доступ к переменной другого процессора, если хотим, просто отбросить смещение, полученное percpu? – dspjm

+0

Когда два потока вызывают функцию 'foo', которая имеет автоматическую переменную' x', есть два стека и два экземпляра 'x'. Каждый из них имеет другой адрес, и оба потока могут получить доступ к обоим, если они имеют адрес. С переменными per-cpu от Linux 'per_cpu (var, cpu)' позволяет вам обращаться к любым переменным процессора. – ugoren

+0

Как раздел .data.percpu определяет, объявлена ​​ли переменная percpu в стеке или куче? – user31986