Теорія операційної системи

:: Меню ::

Головна
Представлення даних в обчислювальних системах
Машинні мови
Завантаження програм
Управління оперативною пам'яттю
Сегментна і сторінкова віртуальна пам'ять
Комп'ютер і зовнішні події
Паралелізм з точки зору програміста
Реалізація багатозадачності на однопроцесорних комп'ютерах  
Зовнішні пристрої
Драйвери зовнішніх пристроїв
Файлові системи
Безпека
Огляд архітектури сучасних ОС

:: Друзі ::

Карта сайту
 

:: Статистика ::

 

 

 

 

 

Динамічні бібліотеки

У Windows і Os/2 використовується саме такий спосіб завантаження. Виконуваний модуль в цих системах містить заслання на інші модулі, звані DLL (Dynamically Loadable Library, динамічно завантажувана бібліотека). Фактично, кожен модуль в цих системах зобов'язаний містити хоч би одне заслання на DLL, бо інтерфейс до системних викликів в цих ОС також реалізований у вигляді DLL.
DLL є бібліотеками в тому сенсі, що зазвичай вони збираються з декількох об'єктних модулів. Але, на відміну від архівних бібліотек, з DLL не можна витягувати окремий модуль, при приєднанні бібліотеки до програми вона приєднується і завантажується цілком.
Головне достоїнство DLL полягає в тому, що модуль (як основний, так і бібліотечний), за власним бажанням, може вибирати різні бібліотеки, підвантажуючи їх вже після свого власного завантаження. При цьому немає навіть строгого обмеження на сумісність цих бібліотек по викликах (дві бібліотеки сумісні по викликах, якщо вони мають однакові точки входу з однаковою семантикою): завантажувач надає можливість проглянути список глобальних символів, визначених в бібліотеці і отримати покажчик на кожен символ, звернувшись до нього по імені' (втім, кількість і типи параметрів або тип змінної, а тим більше їх семантику, завантажувач не повідомляє — цю інформацію треба отримувати з інших джерел, наприклад із списку зареєстрованих в системі об'єктів СОМ).
Особливо зручна можливість викликати будь-яку функцію по імені при зверненні до зовнішніх модулів з мов, що інтерпретуються. У прикладі 3.9 для підключення зовнішніх бібліотек (в даному випадку це стандартна бібліотека Rexxutil і бібліотека доступу до мережевих сервісів rxsock) застосовуються дві процедури: спочатку Rxfuncadd з трьома параметрами: ім'я символу REXX, який використовуватиметься для звернення до функції, що викликається, ім'я DLL і ім'я символу в цій DLL, а потім спеціальна функція, що надається модулем (sysloadfunc і sockloadfunc відповідно), яка реєструє в інтерпретаторі REXX останні функції модуля.

Приклад 3.9. Приклад використання динамічної бібліотеки (тут — REXX | I Socket) в мові, що інтерпретується

/**************************************************
ПРОСТІЙ HTTP клієнт на REXX
Dmitry Maximovich 2:5030/544.60 aka maxim@pabl.ru
**************************************************/
PARSE VALUE ARC (1) WITH Al A2
IF Al = " THEN DO
SAY 'USAGE: wwwget hostname[/path] [port]' EXIT
END
ELSE
DO
PARSE VALUE Al WITH B1'/'b2
sserver = Bl
IF B2 = '' THEM
DO
srequest = 'GET / HTTP 1.0'|i"odoaodoa"x
Say''requesting /' END ELSE DO
srequest = 'GET /'|ib2i|' HTTP 1.0'|i"odoaodoa"x
SAY 'Requesting /'||b2
END
END
IF A2 <> " THEN
DO
nportnumber = A2
END
-ELSE
DO
nportnumber =80
END
/* Завантажити REXX Socket Library якщо ще не загружена*/
IF Rxfuncquery("Sockloadfuncs") THEN
DO
re = Rxfuncaddf"sockloadfuncs","rxsock","sockloadfuncs")
re = Sockloadfuncs ()
END
IF Rxfuncquery("Sysloadfuncs") THEN
DO
re = Rxfuncadd( "Sysloadfuncs","rexxutil","sysloadfuncs") re = Sysloadfuncs()
END
rc=sockgethostbyname(sserver,"host.")
IF rс <> 1 THEN
DO
SAY 'CANNOT RESOLVE HOSTNAME TO ADDRESS: 'sserver EXIT -1 END
SAY 'Trying server : 'host .name1, address: 'host .addr', port: 'nportnumber
socket = Socksocket('Af_inet','sock_stream',0) IF socket < 0 THEN DO
SAY 'UNABLE TO CREATE A SOCKET' EXIT -1
END
address.familу = 'Af_inet' address.port = nportnumber address.addr = host.addr
rc = Sockconnect(socket,'address.')
IF re < 0 THEN
DO
SAY 'UNABLE TO CONNECT TO SERVER:'address.addr
SIGNAL DO
END
re = Socksend(socket, srequest)
SAY 'Request'***************************************************'
Resp = ''
DO FOREVER
re = Sockrecv(socket,"sreceive",256)
IF re <= 0 THEN LEAVE
Resp = Resp || sreceive END
SAY
/* CR -> CRLF */
nstart = 1
nstop = pos(X2c("OA"), Resp)
do while nstop > 0
SAY SUBSTR(Resp,nstart,nstop-nstart)
nstart = nstop + 1
nstop = pos(X2c("OA"), Resp, nstart)
end
DO:
rc = Sockshutdown(socket,2)
rc = Sockclose(socket)

