Драйвери пристроів
Драйвер (driver) є спеціалізованим програмним модулем, керівник зовнішнім пристроєм. Драйвери забезпечують єдиний інтерфейс для доступу до різних пристроїв, тим самим усуваючи залежність призначених для користувача програм і ядра ОС від особливостей апаратури.
Драйвер не обов'язково повинен управляти яким-небудь фізичним пристроєм. Багато ОС надають також драйвери віртуальних пристроїв або псевдопристроїв — об'єктів, які поводяться аналогічно пристрою введення-виводу, але не відповідають жодному фізичному пристрою.
У вигляді псевдопристроїв реалізуються труби в системах сімейства Unix і поштові скриньки в VMS. Ще одним прикладом корисного псевдопристрою є пристрої /dev/null в Unix і аналогічне йому \DEV\NUL у MS DOS\Windows\OS/2. У сучасних системах сімейства Unix у вигляді псевдопристроїв, розміщених в псевдофайловій системі /рrос, реалізований доступ до більшості параметрів системи -- адресним просторам активних процесів, статистиці і параметрам налаштування ядра, даним окремих підсистем, наприклад таблиці маршрутизації мережевого протоколу IP. Прикладні програми, що використовують власні драйвери, не так вже рідкі - прикладами таких програм можуть бути GhostScript (вільно поширюваний інтерпретатор мови PostScript, здатний виводити програми на цій мові на різні пристрої, що як друкують, так і екранні) або LATEX який також здатний друкувати на найрізноманітніших пристроях. Проте ця глава присвячена переважно драйверам, використовуваним ядром ОС.
Більшість ОС загального призначення забороняють призначеним для користувача програмам безпосередній доступ до апаратури. Це робиться для підвищення надійності і забезпечення безпеки в розрахованих на багато користувачів системах. У таких системах драйвери є для прикладних програм єдиним способом доступу до зовнішнього світу.
Ще одна важлива функція драйвера - це взаємовиключає доступу до пристрою в середовищах з витісняючою багатозадачністю. Допускати одночасний неконтрольований доступ до пристрою декількох процесів, що паралельно виконуються, просто не можна, тому що для більшості зовнішніх пристроїв навіть прості операції введення-виводу не є атомарними.
Наприклад, в більшості апаратних реалізацій послідовного порту RS232 передача байта складається з чотирьох кроків: записи значення в регістр даних, записи команди "передавати" в регістр команди, чекання переривання по кінцю передачі і перевірки успішності передачі шляхом прочитування статусного регістра пристрою. Порушення послідовності кроків може наводити до неприємних наслідків — наприклад, перезапис регістра даних після подачі команди, але до завершення передачі, може привести до зупинки передачі або, що ще гірше, передачі спотворених даних і так далі Не можна також забувати про неприємності більш високого рівня — наприклад, змішуванні виведення різних процесів на друці або даних — на пристрої зовнішньої пам'яті. Тому виявляється необхідно пов'язати з кожним зовнішнім пристроєм якийсь розмежувач доступу в часі. У сучасних ОС ця функція покладається саме на драйвер. Зазвичай одна з ниток драйвера є процесом-монітором, що виконує запити, що асихронно поступають, на доступ до пристрою. У Unix, OS/2 і Windows NT/2000/XP цей процес називається стратегічною функцією.
При визначенні інтерфейсу драйвера розробники ОС повинні знайти правильний баланс між суперечливими вимогами: прагненням як можна сильніше спростити драйвер, аби полегшити його розробку і (побічно) зменшити вірогідність небезпечних помилок; бажанням надати гнучкий і інтелектуальний інтерфейс до всіляких пристроїв.
Драйвери зазвичай розробляються не постачальниками операційної системи, а сторонніми фірмами — розробниками і виготівниками периферійного устаткування. Тому інтерфейс драйвера є анітрохи не менш зовнішнім, ніж те, що зазвичай вважається зовнішнім інтерфейсом ОС — інтерфейс системних викликів. Відповідно, до нього пред'являються ті ж вимоги, що і до будь-якого іншого зовнішнього інтерфейсу: він повинен побут умопостижимым, вичерпно документованим і стабільним — мінятися непередбачувано від однієї версії ОС до іншої. Ідеальним варпан том була б повна сумісність драйверів хоч би від низу до верху, аби драйвер попередньої версії ОС міг використовуватися зі всіма подальшими версіями.
Втрата сумісності в даному випадку означає, що всі незалежні виготівники устаткування повинні будуть відновити свої драйвери. Організація такого оновлення виявляється складною, невдячною і часто просто нездійсненним завданням — наприклад, тому, що виготівник устаткування вже не існує як організація або отказачся від підтримки даного пристрою.
Відмова від сумісності драйверів на практиці означає "кинуте" периферійне устаткування і, як наслідок, "кинутих" користувачів, які виявляються вимушені або відмовлятися від установки нової системи, або замінювати устаткування. Обоє варіанту, природно, не покращують відношення користувачів до постачальника ОС, тому багато постачальників просто не можуть дозволити собі переробку підсистеми введення-виводу. Таким чином, інтерфейс драйвера часто виявляється найбільш консервативною частиною ОС.
Якщо говорити про сумісність, то з багатьох точок зору дуже привабливою представляється ідея універсального драйвера — модуля, який без зміні або з мінімальними змінами може використовуватися Для управління одним і тим же пристроєм в різних ОС.
На жаль — незважаючи навіть на те, що, як ми побачимо далі, у загальних рисах архітектура драйвера в більшості сучасних ОС дивно схожа — ідея ця, мабуть, не реалізовується. Навіть для близькоспоріднених ОС — наприклад, систем сімейства Unix — драйвери одного і того ж пристрої не завжди можуть бути легко перенесені з однієї ОС в іншу кажучи вже про можливість використання без модифікацій. Ще дивнішим є той факт, що дві лінії ОС - Windows 95/98/MЕ і Windows NT/2000/XP — що поставляються однією і тією ж компанією Microsoft і що реалізовують майже один і той же інтерфейс системних викликів — Win32 — мають зовсім різний інтерфейс драйвера.
Проблема тут в тому, що інтерфейс між драйвером і ядром ОС завжди двосторонній: не лише прикладні програми і ядро викликають функції драйвера, але і, навпаки, драйвер повинен викликати функції ядра. Структура інтерфейсів ядра, доступних драйверу, визначає багато аспектів архітектури ОС в цілому.