Контекст системного виклику

Як вже обговорювалося в розділі 3, Управління процесами, при виконанні системного виклику ядро ​​працює в контексті процесу Покажчик curren t вказує на поточне завдання, яке і є процесом, який виконує системний виклик

У контексті процесу ядро ​​може переходить в призупинене стан (наприклад, якщо системний виклик блокується при виклику функції або явно викликає функцію schedule ()), а також є повністю витісняється Ці два моменти важливі Можливість переходити в призупинене стан означає, що системний виклик може використовувати більшу частину функціональних можливостей ядра Як буде видно з глави 6, Переривання та обробка переривань, наявність можливості переходити в призупинене стан значно спрощує програмування ядра7 Той факт, що контекст процесу є витісняється, має на увазі, що, як і в просторі користувача, поточне завдання може бути витіснене іншим завданням Так як нове завдання може виконати той же системний виклик, необхідно переконатися, що системні виклики є реєнтерабельним Це дуже схоже на вимоги, висунуті для симетричної мультипроцессорной обробки Способи захисту, які забезпечують реєнтерабельним, описані в главі 8, Введення в синхронізацію виконання коду ядра, і в главі 9, Засоби синхронізації в ядрі.

Після завершення системного виклику керування передається назад у функцію system_cal l (), яка врешті-решт виробляє перемикання в простір користувача, і далі виконання користувальницького процесу триває

Остаточні кроки реєстрації системного виклику

Після того як системний виклик написаний, процедура його реєстрації в якості офіційного системного виклику тривіальна і полягає в наступному

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

• Для всіх підтримуваних апаратних платформ номер системної функції повинен бути визначений у файлі include / linux / unistdh

• Системний виклик повинен бути вкомпільовані в образ ядра (на противагу компіляції в якості завантажуваного модуля8) Це просто відповідає розміщенню коду в якому-небудь важливому файлі каталогу kernel/

7 обробника переривання й не можуть переходити в призупинене стан і, отже, більш обмежений и в своїх діях у порівнянні з системними викликами, які працюють в контексті процесу

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

Давайте більш детально розглянемо ці кроки на прикладі функції системного виклику, FОО () Спочатку функція sys_fоо () повинна бути додана в таблицю системних викликів Для більшості апаратних платформ таблиця системних викликів розміщується у файлі entry S і виглядає приблизно таким чином

ENTRY(sys_call_table)

.long sys_restart_syscall   /* 0 */

.long sys_exit

.long sys_fork

.long sys_read

.long sys_write

.long sys_open    /*    5    */

.long sys_timer_delete

.long sys_clock_settime

.long sys_clock_gettime     /* 280 */

.long sys_clock_getres

.long sys_clock_nanosleep

Необхідно додати новий системний виклик в кінець цього списку:

.long sys_foo

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

Далі необхідно додати номер системного виклику в заголовний файл include / asm / unistdh, який зараз виглядає приблизно так

/*

* This file contains the system call numbers

*/

#define   NR_restart_syscall    0

#define   NR_exit 1

#define   NR_fork 2

#define   NR_read 3

#define   HR_write 4

#define    NR_open 5

#define   NR_mq_unlink          278

#define   NR_mq_timedsend       279

#define    NR_mq_timedreceive    280

#define   NR_mq_notify          281

#define    NR_mq_getsetattr      282

В кінець файлу додається наступна рядок

#define   NR_foo 283

Зрештою необхідно реалізувати сам системний виклик FОО () Так як системний виклик повинен бути вкомпілорован в образ ядра у всіх конфігураціях, ми його помістимо у файл kernel / sysс Код необхідно розміщувати в найбільш підходящому файлі Наприклад, якщо функція належить до планування виконання процесів, то її необхідно поміщати в файл schedс

/*

* Sys_foo всіма улюблений системний виклик

*

* Повертає розмір стека ядра процесу

*/

asmlinkage long sys_foo(void)

{

return THREAD_SIZE

}

