Dynamic loading
Dynamic loading (dynamické načítání) je v informatice označení pro mechanismus, který načte knihovnu do paměťového prostoru za běhu procesu. Běžící proces tak získá možnost volat procedury a funkce, které se nacházejí v načtené knihovně. Knihovnu lze později z paměti uvolnit. Mechanismus umožňuje programátorovi v případě nedostupnosti knihovny provést náhradní činnost (použít alternativní knihovnu, zobrazit hlášení uživateli a podobně). Tím se odlišuje od klasického zavádění dynamických knihoven při spuštění programu, kdy musí být přítomny všechny potřebné knihovny.
Historie
editovatDynamické načítání bylo běžným mechanismem pro operační systém IBM/360 (začátek 60. let až do současné Z/Architektury) a to zejména pro obsluhu vstupně-výstupních rutin, COBOL a PL/1 běhových knihoven. Co se týče programování aplikací, nahrávání je do značné míry transparentní, protože je většinou vyřešené na úrovni operačního systému. IBM využívá dynamické načtení od 70. let 20. století u transakčního zpracování strategického systému CICS a to jak pro jádro operačního systému, tak i pro normální aplikační programy. Opravy pak mohou být uskutečněny za běhu systému nebo programu bez nutnosti jejich restartu.
Mezi hlavní výhody patří:
- opravy subsystému opravují celý program bez nutnosti jeho nového linkování
- knihovny mohou být chráněny před neautorizovanou úpravou
Použití
editovatDynamické načítání je nejčastěji používáno v implementaci softwarových pluginů (modulární struktura Apache HTTP Serveru). Nebo v programech, které nabízejí více podporovaných knihoven a uživatel si je jednotlivě může volit (rozšiřující knihovny pro PHP).
C/C++
editovatDynamické načítání nepodporují všechny systémy. Mac OS X, Linux a Solaris nabízí dynamické načítání prostřednictvím knihovních „dl“ funkcí v jazyce C. Operační systém Windows podporuje dynamické načítání pomocí volání Windows API.
Shrnutí
editovatNázev | Standard POSIX/UNIX API | Microsoft Windows API |
---|---|---|
Zařazení hlavičkového souboru | #include <dlfcn.h>
|
#include <windows.h>
|
Definice hlavičky | dl
( |
Kernel32.dll
|
Načtení knihovny | dlopen
|
LoadLibrary LoadLibraryEx |
Extrahování obsahu | dlsym
|
GetProcAddress
|
Zavření knihovny | dlclose
|
FreeLibrary
|
Načtení knihovny
editovatNačtení knihovny se provede prostřednictvím LoadLibrary
nebo LoadLibraryEx
na operačním systému Windows a pomocí dlopen
na operačních systémech na bázi Linuxu. Následují příklady:
Linux, *BSD, Solaris, etc.
editovatvoid* sdl_library = dlopen("libSDL.so", RTLD_LAZY);
if(sdl_library == NULL) {
// oznámení chyby ...
} else {
// výsledek zavoláním dlsym
}
Mac OS X
editovatUNIX library:
void* sdl_library = dlopen("libsdl.dylib", RTLD_LAZY);
if(sdl_library == NULL) {
// oznámení chyby ...
} else {
// výsledek zavoláním dlsym
}
void* sdl_library = dlopen("/Library/Frameworks/SDL.framework/SDL", RTLD_LAZY);
if(sdl_library == NULL) {
// oznámení chyby ...
} else {
// výsledek zavoláním dlsym
}
Windows
editovatHMODULE sdl_library = LoadLibrary("SDL.dll");
if( sdl_library == NULL) {
//oznámení chyby ...
} else {
// výsledek zavoláním GetProcAddress
}
Extrahování obsahu knihovny
editovatExtrahování obsahu dynamicky načítané knihovny je dosaženo pomocí příkazu GetProcAddress ve Windows a dlsym v Unix systému.
Linux, *BSD, Mac OS X, Solaris, etc.
editovatvoid* initializer = dlsym(sdl_library,"SDL_Init");
if(initializer == NULL) {
// oznámení chyby ...
} else {
...
}
Windows
editovatFARPROC initializer = GetProcAddress(sdl_library,"SDL_Init");
if(initializer == NULL) {
// report error ...
} else {
...
}
Převod extrahovaného obsahu knihovny
editovatVrácený výsledek prostřednictvím dlsym()
nebo GetProcAddress()
musí být převeden do požadované destinace předtím, než může být použit.
Windows
editovatV případě systému Windows, konverze je jednoduchá, protože FARPROC je v podstatě již ukazatel funkce:
typedef INT_PTR (*FARPROC)(void);
Může nastat problém, pokud adresy objektu jsou vyvolány místo funkce. Nicméně, obvykle jeden chce získat funkce stejně, takže to není ve výsledku problém.
typedef void (*sdl_init_function_type)(void);
sdl_init_function_type init_func = (sdl_init_function_type) initializer;
UNIX (POSIX)
editovatDle specifikace POSIX je výsledkem provedení dlsym()
prázdný ukazatel (pointer), což způsobuje problém. Je to způsobeno tím, že programovací jazyky C a C++ nedovolují provést konverzi mezi ukazateli na objekty a ukazateli funkcí (není vyžadováno aby měl ukazatel funkce stejnou velikost jako ukazatel na objekt). Je tedy striktně zakázáno provést konverzi mezi typem void*
a ukazatelem na funkci. Na většině v současnosti používaných systémů jsou ukazatele na funkce s ukazateli na objekty mezi sebou již konvertibilní.
Následující fragment kódu ukazuje jeden ze způsobů řešení, který umožňuje provádět tuto konverzi v různých systémech:
typedef void (*sdl_init_function_type)(void);
sdl_init_function_type init_func = (sdl_init_function_type)initializer;
Výše uvedená část programového kódu může u některých kompilátorů vyvolat toto varovné hlášení: „Přejmenování ukazatele dereferenčního typu porušuje pravidla aliasingu“. Řešením je použití následujícího programového kódu:
typedef void (*sdl_init_function_type)(void);
union { sdl_init_function_type func; void * obj; } alias;
alias.obj = initializer;
sdl_init_function_type init_func = alias.func;
Tím se zakáže varovné hlášení.
Související články
editovatExterní odkazy
editovat- General Links
- C/C++ UNIX API:
- C/C++ Windows API:
- Java API: