Operating Systems: Three Easy Pieces. Part 2: Абстракція: Процес (переклад)

Введення в операційні системи

Привіт, Хабре! Хочу представити вашій увазі серію статей-перекладів однієї цікавої на мою думку літератури — OSTEP. У цьому матеріалі розглядається досить глибоко робота unix-подібних операційних систем, а саме робота з процесами, різними планувальниками, пам'яттю та іншими подібними компонентами, які складають сучасну ОС. Оригінал всіх матеріалів ви можете подивитись ось тут. Прошу врахувати, що переклад виконаний непрофесійно (досить вільно), але сподіваюся, загальний зміст я зберіг.

Лабораторні роботи з даного предмета можна знайти ось тут:

Інші частини:

А ще можете заглядати до мене на канал у телеграма =)

Розглянемо найбільш фундаментальну абстракцію, яку ОС надає користувачам процес. Визначення процесу досить просто — це працююча програма. Програма сама по собі є неживою річчю, що розташовується на диску — це набір інструкцій і можливо якихось статичних даних, які чекають на момент запуску. Саме ОС бере ці байти і запускає їх, перетворюю програму на щось корисне.
Найчастіше користувачі хочуть запускати більше однієї програми одночасно, наприклад, ви можете запустити на вашому ноутбуці браузер, гру, медіаплеєр, текстовий редактор тощо. Фактично типова система може запускати десятки та сотні процесів одночасно. Цей факт робить систему більш простою у використанні, вам ніколи не доводиться турбуватися про те, чи вільний CPU, ви просто запускаєте програми.

Звідси випливає проблема: як забезпечити ілюзію множини CPU? Як ОС створити ілюзію практично нескінченної кількості CPU, навіть якщо у вас лише один фізичний CPU?

ОС створює цю ілюзію у вигляді віртуалізації CPU. Запускаючи один процес, потім зупиняючи його, запускаючи інший процес і так далі, ОС може підтримувати ілюзію того, що існує безліч віртуальних CPU, хоча це фактично буде один або кілька фізичних процесорів. Така техніка називається поділ ресурсів CPU за часом. Ця техніка дозволяє користувачам запускати стільки одночасних процесів, скільки вони забажають. Ціною такого рішення є продуктивність - оскільки якщо CPU ділять кілька процесів, кожен процес оброблятиметься повільніше.
Для втілення віртуалізації CPU, а особливо для того, щоб робити це добре, ОС потребує і низькорівневої і високорівневої підтримки. Низькорівнева підтримка називається механізмами це низькорівневі методи або протоколи, які реалізують потрібну частину функціоналу. Приклад такого функціоналу - контекстне перемикання, яке дає ОС можливість зупиняти одну програму та запускати на процесорі іншу програму. Такий поділ за часом реалізований у всіх сучасних ОС.
На вершині цих механізмів розташовується деяка логіка, закладена в ОС, у вигляді “політик”. Політика - Це деякий алгоритм прийняття рішення операційною системою. Такі політики, наприклад, вирішують, яку програму треба запускати (зі списку команд) насамперед. Так, наприклад, це завдання вирішить політика, що називається планувальник (scheduling policy) і при виборі рішення керуватиметься такими даними як: історія запуску (яка програма була запущена найдовше за останню хвилину), яке навантаження здійснює даний процес (які типи програм були запущені), метрики продуктивності (чи оптимізована система для інтерактивної взаємодії або для пропускної здатності ) і так далі.

Абстракція: процес

Абстракція працюючої програми, яку виконує операційна система це те, що ми називаємо процес. Як вже було сказано раніше процес - це просто працююча програма, у будь-який моментальний проміжок часу. Програма за допомогою якої ми можемо отримати сумарну інформацію з різних ресурсів системи, і до яких звертається або які ця програма торкається в процесі виконання.
Для розуміння складових процесу потрібно розуміти стан системи: що програма може зчитувати або змінювати під час своєї роботи. У будь-який момент часу потрібно розуміти, які елементи системи є важливими для виконання програми.
Одним з очевидних елементів стану системи, які включає процес — це пам'ять. Інструкції розміщуються у пам'яті. Дані, які програма читає або пише також, розміщуються у пам'яті. Таким чином, пам'ять, яку процес може адресувати (так званий адресний простір), є частиною процесу.
Також частиною стану системи є регістри. Багато інструкцій спрямоване на те, щоб змінити значення регістрів або прочитати їх значення і таким чином регістри теж стають важливою частиною роботи процесу.
Слід зазначити, що стан машини формується з деяких спеціальних регістрів. Наприклад, IP - instruction pointer — вказівник на інструкцію, яку програма виконує зараз. Ще є вказівник стека і пов'язаний з ним покажчик рамки, які використовуються для керування: параметрами функцій, локальними змінними та адресами повернення.
Нарешті, програми часто звертаються до ПЗУ (постійного пристрою). Така інформація про "I/O" (введення-виведення) повинна включати список файлів, відкритих процесом в даний момент.