Це все Завантажте нове ядро Тепер з простору користувача можна викликати системну функцію foo ()

Доступ до системних викликів з простору користувача

У більшості випадків системні виклики підтримуються бібліотекою функцій мови С Користувальницькі додатки можуть отримувати прототипи функцій зі стандартних заголовків файлів і компонувати програми з бібліотекою С для використання вашого системного виклику (або бібліотечної функції, яка викликає ваш системний виклик) Однак якщо ви тільки що написали системний виклик, то малоймовірно, що бібліотека glib c вже його підтримує

На щастя, ОС Linux надає набір макросів-оболонок для доступу до системних викликів Вони дозволяють встановити вміст регістрів і виконати машинну інструкцію in t 50×80 Ці макроси мають імя syscall n (), деп – число від нуля до шести Це число відповідає числу параметрів, які повинні передаватися в системний виклик, так як макросу необхідна інформація про те, скільки очікується параметрів, і відповідно, потрібно записати ці параметри в регістри процесора Наприклад, розглянемо системний виклик open (), який визначений наступним чином

long open(const char &quotfilename, int flags, int model

Макрос для виклику цієї системної функції буде виглядати так

#define NR_open 5

_syscall3(long, NR_open, const char *, filename, int, flags, int, mode)

Після цього додаток може просто викликати функцію open ()

Кожен макрос приймає 2 + 2 * n параметрів Перший параметр відповідає типу значення, що повертається системного виклику Другий параметр – імя системного виклику Після цього слідують тип та імя кожного параметра в тому ж поряд-

ке, що і у системного виклику Постійна NR_open, яка визначена у файлі

, – це номер системного виклику У функцію на мові програмування С такий виклик перетворюється за допомогою вставок на мові асемблера, які виконують розглянуті в попередньому розділі кроки Значення аргументів поміщаються у відповідні регістри, і виконується програмне переривання, яке перехоплюється в режимі ядра Вставка даного макросу в додаток – це все, що необхідно для виконання системного виклику open ()

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

#define   NR_foo 283

  syscallO(long, foo)

int main ()

{

long stack_size

stack_size = foo ()

printf (Розмір стека ядра дорівнює% ld \ n, stack_size)

return 0

}

Чому не потрібно створювати системні виклики

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

Для створення нового інтерфейсу у вигляді системного виклику можуть бути наступні за.

• Системні виклики просто реалізувати і легко використовувати

• Продуктивність системних викликів в операційній системі Linux дуже висока

Можливі проти.

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

• Після того як системний виклик включений в стабільну серію ядра, він стає висіченим у камені. Інтерфейс не повинен змінюватися, щоб не порушити сумісності з прикладними користувацькими програмами

• Для кожної апаратної платформи необхідно реєструвати окремий системний виклик і здійснювати його підтримку

• Для простого обміну інформацією системний виклик – це стрільба з гармати по горобцях.

Можливі варіанти

• Реалізувати файл пристрою і використовувати функції rea d () і writ e () для цього пристрою, а також використовувати функцію ioct l () для маніпуляції специфічними параметрами або для отримання специфічної інформації

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

• Додати інформаційний файл у відповідному місці файлової системи sysfs

Для більшого числа інтерфейсів, системні виклики-це правильний вибір В операційній системі Linux намагаються уникати простого додавання системного низова для підтримки кожної повий, раптом що зявляється абстракції В результаті вийшов дивно чіткий рівень системних викликів, який приніс дуже мало розчарувань і привів до малого числа не рекомендованих до використання та застарілих (deprecated) інтерфейсів (тобто таких, які більше не використовуються або не підтримуються)

Мала частота додавання нових системних викликів свідчить про те, що Linux-це стабільна операційна система з повним набором функцій Дуже небагато системних викликів було додано під час розробки серій ядер 23 і

25 Велика частина з нових системних викликів призначена для поліпшення про-

дуктивності

Джерело: Лав, Роберт Розробка ядра 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>

*

*