Новий інтерфейс percp u

У ядрах серії 26 запропоновано новий інтерфейс, іменований percpu,  який служить для створення даних і роботи з даними, повязаними з певним процесором Цей інтерфейс узагальнює попередній приклад При використанні нового підходу робота з per-CPU-даними спрощується

Розглянутий раніше метод роботи з даними, які повязані з певним процесором, є цілком законним Новий інтерфейс виник з необхідності мати більш простий і потужний метод роботи з даними, повязаними з процесорами, на великих компютерах з симетричною мультипроцесорного

Всі підпрограми оголошені у файлі Описи ж перебувають у файлах mm / slab с і

Робота з даними, повязаними

з процесорами, на етапі компіляції

Описати змінну, яка повязана з певним процесором, на етапі компіляції можна досить просто таким чином

DEFINE_PER_CPU(type, name)

Це опис створює змінну типу typ e з імям name, яка має інтерфейс звязку з кожним процесором в системі Якщо необхідно оголосити відповідну змінну з метою уникнення попереджень компілятора, то необхідно використовувати наступний макрос

DECLARE_PER_CPU(type, name)

Працювати з цими змінними можна за допомогою функцій get_cpu_va r () і put_cpu_va r () Виклик функції get_cpu_va r () повертає 1-значеніс (лівий операнд, 1-value) зазначеної змінної на поточному процесорі Цей виклик також забороняє витіснення коду в режимі ядра, а відповідний виклик функції put_cpu_va r () дозволяє витіснення

get_cpu_var (name) + + / * Збільшити на одиницю значення змінної name, повязане з поточним процесором * /

put_cpu_var () / * Дозволити витіснення коду в режимі ядра * / Можнотакжеполучитьдоступкпеременной, связаннойсіншимпроцесором

per_cpu (name, cpu) + + / * Збільшити значення змінної name

на зазначеному процесорі * /

Використовувати функцію per_cp u () необхідно обережно, так як цей виклик не забороняє витіснення коду і не забезпечує ніяких блокувань Необхідність використання блокувань при роботі з даними, повязаними з певним процесором, відпадає, тільки якщо до цих даних може звертатися один процесор Якщо процесори звертаються до даних інших процесорів, то необхідно використовувати блокування Будьте обережні Застосування блокувань розглядається в розділі 8, Введення в синхронізацію виконання коду ядра, і главі 9, Засоби синхронізації в ядрі .

Необхідно зробити ще одне важливе зауваження щодо створення даних повязаних з процесорами, на етапі компіляції Завантажувані модулі не можуть використовувати ті з них, які оголошені не в самому модулі, тому що компонувальник створює ці дані в спеціальних сегментах коду (а саме, datapercpu) Якщо необхідно використовувати дані, повязані з процесорами, в завантажуваних модулях ядра, то потрібно створити ці дані для кожного модуля окремо або використовувати динамічно створювані дані

Робота з даними процесорів на етапі виконання

Для динамічного створення даних, повязаних з процесорами, в ядрі реалізований спеціальний розподільник памяті, який має інтерфейс, аналогічний kmallo c () Ці функції дозволяють створити екземпляр ділянки памяті для кожного процесора в системі Прототипи цих функцій оголошені у файлі

таким чином

void * alloc percpu (type) / * Макрос * /

void *  alloc_percpu(size_t size, size_t align)

voidfree_percpu(constvoid*)

Функція allo c percpu () створює екземпляр обєкта заданого типу (виділяє память) для кожного процесора в системі Ця функція є оболонкою навколо функції __ alloc_percp u () Остання функція приймає в якості аргументів кількість байтів памяті, які необхідно виділити, і кількість байтів, але якому необхідно виконати вирівнювання цієї області памяті Функція alloc_percp u () виконує вирівнювання по тій кордоні, яка використовується для зазначеного типу даних Таке вирівнювання відповідає звичайній поведінці, як показано в наступному прикладі

struct rabid_cheetah = alloc_percpu(struct rabid_cheetah),

що аналогічно наступного виклику

struct rabid_cheetah =   alloc_percpu(sizeof (struct rabid_cheetah), alignof  (struct rabid_cheetah))

Оператор __ alignof_ _ – це розширення, що надається компілятором gcc, який повертає кількість байтів, по межі якого необхідно виконувати вирівнювання (або рекомендується виконувати для тих апаратних платформ, у яких немає жорстких вимог до вирівнювання даних в памяті) Синтаксис цього виклику такий же як і у оператора sizeo f () У прикладі, показаному нижче, для апаратної платформи х86 буде повернуто значення 4

  alignof__ (unsigned long)

Пр і передачі 1-значення (ліве значення, lvalue) повертається максимально можливе вирівнювання, які е може потребоватьс я для цього 1-значення Наприклад, 1-значення всередині структури може мати більше значення вирівнювання, ніж це необхідно для зберігання того ж типу даних за межами структури, що повязано з особливостями вирівнювання структур даних у памяті Проблеми вирівнювання більш детально розглянуті в главі 19, Переносимість.

Відповідний виклик функції freepercp u () звільняє память, яку займають відповідні дані на всіх процесорах

Функції alloc_percp u () і __ alloc_percp u () повертають покажчик, який використовується для непрямої посилання на динамічно створені дані, повязані з кожним процесором в системі Для простого доступу до даних ядро ​​надає два наступних макросу

get_cpu_ptr (ptr) / * Повертає вказівник типу void на дані, відповідні параметру ptr, повязані з поточним процесом * /

put_cpu_ptr (ptr) / * Готове, дозволяємо витіснення коду в режимі ядра

*/

Макрос get_cpu_pt r () повертає покажчик на екземпляр даних, повязаних з поточним процесором Цей виклик також забороняє витіснення коду в режимі ядра, яке знову дозволяється викликом функції  put_cpu_pt r ()

Розглянемо приклад використання цих функцій Звичайно, цей приклад не зовсім логічний, тому що память звичайно необхідно виділяти один раз (наприклад, в деякій функції ініціалізації), використовувати її в різних необхідних місцях, а потім звільнити також один раз (наприклад, в деякій функції, яка викликається при завершенні роботи) Проте цей приклад дозволяє пояснити особливості використання

void*percpu_ptr

unsigned long *foo

percpu_ptr = alloc_percpu(unsigned long)

if (ptr)

/ * Помилка виділення памяті . * /

foo = get_cpu_ptr(percpu_ptr)

/ * Працюємо з даними foo . * /

put_cpu_ptr(percpu_ptr)

Ще одна функція – per_cpu_ptr () – повертає екземпляр даних, повязаних із зазначеним процесором

per_cpu_ptr(ptr, cpu)

Ця функція не забороняє витіснення в режимі ядра Якщо ви чіпаєте дані, повязані з іншим процесором, то, ймовірно, необхідно застосувати блокування

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*