Наша совместная команда Banwar.org

Связаться с нами

  • (097) ?601-88-87
    (067) ?493-44-27
    (096) ?830-00-01

Статьи

Архітектура операційної системи UNIX

  1. 6.4.1 Переривання і особливі ситуації
  2. 6.4.2 Взаємодія з операційною системою через виклики системних функцій
  3. 6.4.3 Перемикання контексту
  4. 6.4.4 Збереження контексту на випадок аварійного завершення
  5. 6.4.5 Копіювання даних між адресним простором системи і адресним простором завдання

Як вже говорилося раніше, ядро ​​зберігає контекст процесу, поміщаючи в стек новий контекстний рівень. Зокрема, це має місце, коли система отримує переривання, коли процес викликає системну функцію або коли ядро ​​виконує перемикання контексту. Кожен з цих випадків докладно розглядається в цьому розділі.

6.4.1 Переривання і особливі ситуації

Система відповідає за обробку всіх переривань, чи надійшли вони від апаратури (наприклад, від таймера або від периферійних пристроїв), від програм (у зв'язку з виконанням інструкцій, що викликають виникнення "програмних переривань") або з'явилися результатом особливих ситуацій (таких як звернення до відсутньої сторінці). Якщо центральний процесор веде обробку на більш низькому рівні в порівнянні з рівнем надійшов переривання, то перед виконанням наступної інструкції його робота переривається, а рівень переривання процесора підвищується, щоб інші переривання з тим же (або нижчим) рівнем не могли мати місця до тих пір , поки ядро ​​не оброблені поточний переривання, завдяки чому забезпечується збереження цілісності структур даних ядра. В процесі обробки переривання ядро ​​виконує наступну послідовність дій:

  1. Зберігає поточний регістровий контекст виконується процесу і створює в стеку (поміщає в стек) новий контекстний рівень.
  2. Встановлює "джерело" переривання, ідентифікуючи тип переривання (наприклад, переривання по таймеру або від диска) і номер пристрою, що викликав переривання (наприклад, якщо переривання викликано дисковим запам'ятовуючим пристроєм). При виникненні переривання система отримує від машини число, яке використовує в якості зсуву в таблиці векторів переривання. Вміст векторів переривання в різних машинах по-різному, але, як правило, в них зберігається адреса програми обробки переривання, що відповідає джерелу переривання, і вказується шлях пошуку параметра для програми. Як приклад розглянемо таблицю векторів переривання, наведену на малюнку 6.9 . Якщо джерелом переривання з'явився термінал, ядро ​​отримує від апаратури номер переривання, рівний 2, і викликає програму обробки переривань від терміналу, іменовану ttyintr.

Номер переривання Програма обробки переривання 0 clockintr 1 diskintr 2 ttyintr 3 devintr 4 softintr 5 otherintr Малюнок 6.9. Приклад векторів переривання

  1. Виклик програми обробки переривання. Стек ядра для нового контекстного рівня, якщо міркувати логічно, повинен відрізнятися від стека ядра попереднього контекстного рівня. У деяких розробках стек ядра з поточною діяльністю використовується для зберігання елементів, відповідних програмам обробки переривань, в інших розробках ці елементи зберігаються в глобальному стеку переривань, завдяки чому забезпечується повернення з програми без перемикання контексту.
  2. Програма завершує свою роботу і повертає керування ядру. Ядро виконує набір машинних команд по збереженню реєстрового контексту і стека ядра попереднього контекстного рівня в тому вигляді, який вони мали в момент переривання, після чого відновлює виконання відновленого контекстного рівня. Програма обробки переривань може вплинути на поведінку процесу, оскільки вона може внести зміни в глобальні структури даних ядра і відновити виконання припинених процесів. Однак, зазвичай процес залишиться активним так, як якщо б переривання ніколи не відбувалося.

алгоритм inthand / * обробка переривань * / вхідна інформація: відсутня вихідна інформація: відсутній {зберегти (помістити в стек) поточний контекстний рівень; встановити джерело переривання; знайти вектор переривання; викликати програму обробки переривання; відновити (витягти з стека) попередній кон- текстний рівень; } Малюнок 6.10. Алгоритм обробки переривань

На рисунку 6.10 коротко викладено, яким чином ядро ​​обробляє переривання. За допомогою використання в окремих випадках послідовності машинних операцій або микрокоманд на деяких машинах досягається більший ефект в порівнянні з тим, коли всі операції виконуються програмним забезпеченням, проте є вузькі місця, пов'язані з числом зберігаються контекстних рівнів і швидкістю виконання машинних команд, що реалізують збереження контексту. З цієї причини певні операції, виконання яких вимагає реалізація системи UNIX, є машинно-залежними.

на малюнку 6.11 показаний приклад, в якому процес запитує виконання системної функції (див. наступний розділ) і отримує переривання від диска при її виконанні. Запустивши програму обробки переривання від диска, система отримує переривання по таймеру і викликає вже програму обробки переривання по таймеру. Кожен раз, коли система отримує переривання (або викликає системну функцію), вона створює в стеку новий контекстний рівень і зберігає регістровий контекст попереднього рівня.

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

Такого роду взаємодія з ядром було предметом розгляду в попередніх розділах, де йшлося про звичайний виклик функцій. Очевидно, що звичайна послідовність команд звернення до функції не в змозі переключити виконання процесу з режиму завдання на режим ядра. Компілятор з мови Сі використовує бібліотеку функцій, імена яких збігаються з іменами системних функцій, інакше посилання на системні функції в призначених для користувача програмах були б посиланнями на невизначені імена. В бібліотечних функціях зазвичай виповнюється команда, яка переводить виконання процесу в режим ядра і спонукає ядро ​​до запуску виконуваного коду системної функції. Надалі ця команда називається "внутрішнім перериванням операційної системи". Бібліотечні процедури виконуються в режимі завдання, а взаємодія з операційною системою через виклик системної функції можна визначити в декількох словах як особливий випадок програми обробки переривання. Бібліотечні функції передають ядру унікальний номер системної функції одним з машинно-залежних способів - або як параметр внутрішнього переривання операційної системи, або через окремий регістр, або через стек - а ядро ​​таким чином визначає тип викликається функції.

Малюнок 6
Малюнок 6.11.приклади переривань

Обробляючи внутрішнє переривання операційної системи, ядро ​​за номером системної функції веде в таблиці пошук адреси відповідної процедури ядра, тобто точки входу системної функції, і кількості переданих функції параметрів ( малюнок 6.12 ). Ядро обчислює адресу (призначений для користувача) першого параметра функції, додаючи (або віднімаючи, в залежності від напрямку збільшення стека) зміщення до покажчика вершини стека завдання (аналогічно для всіх параметрів функції). Нарешті, ядро ​​копіює параметри завдання в простір процесу і викликає відповідну процедуру, яка виконує системну функцію. Після виконання процедури ядро ​​з'ясовує, чи не було помилки. Якщо помилка була, ядро ​​робить відповідні установки в збереженому регістровому контексті завдання, при цьому в регістрі PS зазвичай встановлюється біт перенесення, а в нульовий регістр заноситься номер помилки. Якщо при виконанні системної функції не було помилок, ядро ​​очищає в регістрі PS біт перенесення і заносить повертаються функцією значення в регістри 0 і 1 в збереженому регістровому контексті завдання. Коли ядро ​​повертається після обробки внутрішнього переривання операційної системи в режим завдання, воно потрапляє в наступну бібліотечну інструкцію після переривання. Бібліотечна функція інтерпретує повернуті ядром значення і передає їх програмі користувача.

алгоритм syscall / * алгоритм запуску системної функції * / вхідна інформація: номер системної функції вихідна інформація: результат системної функції {знайти запис в таблиці системних функцій, відповідним щую вказаним номером функції; визначити кількість параметрів, переданих функції; скопіювати параметри з адресного простору завдання в простір процесу; зберегти поточний контекст для аварійного завершення (див. розділ 6.44); запустити в ядрі виконуваний код системної функції; якщо (під час виконання функції сталася помилка) {встановити номер помилки в нульовому регістрі сохра- ненного реєстрового контексту завдання; включити біт перенесення в регістрі PS збереженого реєстрового контексту завдання; } В іншому випадку занести повертаються функцією значення в регістри 0 і 1 в збереженому регістровому контексті завдання; } Малюнок 6.12. Алгоритм звернення до системних функцій

Як приклад розглянемо програму, яка створює файл з дозволом читання і запису в нього для всіх користувачів (режим доступу 0666) і яка приведена у верхній частині малюнка 6.13 . Далі на малюнку зображений відредагований фрагмент згенерованого коду програми після компіляції і дісассемблірованія (створення по об'єктному коду еквівалентної програми на мові асемблера) в системі Motorola 68000. На малюнку 6.14 зображена конфігурація стека для системної функції створення. Компілятор генерує програму приміщення в стек завдання двох параметрів, один з яких містить установку прав доступу (0666), а інший - змінну "ім'я файлу" (**) . Потім з адреси 64 процес викликає бібліотечну функцію creat (адреса 7a), аналогічну відповідної системної функції. Адреса точки повернення з функції 6a, ця адреса міститься процесом в стек. Бібліотечна функція creat засилає в регістр 0 константу 8 і виконує команду переривання (trap), яка перемикає процес з режиму завдання в режим ядра і змушує його звернутися до системної функції. Помітивши, що процес викликає системну функцію, ядро ​​вибирає з регістра 0 номер функції (8) і визначає таким чином, що викликана функція creat. Переглядаючи внутрішню таблицю, ядро ​​виявляє, що системної функції creat необхідні два параметри; відновлюючи регістровий контекст попереднього рівня, ядро ​​копіює параметри з користувальницького простору в простір процесу. Процедури ядра, яким знадобляться ці параметри, можуть знайти їх в певних місцях адресного простору процесу. По завершенні виконання коду функції creat управління повертається програмі обробки звернень до операційної системи, яка перевіряє, чи встановлено поле помилки в просторі процесу (тобто мала місце під час виконання функції помилка); якщо так, програма встановлює в регістрі PS біт перенесення, заносить в регістр 0 код помилки і повертає управління ядру. Якщо помилок не було, в регістри 0 і 1 ядро ​​заносить код завершення. Повертаючи управління з програми обробки звернень до операційної системи в режим завдання, бібліотечна функція перевіряє стан біта перенесення в регістрі PS (за адресою 7): якщо біт встановлений, управління передається за адресою 13c, з нульового регістру вибирається код помилки і поміщається в глобальну змінну errno за адресою 20, в регістр 0 заноситься -1, і управління повертається на наступну після адреси 64 (де здійснюється виклик функції) команду. Код завершення функції має значення -1, що вказує на помилку в виконанні системної функції. Якщо ж біт перенесення в регістрі PS при переході з режиму ядра в режим завдання має нульове значення, процес з адреси 7 переходить за адресою 86 і повертає управління викликала програмі (адреса 64); регістр 0 містить повертається функцією значення.

char name [] = "file"; main () {int fd; fd = creat (name, 0666); } Фрагменти ассемблерной програми, згенерованої в системі Motorola 68000 Звідки Команда - - # текст головної програми - 58: mov & Ox1b6, (% sp) # помістити код 0666 в стек 5e: mov & Ox204, - (% sp) # помістити покажчик вершини # стека і змінну "ім'я файлу" # в стек 64: jsr Ox7a # виклик бібліотечної функції # створення файлу - - # текст бібліотечної функції створення файлу 7a: movq & Ox8,% d0 # занести значення 8 в регістр 0 7c: trap & Ox0 # внутрішнє переривання операци - # ційної системи 7e: bcc & Ox6 <86> # якщо біт перенесення очищений, # перейти за адресою 86 80: jmp Ox13c # перейти за адресою 13c 86: rts # повернення з підпрограми - - # екст обробки помилок функції 13c: mov% d0, & Ox20e # помістити вміст регістра # 0 в осередок 20e (змінна # errno) 142: movq & -Ox1,% d0 # занести в регістр 0 константу # -1 144: mova% d0,% a0 146: rts # повернення з підпрограми Малюнок 6.13. Системна функція creat і згенерувала програма її виконання в системі Motorola 68000 char name [] = file;  main () {int fd;  fd = creat (name, 0666);  } Фрагменти ассемблерной програми, згенерованої в системі Motorola 68000 Звідки Команда - - # текст головної програми - 58: mov & Ox1b6, (% sp) # помістити код 0666 в стек 5e: mov & Ox204, - (% sp) # помістити покажчик вершини # стека і змінну ім'я файлу # в стек 64: jsr Ox7a # виклик бібліотечної функції # створення файлу - - # текст бібліотечної функції створення файлу 7a: movq & Ox8,% d0 # занести значення 8 в регістр 0 7c: trap & Ox0 # внутрішнє переривання операци - # ційної системи 7e: bcc & Ox6 <86> # якщо біт перенесення очищений, # перейти за адресою 86 80: jmp Ox13c # перейти за адресою 13c 86: rts # повернення з підпрограми - - #  екст обробки помилок функції 13c: mov% d0, & Ox20e # помістити вміст регістра # 0 в осередок 20e (змінна # errno) 142: movq & -Ox1,% d0 # занести в регістр 0 константу # -1 144: mova% d0,% a0 146: rts # повернення з підпрограми Малюнок 6
Малюнок 6.14. Конфігурація стека для системної функції creat

Кілька бібліотечних функцій можуть відображатися на одну точку входу в список системних функцій. Кожна точка входу визначає точні синтаксис і семантику звернення до системної функції, однак більш зручний інтерфейс забезпечується за допомогою бібліотек. Існує, наприклад, кілька конструкцій системної функції exec, таких як execl і execle, що виконують одні і ті ж дії з невеликими відмінностями. Бібліотечні функції, що відповідають цим конструкціям, при обробці параметрів реалізують заявлені властивості, але в кінцевому підсумку, відображаються на одну й ту ж функцію ядра.

(**) Черговість, в якій компілятор обчислює і поміщає в стек параметри функції, залежить від реалізації системи.

6.4.3 Перемикання контексту

Якщо звернутися до діаграми станів процесу ( малюнок 6.1 ), Можна побачити, що ядро ​​дозволяє проводити перемикання контексту в чотирьох випадках: коли процес призупиняє своє виконання, коли він завершується, коли він повертається після виклику системної функції в режим завдання, але не є найбільш підходящим для запуску, або коли він повертається в режим завдання після завершення ядром обробки переривання, але так само не є найбільш підходящим для запуску. Як вже було показано в розділі 2 , Ядро підтримує цілісність і узгодженість своїх внутрішніх структур даних, забороняючи довільно перемикати контекст. Перш ніж перемикати контекст, ядро ​​має упевнитися в узгодженості своїх структур даних: тобто в тому, що зроблені всі необхідні коректування, все черзі збудовані належним чином, встановлені відповідні блокування, що дозволяють уникнути втручання з боку інших процесів, що немає зайвих блокувань і т. д. Наприклад, якщо ядро ​​виділяє буфер, зчитує блок з файлу і призупиняє виконання до завершення передачі даних з диска, воно залишає буфер заблокованим, щоб інші процеси не змогли звернутися до буферу. Але якщо процес виконує системну функцію link, ядро ​​знімає блокування з першого індексу перед тим, як зняти її з другого індексу, і тим самим запобігає виникненню тупикових ситуацій (взаємного блокування).

Ядро виконує перемикання контексту по завершенні системної функції exit, оскільки в цьому випадку більше нічого не залишається робити. Крім того, перемикання контексту допускається, коли процес призупиняє свою роботу, оскільки до моменту відновлення може пройти чимало часу, протягом якого могли б виконуватися інші процеси. Перемикання контексту допускається і тоді, коли процес не має переваг перед іншими процесами при виконанні, з тим, щоб забезпечити більш справедливий планування процесів: якщо після виходу процесу з системної функції або з переривання виявляється, що існує ще один процес, який має більш високий пріоритет і чекає виконання, то було б несправедливо залишати його в очікуванні.

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

1. Прийняти рішення щодо необхідності переклю- чення контексту і його допустимості в даний момент. 2. Зберегти контекст "колишнього" процесу. 3. Вибрати процес, найбільш підходящий для виконання, використовуючи алгоритм диспетчеризації процесів, приве- денний в главі 8. 4. Відновити його контекст. Малюнок 6.15. Послідовність кроків, виконуваних при перемиканні контексту

Текст програми, що реалізує перемикання контексту в системі UNIX, з усіх програм операційної системи найважчий для розуміння, бо при розгляді звернень до функцій створюється враження, що вони в одних випадках не повертають управління, а в інших - виникають незрозуміло звідки. Причиною цього є те, що ядро ​​в багатьох системних реалізаціях зберігає контекст процесу в одному місці програми, але продовжує роботу, виконуючи перемикання контексту і алгоритми диспетчеризації в контексті "колишнього" процесу. Коли пізніше ядро ​​відновлює контекст процесу, воно відновлює його виконання відповідно до раніше збереженим контекстом. Щоб розрізняти між собою ті випадки, коли ядро ​​відновлює контекст нового процесу, і коли воно продовжує виконувати раніше збережений контекст, можна варіювати значення, які повертаються критичними функціями, або встановлювати штучним чином поточне значення лічильника команд.

на малюнку 6.16 приведена схема перемикання контексту. Функція save_context зберігає інформацію про контекст виконуваного процесу і повертає значення 1. Крім усього іншого, ядро ​​зберігає поточне значення лічильника команд (у функції save_context) і значення 0 в нульовому регістрі при виході з функції. Ядро продовжує виконувати контекст "колишнього" процесу (A), вибираючи для виконання наступного процес (B) і викликаючи функцію resume_context для відновлення його контексту. Після відновлення контексту система виконує процес B; колишній процес (A) більше не виконується, але він залишив після себе збережений контекст. Пізніше, коли буде виконуватися перемикання контексту, ядро ​​знову обере процес A (якщо тільки, зрозуміло, він не був завершений). В результаті відновлення контексту A ядро ​​присвоїть лічильнику команд то значення, яке було збережено процесом A раніше в функції save_context, і поверне в регістрі 0 значення 0. Ядро відновлює виконання процесу A з функції save_context, нехай навіть при виконанні програми перемикання контексту воно не дісталося ще до функції resume_context. В кінцевому підсумку, процес A повертається з функції save_context зі значенням 0 (в нульовому регістрі) і відновлює виконання після рядка коментаря "відновлення виконання процесу починається звідси".

if (save_context ()) / * збереження контексту виконується процесу * / {/ * вибір наступного процесу для виконання * / - - - resume_context (new_process); / * Сюди програма не влучає! * /} / * Відновлення виконання процесу починається звідси * / Малюнок 6.16. Псевдопрограму перемикання контексту

6.4.4 Збереження контексту на випадок аварійного завершення

Існують ситуації, коли ядро ​​змушене аварійно переривати поточний порядок виконання і негайно переходити до виконання раніше збереженого контексту. У наступних розділах, де йтиметься про призупинення виконання і про сигнали, будуть описані обставини, при яких процесу доводиться раптово змінювати свій контекст; в даному ж розділі розглядається механізм виконання попереднього контексту. Алгоритм збереження контексту називається setjmp, а алгоритм відновлення контексту - longjmp (***) . Механізм роботи алгоритму setjmp схожий на механізм функції save_context, розглянутий в попередньому розділі, якщо не брати до уваги того, що функція save_context поміщає новий контекстний рівень в стек, в той час як setjmp зберігає контекст в просторі процесу і після виходу з нього виконання триває в колишньому контекстному рівні. Коли ядру знадобиться відновити контекст, який було збережено в результаті роботи алгоритму setjmp, воно виконає алгоритм longjmp, який відновлює контекст з простору процесу і має, як і setjmp, код завершення, рівний 1.

6.4.5 Копіювання даних між адресним простором системи і адресним простором завдання

До цих пір мова йшла про те, що процес виконується в режимі ядра або в режимі завдання без будь-яких перекриттів (перетинів) між режимами. Однак, при виконанні більшості системних функцій, розглянутих в останньому розділі, між простором ядра і простором завдання здійснюється пересилання даних, наприклад, коли йде копіювання параметрів викликається функції з простору завдання в простір ядра або коли проводиться передача даних з буферів введення-виведення в процесі виконання функції read. На багатьох машинах ядро ​​системи може безпосередньо посилатися на адреси, що належать адресного простору завдання. Ядро має переконатися в тому, що адреса, по якому проводиться запис або зчитування, доступний, як ніби-то робота ведеться в режимі завдання; в іншому випадку відбулося б порушення стандартних методів захисту і ядро, нехай ненавмисно, стало б звертатися до адрес, які знаходяться за межами адресного простору завдання (і, можливо, належать структурам даних ядра). Тому передача даних між простором ядра і простором завдання є "дорогим підприємством", що вимагає для своєї реалізації декількох команд.

fubyte: # пересилання байта з # простору завдання prober $ 3, $ 1, * 4 (ap) # байт доступний? beql eret # немає movzbl * 4 (ap), r0 ret eret: mnegl $ 1, r0 # повернення помилки (-1) ret Малюнок 6.17. Пересилання даних з простору завдання в простір ядра в системі VAX

На рисунку 6.17 показаний приклад реалізованої в системі VAX програми пересилання символу з адресного простору завдання в адресний простір ядра. Команда prober перевіряє, чи може байт за адресою, рівному (реєстр покажчика аргументу + 4), бути лічений в режимі завдання (режимі 3), і якщо немає, ядро ​​передає керування за адресою eret, зберігає в нульовому регістрі -1 і виходить з програми ; при цьому пересилання символу не відбувається. В іншому випадку ядро ​​пересилає один байт, що знаходиться за вказаною адресою, в регістр 0 і повертає його в зухвалу програму. Пересилання 1 символу зажадала п'яти команд (включаючи виклик функції з ім'ям fubyte).

(***) Ці алгоритми не слід плутати з мають ті ж назви бібліотечними функціями, які можуть викликатися безпосередньо з призначених для користувача програм (див. [SVID 85]). Однак дія цих функцій схоже.

попередня глава

|| Зміст || Наступна глава

Спонсори:

Хостинг:



Fubyte: # пересилання байта з # простору завдання prober $ 3, $ 1, * 4 (ap) # байт доступний?

Новости

Banwar.org
Наша совместная команда Banwar.org. Сайт казино "Пари Матч" теперь доступен для всех желающих, жаждущих волнения и азартных приключений.