API обробки

Для того, щоб поліпшити розуміння роботи процесу, вивчимо приклади системних викликів, які повинні бути включені в будь-який інтерфейс операційної системи. Ці API у тому чи іншому вигляді доступні будь-який ОС.

Створювати (Створення): В ОС повинен входити якийсь метод, що дозволяє створювати нові процеси. Коли ви вводите команду в термінал або запускаєте програму через подвійний клік по іконці, надсилається звернення до ОС для створення нового процесу та наступного запуску вказаної програми.
Видалення: Якщо є інтерфейс для створення процесу, ОС також має надавати можливість для примусового видалення процесу. Більшість програм природно буде запущено і завершено власними силами в міру їх виконання. В іншому випадку користувач хотів би мати можливість вбити їх і таким чином інтерфейс для зупинки процесу буде не зайвим.
Почекай (очікування): Іноді корисно дочекатися завершення процесу, тому забезпечуються деякі інтерфейси, що надають можливістю очікування.
Misc Control (різне управління): Крім вбивства та очікування процесу ще існують інші різноманітні контролюючі методи. Наприклад, більшість ОС надають можливість заморожування процесу (зупинка його виконання на деякий період) і подальше відновлення (продовження виконання).
Статус (стан): Існують різні інтерфейси для отримання деякої інформації про його статус процесу, такі як тривалість його роботи або в якому стані він зараз знаходиться.

Operating Systems: Three Easy Pieces. Part 2: Абстракція: Процес (переклад)

Створення процесу: деталі

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

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

Після того, як код і статичні дані завантажені в пам'ять ОС, потрібно виконати ще кілька речей перед тим як запустити процес. Деяка кількість пам'яті має бути виділена під стек. Програми використовують стек для локальних змінних, параметрів функцій та адрес повернення. ОС виділяє цю пам'ять та віддає її процесу. Стек може виділятися з деякими аргументами, саме вона заповнює параметри функції main(), наприклад масивом argc і argv.

Операційна система може також виділяти кілька пам'яті під купу (heap) програми. Купа використовується програмами для динамічно виділених даних, що явно запитуються.. Програми запитують цей простір, викликаючи функцію malloc () і явно очищає, викликаючи функцію безкоштовно (). Купа потрібна таких структур даних як: пов'язані листи, таблиці хешів, дерева та інші. Спочатку під купу виділяється невелика кількість пам'яті, але згодом у процесі програми купа може запросити більшу кількість пам'яті, через бібліотечний API виклик malloc(). Операційна система залучена до процесу виділення більшої кількості пам'яті для того, щоб допомогти у задоволенні цих викликів.

Операційна система також виконуватиме завдання ініціалізації, зокрема ті, що належать до введення-виводу. Наприклад, у системах UNIX кожен процес за умовчанням має 3 відкритих файлових дескриптори, для стандартного потоку введення, виведення та помилок. Ці дескриптори дозволяють програмам зчитувати введення терміналу, а також виводити інформацію на екран.

Таким чином, завантажуючи код та статичні дані в пам'ять, створюючи та ініціалізуючи стек, а також виконуючи іншу роботу, що відноситься до виконання завдань введення-виведення, ОС готує майданчик для виконання процесу. Зрештою, залишається останнє завдання: запустити виконання програму через її точку введення, звану функцією main(). Переходячи до виконання функції main(), ОС передає управління CPU новоствореному процесу, таким чином, програма починає виконуватися.

Стан процесу