При збірці DLL з декількох об'єктних модулів програміст повинен надати DEF-файл (приклад 3.10). У цьому файлі міститься перерахування символів, що експортуються бібліотекою (на відміну від звичайних, "архівних" бібліотек, набір цих символів не обов'язково дорівнює об'єднанню наборів експортних символів всіх включених в бібліотеку об'єктів), а також деякі інші параметри. Наприклад, можна вказати, що DLL має функції ініціалізації і термінациі. Ці функції можуть запускатися як при першому завантаженні бібліотеки (INITGLOBAL), так і при підключенні бібліотеки черговою програмою (INITINSTANCE). Можна також управляти розділенням сегменту даних DLL — застосовувати спільний сегмент даних для всіх програм, що використовують бібліотеку, або створювати свою копію для кожної програми.

Приклад 3.10. DEF-файл з прикладів коди Visualage C++ V3.0

LIBRARY REXXUTIL INITINSTANCE LONGNAMES
PROTMODE
DESCRIPTION 'REXXUTIL Utilities - (c) Copyright IBM Corporation 1991'
DATA MULTIPLE NONSHARED STACKSIZE 32768
EXPORTS
SYSCLS = Syscls @1 SYSCURPOS = Syscurpos @2 SYSCURSTATE = Syscurstate @3 SYSDRIVEINFO = Sysdrivelnfo @4
SYSDRIVEMAP = Sysdrivemap @5
Sysdropf0ncs = Sysdropfuncs @6
SYSFILEDELETE = Sysfiledelete @7
SYSFILESEARCH = Sysfilesearch @8
SYSFILETREE - Sysfiletree @9
SYSGETMESSAGE = Sysgetmessage 010
SYSINI = Syslni 011
SYSLOADFUNCS = Sysloadfuncs @12
SYSMKDIR = Sysmkdir @13
Sysos2ver = Sysos2ver 014
SYSRMDIR = Sysrmdir @15
SYSSEARCHPATH = Syssearchpath @16
SYSSLEEP = Syssleep @17
SYSTEMPFILENAME = Systempfilename @18
SYSTEXTSCREENREAD = Systextscreenread @19
SYSTEXTSCREENSIZE = Systextscreensize La20
SYSGETEA = Sysgetea @21
SYSPUTEA = Sysputea @22
SYSWAITNAMEDPIPE = Syswaitnamedpipe @23

