Нормальные глобальные переменные не относятся к процессору. Автоматические переменные находятся в стеке, а разные процессоры используют разные стеки, поэтому, естественно, они получают отдельные переменные.
Думаю, вы имеете в виду инфраструктуру переменных для каждого процессора 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
на заданное смещение в байтах (независимо от типа указателя).
Что это?
- При определении
DEFINE_PER_CPU(int, x)
, целое __per_cpu_x
создается в специальном .data.percpu
разделе.
- Когда ядро загружено, этот раздел загружается несколько раз - один раз на процессор (эта часть магии не находится в коде выше).
- Массив
__per_cpu_offset
заполнен расстояниями между копиями. Предположим, что используются 1000 байт данных за процессор, __per_cpu_offset[n]
будет содержать 1000*n
.
- Символ
per_cpu__x
будет перемещен во время загрузки на CPU 0's per_cpu__x
.
__get_cpu_var(x)
, при запуске на CPU 3, перейдет на *RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])
. Это начинается с CPU x
, добавляет смещение между данными CPU 0 и CPU 3, и в конечном итоге разыгрывает результирующий указатель.
Спасибо за ваш анссер, но у меня все еще есть некоторые вопросы, новые для smp, поэтому не обижайтесь на вашу идею. Во-первых, я думал, что один и тот же процесс должен иметь один и тот же стек, вот определение потоков в POSIX «... и автоматические переменные доступны для всех потоков в одном процессе». Автоматическая переменная совместно используется потоками. У другого процессора может быть другой регистр сегмента стека, но контент должен быть одинаковым. Во-вторых, можем ли мы сказать, что мы можем также получить доступ к переменной другого процессора, если хотим, просто отбросить смещение, полученное percpu? – dspjm
Когда два потока вызывают функцию 'foo', которая имеет автоматическую переменную' x', есть два стека и два экземпляра 'x'. Каждый из них имеет другой адрес, и оба потока могут получить доступ к обоим, если они имеют адрес. С переменными per-cpu от Linux 'per_cpu (var, cpu)' позволяет вам обращаться к любым переменным процессора. – ugoren
Как раздел .data.percpu определяет, объявлена ли переменная percpu в стеке или куче? – user31986