Тепер, коли ми маємо деяке розуміння, що таке процес і як він створюється, перерахуємо стан процесу, в якому він може знаходитися. У найпростішій формі процес може бути в одному з цих станів:
Робота. У занедбаному стані процес виконується на процесорі. Це означає, що відбувається виконання вказівок.
Готовий. У стані готовності процес готовий запуститись, але з якихось причин ОС не виконує його в заданий момент часу.
блокований. У заблокованому стані процес виконує якісь операції, які дають йому бути готовим до виконання до того часу, доки станеться якесь подія. Один із звичайних прикладів - коли процес ініціалізує операцію IO, він стає заблокованим і таким чином якийсь інший процес може використовувати процесор.

Operating Systems: Three Easy Pieces. Part 2: Абстракція: Процес (переклад)

Уявити ці стани можна як графа. Як ми бачимо на картинці, стан процесу може змінюватися між RUNNING і READY на розсуд ОС. Коли стан процесу змінюється з READY, на RUNNING це означає, що процес було заплановано. У зворотний бік — знято з планування. У момент, коли процес стає BLOCKED, наприклад, ініціалізую операцію IO, ОС триматиме його в цьому стані до настання деякої події, наприклад завершення IO. в цей момент перехід у стан READY і можливий моментально в стан RUNNING, якщо так вирішить ОС.
Погляньмо на приклад того, як два процеси проходять через ці стани. Для початку уявімо, що обидва процеси запущені, і кожен використовує лише CPU. У цьому випадку їх стану будуть виглядати наступним чином.

Operating Systems: Three Easy Pieces. Part 2: Абстракція: Процес (переклад)

У наступному прикладі перший процес через деякий час роботи вимагає IO і переходить у стан BLOCKED, надаючи іншому процесу можливість запуску (РИС 1.4). ОС бачить, що процес 0 не використовує CPU і запускає процес 1. Під час виконання процесу 1 - IO завершується та статус процесу 0 змінюється на READY. Нарешті процес 1 завершився, а після його закінчення процес 0 запускається, виконується і закінчує свою роботу.

Operating Systems: Three Easy Pieces. Part 2: Абстракція: Процес (переклад)

Структура даних

ОС сама є програмою, а також будь-яка інша програма має деякі ключові структури даних, які відстежують різноманітні релевантні шматки інформації. Для відстеження стану кожного процесу в ОС підтримуватиметься деякий process list для всіх процесів у стані READY та деяку додаткову інформацію для відстеження процесів, що виконуються в даний момент. Також, ОС має відслідковувати та заблоковані процеси. Після завершення IO, ОС має розбудити необхідний процес і перевести їх у стан готовності до запуску.

Так, наприклад, ОС має зберегти стан регістрів процесора. У момент зупинення процесу стан регістрів зберігається в адресному просторі процесу, а в момент продовження його роботи відновити значення регістрів і таким чином продовжити виконання цього процесу.

Крім станів ready, blocked, running існують ще деякі інші стани. Іноді під час створення процес може мати стан INIT. Нарешті, процес може бути поміщений стан FINAL, коли він вже завершився, але інформація про нього ще не вичищена. У UNIX системах такий стан називається процес-зомбі. Цей стан корисний для випадків, коли батьківський процес хоче дізнатися код повернення нащадка, наприклад, зазвичай 0 сигналізує про успішне завершення, а 1 про помилкове, проте програмісти можуть робити додаткові коди виведення, сигналізуючи про різні проблеми. При завершенні процес-батько робить останній системний виклик, наприклад wait(), щоб дочекатися завершення роботи процесу-нащадка і просигналізувати ОС у тому, що можна очистити будь-які дані, пов'язані з завершеним процесом.

Operating Systems: Three Easy Pieces. Part 2: Абстракція: Процес (переклад)

Ключові моменти лекції:

Процес - Головна абстракція працюючої програми в ОС. У будь-який час процес може бути описаний за його станом: вміст пам'яті в його адресному просторі, вміст регістрів процесора, включаючи instruction pointer і stack pointer також інформацією про IO, наприклад відкритими файлами, які зчитуються або записуються.
API обробки складається з викликів, які програми можуть робити щодо процесів. Зазвичай це виклики створення, видалення чи інші.
● Процес знаходиться в одному з багатьох станів, включаючи running, ready, blocked. Різні події, такі як планування, виключення з планування або очікування, можуть переводити стан процесу з одного в інше.
Список процесів містить інформацію про всі процеси в системі. Кожна запис у ній називається process control block, яка насправді є структурою, що містить всю необхідну інформацію про конкретний процес. 

Джерело: habr.com

Додати коментар або відгук