DLL є зручним засобом розділення коди і створення окремо завантажуваних програмних модулів, але їх використання зв'язане з певною проблемою, яка детальніше пояснюватиметься в разд. Бібліотеки, що розділяються. Забігаючи вперед, скажімо, що концепція DLL, що розділяються, найбільш природна в системах, де веб-сервер завдання використовують єдиний адресний простір — але при цьому помилка в будь-якій з програм може привести до псування даних або коди іншого завдання. Стандартний же спосіб боротьби з цією проблемою — виділення кожному процесу свого адресного простору — значно ускладнює розділення коди.
Інша проблема, обумовлена широким використанням коди, що розділяється, полягає в стеженні за версією цієї коди. Дійсно, уявимо собі життєву ситуацію: у системі одночасно завантажено тридцять програм, що використовують бібліотеку LIBC.DLL. При цьому десять з них розроблялися і тестувалися з версією 1.0 цієї бібліотеки, п'ять — з версією 1.5 і п'ятнадцять — з версією 1.5а. Зрозуміло, що розраховувати на стійку роботу всіх тридцяти програм можна лише за умови, що всі три версії бібліотеки повністю сумісні від низу до верху не лише по набору викликів і їх параметрів, але і по точній семантиці кожного з цих викликів. Останню вимогу інколи формулюють як bug-for-bug compatibility (коректно перевести цю словосполуку можна так: повна сумісність не лише по специфікаціях, але і по відхиленнях від них).
Здавалося б, виправлення помилок повинне лише покращувати роботу програм, що використовують виправлений код. На практиці ж бувають ситуації, коли код основної програми містить власні обхідні дороги, компенсуючі помилки в бібліотеці. Ці обходи можуть бути як внесені свідомо (коли постачальник бібліотеки виправить, ще невідомо, а програма потрібна зараз), так і вийти самі собою (арифметичний знак, переплутаний парне число разів і т. д.). У цих випадках виправлення помилки може привести до труднопредськазуємим наслідків. Не можна також забувати і про можливість внесення нових помилок при виправленні старих, тому при розробці і експлуатації складних програмних систем, необхідно ретельно стежити за тим, що саме і де змінилося, а не просто фіксувати помилки.
Вимога "сумісності з точністю до помилок" — це лише полемічеськи загострене формулювання вимоги контрольованості поведінки коди. З наведених вище міркувань зрозуміло, що порушення такої контрольованості є проблемою, яка, не будучи так чи інакше дозволена, може серйозно ускладнити роботу адміністраторів системи і додатків.

Код, що розділяється, в системах сімейства Windows
Катастрофічні масштаби ця проблема приймає в системах сімейства Windows, де прийнято поміщати в дистрибутиви прикладних програм всі модулі, що потенційно розділяються, які цій програмі можуть потрібно, — середа виконання компілятора і так далі При цьому кожне застосування вважає своїм обов'язком помістити свої модулі, що розділяються, в C:\windows\system32 (у Windows Nt/2000/xp це заразом приводить до того, що установка найшкідливішої утиліти вимагає адміністраторських привілеїв). Засобів же простежити за тим, КТО, яку версію, чого, куди і навіщо поклав, практично не надається.
В кращому разі настановна програма запитує: "Тут ось у вас щось вже лежить, перезаписати?". Стандартний дєїнсталлятор містить список DLL, які належать даному застосуванню, і усвідомлює той факт, що ці ж DLL використовуються кимось ще, але не надає (і, мабуть, не намагається зібрати) інформації про той, КТО саме вони використовуються. Наявність реєстру об'єктів СОМ не вирішує проблеми, бо велика частина приношуваного кожним додатком коди (лапки стоять тому, що значна частина цієї коди нікому іншому, окрім застосування, що принесло його, не потрібна), що "розділяється", не є сервером СОМ.
В результаті, коли, наприклад, після установки MS Project 2000 перестає працювати MS Office 2000 [Mskb Ru270125], це нікого не дивує, а конфлікти між додатками різних розробників або різних "поколінь" вважаються неминучими. Встановити ж в одній системі і використовувати хоч би поперемінно дві різні версії одного продукту просто неможливо — проте, коли кожна версія продукту використовує власний формат даних, а конверсія між ними неідеальна, це часто виявляється бажано.
Розробники ж і тестери, яким треба забезпечити сумісність з різними версіями існуючих застосувань, при цьому просто опиняються в безвихідній ситуації. Невипадково постачальники Vmware (системи віртуальних машин для х8б) як одне з головних достоїнств своєї системи рекламують можливість тримати декілька копій Windows одночасно завантаженими на одній машині.
Приваблива дорога вирішення цієї проблеми — давати кожному пріложе-нію можливість вказувати, які саме DLL йому потрібні і де їх шукати, і дозволяти одночасно завантажувати однойменні DLL з різною семантикою — насправді зовсім не простий як з точки зору реалізації, так і з точки зору управління системою. Системи з віртуальною пам'яттю пропонують деякі підходи до реалізації цієї дороги, але це обговорюватиметься в разд. Бібліотеки, що розділяються.

 

:: Реклама ::

 

:: Посилання ::


 

 

 


Copyright © Kivik, 2017