Le variabili globali normali non sono per CPU. Le variabili automatiche sono in pila e le diverse CPU usano stack diversi, quindi naturalmente ottengono variabili separate.
Immagino che ti riferisci all'infrastruttura variabile per CPU di Linux.
La maggior parte della magia è qui (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())
La macro RELOC_HIDE(ptr, offset)
avanza semplicemente ptr
dalla data di offset in byte (a prescindere dal tipo di puntatore).
Cosa fa?
- Quando si definisce
DEFINE_PER_CPU(int, x)
, un intero __per_cpu_x
viene creato nella sezione speciale .data.percpu
.
- Quando il kernel è caricato, questa sezione viene caricata più volte, una volta per CPU (questa parte della magia non è nel codice sopra).
- L'array
__per_cpu_offset
è riempito con le distanze tra le copie. Supponendo che vengano utilizzati 1000 byte di dati per CPU, __per_cpu_offset[n]
conterrà 1000*n
.
- Il simbolo
per_cpu__x
verrà riposizionato, durante il caricamento, alla CPU 0 per_cpu__x
.
__get_cpu_var(x)
, quando è in esecuzione sulla CPU 3, verrà convertito in *RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])
. Questo inizia con la CPU 0 x
, aggiunge l'offset tra i dati della CPU 0 e quelli della CPU 3, e alla fine dereferenzia il puntatore risultante.
Grazie per il tuo ansser, ma ho ancora alcune domande, nuove da smp, quindi, senza offesa alla tua idea. In primo luogo, ho pensato che lo stesso processo avrebbe dovuto avere lo stesso stack, qui la definizione del thread in POSIX "... e le variabili automatiche, sono accessibili a tutti i thread nello stesso processo.". Le variabili automatiche sono condivise dai thread. Un diverso processore potrebbe avere un registro di segmenti di stack diverso, ma il contenuto dovrebbe essere lo stesso. In secondo luogo, possiamo dire che possiamo anche accedere alla variabile della cpu se vogliamo, basta ripristinare l'offset ottenuto da percpu? – dspjm
Quando due thread chiamano la funzione 'pippo', che ha una variabile automatica' x', ci sono due pile e due istanze di 'x'. Ognuno ha un indirizzo diverso e entrambi i thread possono accedere a entrambi, se hanno l'indirizzo. Con le variabili per-cpu di Linux, 'per_cpu (var, cpu)' consente di accedere alle variabili di cpu. – ugoren
In che modo la sezione .data.percpu determina se la variabile percpu è dichiarata nello stack o nell'heap? – user31986