Tworzenie aplikacji dla systemu operacyjnego QNX Neutrino

Transkrypt

Tworzenie aplikacji dla systemu operacyjnego QNX Neutrino
Max Hansen
[email protected]
Energy, Oil and Gas Industry
Congo, Angola and Singapore
Andrzej Rychlik
Politechnika Radomska, Instytut Informatyczno-Techniczny
Politechnika Łódzka, Instytut Informatyki
Tworzenie aplikacji dla systemu operacyjnego QNX Neutrino
Zintegrowane środowisko programistyczne (ang. Integrated Development
Environment) to oprogramowanie udostępniające zestaw narzędzi i bibliotek służących do
tworzenia, modyfikowania, testowania i konserwacji oprogramowania.
W systemie QNX najpopularniejszym środowiskiem programistycznym jest
Momentics IDE oparte o platformę Eclipse, działające w całości na Javie, a udostępniające
programiście, m.in. możliwość kompilacji kodu pod wybrany procesor.
Celem rozdziału jest przedstawienie procesu wytwarzania oprogramowania dla
systemu QNX Neutrino, poczynając od prezentacji popularnych kompilatorów, a skupiając
się głównie na tematyce wytwarzania w środowisku QNX Momentics IDE.
Wprowadzenie do programowania dla QNX Neutrino
Środowisk programistycznych dla systemu QNX jest wiele, jednak największą
popularnością cieszy się zaledwie garstka. Najpopularniejszy multiplatformowy kompilator to
CC i GCC wbudowany w system. Bardzo popularnym środowiskiem wykorzystującym GCC
jest GNAT. Posiada on rozbudowany system testów ACATS, zaś źródłem dobrych
przykładów na wykorzystanie w praktyce tego kompilatora może być strona
http://www.ajam.org.pl/ programy/ gnat-examples.tar.bz2.
Generalnie w systemie QNX praktycznie każde środowisko programistyczne oparte
jest o kompilator GCC, który w zależności od parametrów potrafi obsługiwać różne języki
programowania, poziomy optymalizacji, itp.
QNX Neutrino i QNX Momentics IDE
QNX to system czasu rzeczywistego, którego priorytetem jest bezpieczeństwo,
w tym gwarancja wykonywania operacji w określonych ramach czasowych. W związku z tym
istnieją odpowiednie zasady tworzenia oprogramowania dla tego systemu. Elementom
tworzonego oprogramowania przypisuje się odpowiednie priorytety wykonywania, wedle
których system będzie miał prawo na dopuszczanie opóźnień danego elementu, bądź tego
prawa nie otrzyma.
Dwa niezbędne składniki QNX Neutrino, traktowane łącznie jako jądro, objęte jedną
nazwą „pronto”, to:
 mikrojądro systemu, będące modułem programowym dostarczającym elementarnych
usług umożliwiających działanie procesów;
1

administrator procesów, czyli proces zarządzający pamięcią, przestrzenią nazw plików,
czy procesami w systemie.
Aby programować „pronto” niezbędna jest odpowiednia platforma programistyczna.
Najlepszym rozwiązaniem na rynku cieszącym się coraz większą popularnością jest QNX
Momentics.
QNX Momentics zawiera w pakiecie system operacyjny QNX Neutrino, środowisko
graficzne Photon, wraz z oprogramowaniem do tworzenia aplikacji okienkowych phAB,
środowisko programistyczne IDE, narzędzia do pisania sterowników DDK, pakiety BSP,
biblioteki i narzędzia GNU, instruktarzowe klipy wideo, obszerną dokumentację oraz szereg
kodów. Pakiety BSP (Board Support Package) są zestawem narzędzi do uruchamiania
systemu operacyjnego wraz z kompletną obsługą urządzeń docelowej platformy sprzętowej.
Liczba zestawów wciąż rośnie, a dostępne są pod adresem: http://www.qnx.com/products/
ps_bsps.
Przykładowy skrócony harmonogram tworzenia w QNX Momentics IDE
oprogramowania dedykowanego:
 Utworzenie projektu i zaimportowanie do niego pakietów BSP ‘File’ > ‘Import’;
 Opisanie kodem i konfiguracja na bazie BSP;
 Budowanie projektu przez ‘make all’ zawarty w BSP;
 W rezultacie mamy bootowalny obraz systemu operacyjnego!
Rys. 1. QNX Momentics IDE: Import pakietów źródłowych i BSP, krok 1
2
Wybieramy repozytorium źródeł BSP.
Rys. 2. QNX Momentics IDE: Import pakietów źródłowych i BSP, krok 2
Zaznaczamy interesującą nas wersję pakietów BPS.
Rys. 3. QNX Momentics IDE: Import pakietów źródłowych i BSP, krok 3.
Wybieramy architekturę na jaką ma być zaimportowany BSP
3
Ustawienia projektu, w tym katalog docelowy, prefix.
Rys. 4. QNX Momentics IDE: Import pakietów źródłowych i BSP, krok 4
Instalacja QNX Software Development Platform
Do pracy nad projektem dla systemu QNX niezbędne jest odpowiednie środowisko
programistyczne, jak QNX Software Development Platform. Ściągamy oprogramowanie ze
strony http://www.qnx.com/download/feature.html?programid=21180, na której także
wypełniamy formularz rejestracyjny. Otrzymamy na podany przez nas w formularzu adres
email, podziękowania za ściągnięcie testowej wersji platformy deweloperskiej QNX oraz
w chwilę później klucz licencyjny potrzebny do aktywacji testowej wersji oprogramowania.
QNX Software Development Platform oferuje wersje dla różnych systemów
operacyjnych jak Windows, Solaris, Linux, czy QNX Neutrino. Na potrzeby prezentacyjne
wybieramy wersję oprogramowania pod Windows, zaczynając instalację od zatwierdzenia
harmonogramu instalacyjnego QNX SDP. (Możliwość tworzenia oprogramowania w QNX
SDP dla jądra QNX Neutrino w systemach Windows, Solaris, czy Linux umożliwia
zmniejszenie kosztów wdrożenia narzędzi deweloperskich w firmach pracujących trwale
w środowiskach Windows/Linux)
4
Rys. 5. Instalacja QNX SDP – rozpoczęcie instalacji
Kolejnym krokiem jest wprowadzenie klucza produktu, który otrzymaliśmy po
rejestracji na podany w formularzu adres email.
Rys. 6. Instalacja QNX SDP wprowadzanie klucza produktu
Aby kontynuować należy także zaakceptować warunki licencji.
Rys. 7. Instalacja QNX SDP – akceptacja warunków licencji
5
Wybieramy ścieżkę, w której ma być zainstalowane oprogramowanie.
Rys. 8. Instalacja QNX SDP – wybór ścieżki instalacji
Zaznaczamy opcjonalne elementy produktu.
Rys. 9. Instalacja QNX SDP – wybór opcjonalnych elementów
Wyświetlone zostaje podsumowanie wybranych opcji do zatwierdzenia.
Rys. 10. Instalacja QNX SDP – zatwierdzenie podsumowania
6
Rozpoczyna się proces instalacji.
Rys. 11. Instalacja QNX SDP – proces ładowania środowiska
Po instalacji otrzymujemy informację o lokalizacji przewodnika licencyjnego,
po zatwierdzeniu, którego możemy rozpocząć pracę nad projektem.
Rys. 12. Instalacja QNX SDP – informacja o pozytywnym ukończeniu instalacji
Rys. 13. Instalacja QNX SDP – informacja o lokalizacji przewodnika licencyjnego
Pierwsze uruchomienie QNX Momentics IDE 4.7
Przy pierwszym uruchomieniu QNX Momentics IDE ukazuje nam się zakładka
‘Welcome’ dostępna przy późniejszych próbach odsłony pod menu ‘Help’ > ‘Welcom’.
7
Rys. 14. Instalacja QNX SDP – Powitanie
Zakładka oferuje bezpośredni dostęp do dokumentacji środowiska i języków
programowania, wprowadzenie do środowiska, kursy, przykładowe małe projekty
wdrożeniowe programisty oraz bezpośrednie przekierowanie do właściwej części
środowiska, celem rozpoczęcia pracy nad projektem (tzw. Workbench).
Rys. 15. Instalacja QNX SDP – Workbench starter
Po kliknięciu opcji Workbench uruchomiona zostaje część właściwa środowiska.
8
Rys. 16. Instalacja QNX SDP – Workbench
Tworzenie projektu w QNX Momentics IDE 4.7
Aby utworzyć nowy projekt C++, wybieramy ‘File’ > ‘New’ > ‘QNX C++ Project’
z głównego menu.
Rys. 17. QNX SDP – Tworzenie projektu, krok 1
Nadajemy jakąś nazwę projektowi (np. ‘MyFirstProject’).
9
Rys. 18. QNX SDP – Tworzenie projektu, krok 2
W następnym kroku wybieramy architekturę procesora (zakładka ‘Build Variants),
na którą będziemy tworzyć oprogramowanie (w naszym przypadku x86), klikając przycisk
"Finish’ celem utworzenia szkieletu projektu.
Rys. 19. QNX SDP – Tworzenie projektu, krok 3
Naszym oczom ukaże się prosty przykładowy kod, realizujący wyświetlenie
na ekranie powitania w środowisku QNX Momentics IDE.
#include <cstdlib>
#include <iostream>
int main(int argc, char *argv[ ]) {
std::cout << "Welcome to the QNX Momentics IDE" << std::endl;
return EXIT_SUCCESS;
}
Kompilacja, konsolidacja, uruchamianie w QNX Momentics IDE 4.7
Celem utworzenia plików wykonywalnych prawym przyciskiem myszy klikamy
na nazwie projektu wybierając ‘Build Project’. W konsoli wyświetlone zostaną opcje z jakimi
program został skompilowany i/lub ewentualne błędy kompilacji.
10
Rys. 20. QNX SDP – Logi procesów tworzenia
Uruchamianie programu konfigurujemy po wyborze opcji ‘Run’ > ‘Run As’ > ‘C/C++
QNX application’ ustanawiając, m.in. argumenty uruchomieniowe, wirtualne środowisko
w jakim projekt ma być uruchamiany, priorytet czy sposób kolejkowania.
Rys. 21. QNX SDP – Konfiguracja uruchomieniowa projektu
Po uzupełnieniu pól przede wszystkim w karcie Main, możemy uruchomić aplikację,
czego rezultat obejrzymy w podglądzie konsoli.
Tworzenie oprogramowania dla urządzeń wbudowanych
QNX Momentics wspiera 3 nurty tworzenia oprogramowania:
– self-hosted development
Oprogramowanie tworzy się i uruchamia na tym samym komputerze.
– cross-development
Przygotowuje się oprogramowanie dla maszyny docelowej target innego typu niż
maszyna deweloperska host. Główną i chyba najistotniejszą różnicą jest typ
procesora w obu komputerach.
– host-target development
Oprogramowanie tworzy się na stacji zwanej hostem, a uruchamia na maszynie
docelowej zwanej targetem. Metodą tą tworzy się oprogramowanie dla systemów
wbudowanych, by uniknąć problemów związanych z różnicą architektury hosta
i targetu.
11
Przykładowe problemy związane z różnicami architekturalnymi systemu hosta
i systemu docelowego:
 za małe zasoby pamięciowe, procesorowe;
 brak, bądź zbyt ubogi interface;
 niewystarczające zasoby osprzętowe;
 brak wsparcia dla danych rozdzielczości.
Celem uzyskania dostępu do systemu docelowego z IDE, należy utworzyć projekt
docelowy (‘Target Project’), przez otwarcie perspektywy informacji systemowej: w menu
okna ‘Open Perspective’ > ‘Other’ > ‘QNX System Information’.
W pustym oknie ‘Target Navigator’ klikamy prawym przyciskiem myszy, po czym
wybieramy ‘Ad New Target’. Wprowadzamy następnie nazwę systemu docelowego oraz
jego adres IP. Jeśli docelowym systemem jest QNX Neutrino w konsoli ukaże się lista
procesów uruchomionych w tymże systemie.
Obsługa wątków
W systemie QNX obsługa wątków realizowana jest przez mikrojądro. System
zapewnia wszystkie procedury obsługi i synchronizacji wątków, dostarcza standardowego
interfejsu wątków POSIX 1003.1.
Tworzenie wątków w programach Neutrino jest bardzo proste. Wystarczy dołączyć
bibliotekę pthread.h do nagłówka programu C/C++ i wykorzystać funkcje pthread_*().
Dołączanie nagłówka celem korzystania z wątków POSIX:
#include <pthread.h>
...
Przy kompilacji (dokładniej przy konsolidacji) należy dołączyć bibliotekę libc.
Przykładowo, żeby skompilować program a.c należy wpisać:
$ qcc a.c -l c
Wszystkie funkcje oraz typy danych tworzące API wątków POSIX’owych mają nazwy
rozpoczynające się od przedrostka pthread_.
Wątki obiektowo
Wątkowość bardzo słabo nadaje się do implementacji obiektowej. Wątki tworzone
i wysyłane są w blokach kodowych, po czym dostarczane z wywołań zwrotnych funkcji do
wykonywanych zadań. Taka kolej rzeczy wpływa na to, że programista sięga do zmiennych
globalnych, powstają segmenty, całkowicie słabego jakościowo kodu.
Tradycyjnie tworzenie i wysyłanie wątku wygląda mniej więcej tak:
void * callback_function(void *object)
{
// Wykonywanie jakiegoś kodu
}
int main(int argc, char **argv) {
...
int threadId;
threadId = ThreadCreate(0, &callback_function, NULL, NULL);
12
...
}
ThreadCreate jest funkcją, która tworzy i wysyła wątek.
#include <sys/neutrino.h>
int ThreadCreate(
pid_t pid,
void* (func)( void* ),
void* arg,
const struct _thread_attr* attr );
pid: tu używamy ID procesu, którym chcemy utworzyć wątek lub 0 by utworzyć wątek
w aktualnym procesie.
Przykład uproszczonego programu opartego o wątki:
#include <pthread.h>
//--------------------------------------------------------void *
funcThreadA( void )
{
int a_petla;
for ( a_petla = 1; a_petla <= 20; a_petla++ )
{
printf( "A\n" );
sleep( 1 ); // opoznienie
}
return;
}
//--------------------------------------------------------void *
funcThreadB( void )
{
int b_petla;
for ( b_petla = 1; b_petla <= 10; b_petla++ )
{
printf( "B\n" );
sleep( 2 );
}
return;
}
//----------------------------------------------------------int
main( void )
{
pthread_t threadA;
13
pthread_t threadB;
printf( "Startowanie glownego programu\n" );
/* Tworz watek, dodaj do istniejacego,
pthread_create( &threadA, NULL, &funcThreadA, NULL );
pthread_create( &threadB, NULL, &funcThreadB, NULL );
printf( "Glowny program oczekuje..\n" );
pthread_join( threadA, NULL );
pthread_join( threadB, NULL );
printf( "Glowny program konczy\n" );
return 0;
}
wątku.
Istnieje możliwość na znalezienie prostego rozwiązania obiektowego tworzenia
class SomeClass
{
public:
SomeClass() {
ThreadCreate(0, &SomeClass::someMethod, NULL, NULL);
}
private:
int someVariable;
static void *someMethod(void *object) {
SomeClass *classInstance =
dynamic_cast<SomeClass*>(object);
if (!classInstance)
return NULL;
while (!done) {
if (somethingChanged)
classInstance->someVariable++;
}
}
};
Administracja procesami
Procesy są podstawowymi składnikami budulcowymi każdej aplikacji systemów
wielozadaniowych. W systemie QNX istnieje kilka metod tworzenia procesów.
Metody tworzące procesy w systemie QNX to:
 fork() – tworzy proces potomny procesu macierzystego w formie kopii;
 exec*() – zastąpienie bieżącego procesu procesem utworzonym z podanego jako
parametr funkcji pliku wykonywalnego;
 spawn*() – dają efekt wywołania sekwencji funkcji fork() i exec*();
 system() – najprostsza metoda utworzenia procesu.
Na zakończenie procesu powinny składać się następujące czynności:
 zakończenie komunikacji z innymi procesami;
14


zwolnienie zasobów zajmowanych przez proces;
oczekiwanie na zakończenie procesów potomnych.
Metody kończące procesy w systemie QNX to:
exit() – powoduje zakończenie bieżącego procesu;
wait(), waitpid() – wykorzystywane do synchronizacji zakończenia procesu;
spawn*() – dają efekt wywołania sekwencji funkcji fork() i exec*();
system() – najprostsza metoda utworzenia procesu.
Do kontroli procesów w systemie QNX wprowadzono odpowiednie limity, które
można określać metodą setrlimit(), zaś testować metodą getrlimit().




Tab. 1. Zasoby systemowe podlegające ograniczeniu
Oznaczenie
RLIMIT_CORE
Opis
Pamięć operacyjna
RLIMIT_CPU
Czas procesora
RLIMIT_DATA
Wielkość pamięci pobranej ze sterty
RLIMIT_FSIZE
Max plik tworzony przez proces
RLIMIT_NOFILE
Max liczba deskryptorów plików
tworzonych przez proces
ELIMIT_STACK
Maksymalny rozmiar stosu
RLMIT_NPROC
Maksymalna liczba procesów
potomnych tworzonych przez proces
Akcja przy przekroczeniu
Zakończenie procesu
Wysłanie sygnału SIGCPU do procesu
przekraczającego zasób
Funkcja pobierająca pamięć kończy się
błędem
Wysłanie sygnału SIGXFSZ do procesu
przekraczającego zasób
Funkcja tworząca ponad limitowe pliki
zakończy się błędem
Wysłanie sygnału SIGSEGV do procesu
przekraczającego stos
Procesy potomne przekraczające limit
nie będą tworzone
Celem kontrolowania danych procesów należy posługiwać się odpowiednimi
atrybutami procesów.
15
Tab. 2. Atrybuty procesów w systemie QNX
Atrybut procesu
Identyfikator procesu PID
Identyfikator procesu macierzystego PPID
Numer grupy procesów PGID
Identyfikator sesji SID
Rzeczywisty identyfikator użytkownika UID
Rzeczywisty identyfikator grupy GID
Środowisko procesu
Katalog bieżący
Priorytet procesu
Strategia szeregowania




Testowanie
getpid()
getppid()
getpgrp()
getsid()
getuid()
getgid()
getenv()
getcwd()
getprio(),
sched_getparam()
sched_getparam()
Ustawianie
setpgrp(), setpgid()
setsid()
putenv()
chdir()
setprio(),
sched_setparam()
sched_setparam()
Zarządzanie procesami wiąże się z następującymi czynnościami:
testowaniem i ustawianiem atrybutów procesu;
tworzeniem i kończeniem procesu;
synchronizacją zakończenia procesu potomnego z jego procesem macierzystym;
testowaniem statusu zakończonego procesu potomnego.
W systemach wielozadaniowych prawie zawsze istnieje pewien podzbiór procesów
oddziaływującym na siebie. Źle zorganizowany dostęp do tych samych zasobów prowadzi
do wielu problematycznych sytuacji.
W systemach opartych o priorytety z możliwością wywłaszczania (w tym QNX),
projektanci muszą wykazywać się szczególną ostrożnością. Najczęściej powstającym złym
scenariuszem jest tworzenie procesów o wysokich priorytetach, przekazujących między
sobą zasoby, a nie dopuszczających pozostałych procesów. Takie sytuacje doprowadzają
do niemożliwości zakończenia zadań mniej priorytetowych, aczkolwiek nadal ważnych,
nazywa się to „głodzeniem”, bądź „wykluczeniem”. Innym jeszcze gorszym problemem są
zakleszczenia procesów lub inwersja priorytetów.
Zakleszczenie procesów to sytuacja, w której dane procesy nawzajem blokują sobie
wzajemnie zasoby systemowe. Przykładowo, istnieją w systemie 3 procesy, nazwijmy je P1,
P2, P3 oraz docelowe zasoby zwane Z1, Z2, Z3. Proces P1 posiada Z1, lecz potrzebuje do
działania również dostępu do Z2, zaś P2 nie może być wykonane, ponieważ potrzebuje
dostępu do Z3, do tego jeśli P3 potrzebuje dostępu do Z1, zarezerwowanego przez P1
system potrzebuje jakichś określonych metod wykrywania sytuacji i limitów czasowych na jej
blokowanie (algorytmy wykrywające zakleszczenie procesów opierają się o teorię grafów).
Inwersja priorytetów polega na tym, że zadanie o niskim priorytecie zajmując zasób
dzielony, zmusza zadanie o wyższym priorytecie do przejścia w stan „blokowane”
i oczekiwania na zwolnienie tego zasobu. Taka sytuacja prowadzi do wielu
16
niebezpieczeństw, które w najgorszym wypadku mogą powodować powstanie sporych
anomalii czasowych w systemie.
System operacyjny QNX posiada sprawne systemy zarządzania procesami
współbieżnymi, tj. nadawanie procesom priorytetów, wywłaszczanie procesów mniej
priorytetowych, kolejkowanie procesów, zoptymalizowane czasowo przełączanie procesów.
W systemie QNX priorytety, to liczby całkowite z zakresu 0-31 dla zadań super
użytkownika lub 0-19 dla pozostałych. Wątki dziedziczą priorytet od swoich zadań
macierzystych. Najniższy priorytet działa w tak zwanym tle (ang. idle), a jego wątki
realizowane są wtedy, gdy w systemie nie ma nic innego „do roboty”. Zadanie idle jest
zawsze gotowe do wykonania (ang. ready to run). Zadania uruchomione przez powłokę
standardowo uzyskują priorytet 10. Każde zadanie, w oparciu o swój priorytet, trafia
do odpowiedniej kolejki, tzw. FIFO (ang. First In First Out), działając wedle zasady „pierwszy
przyszedł, pierwszy zostanie obsłużony”.
System QNX dostarcza trzy algorytmy szeregowania procesów, które są używane,
gdy istnieją równoważne priorytetowo zadania ubiegające się o procesor:
 Kolejka FIFO. Zadanie wybrane do wykonywania, kontynuuje swoje działania, aż samo
odda sterowanie, np. procesowi systemowemu, zostanie wywłaszczone przez zadanie
o wyższym priorytecie, bądź trwa do zakończenia.
 Algorytm karuzelowy, oparty o kolejkę FIFO, lecz z limitem czasowym, który wynosi
50 ms. Wówczas zadanie zostaje wywłaszczone, poza warunkami opisanymi we
wcześniejszym algorytmie, również wtedy, kiedy wykorzysta przydzielony mu czas.
 Algorytm adaptacyjny (ang. adaptive scheduling), podobnie jak karuzelowy ograniczony
kwantem czasu, lecz jeśli dane zadanie wykorzysta przydzielony czas procesora
i nie zostanie zablokowane, to jego priorytet jest dekrementowany o jeden poziom,
po czym po przebiegu każdej kolejnej sekundy oczekiwania na wykonanie podnoszony
o jeden, lecz nie wyżej niż do stanu początkowego. Algorytm ten znajduje zastosowanie
w sytuacjach, kiedy zadania wykonujące ogromne ilości obliczeń dzielą czas procesora
z zadaniami interaktywnymi. Jest to domyślny algorytm dla programów uruchamianych
przez powłokę.
Algorytm szeregowania może być przyporządkowywany do zadania w sposób
dynamiczny. Wybór konkretnego algorytmu szeregowania może być dokonywany przy
pomocy funkcji POSIX takich jak: sched_getscheduler(), sched_set_scheduler().
Reasumując, podczas projektowania aplikacji działających w oparciu o priorytety
należy trzymać się zasad bardzo starannego zarządzania zasobami, bowiem nawet te
najlepsze metody zabezpieczeń systemowych niosą za sobą ryzyko krytycznych opóźnień
systemu, utraty danych, bądź innych niekorzystnych sytuacji.
Zadania powinny działać według określonych zasad:
 procesy zwalniają zasoby możliwie najszybciej;
 hierarchiczna organizacja zasobów;
 implementacja protokołu przydziału.
17
Błędy a QNX Neutrino
Odnajdywanie błędów
Ponieważ każdy program posiada błędy, nigdy nie ma pewności czy i kiedy
otrzymamy zapytanie od użytkownika stworzonej przez nas aplikacji dlaczego po kilku
dniach użytkowania program przestaje działać. Jeśli tak się stanie może to oznaczać,
że nasz program generuje błędy, gdzieś w pamięci.
Debugowanie błędów pamięciowych potrafi być irytujące, jednak na nasz ratunek
przychodzi perspektywa analizy pamięci QNX. Ułatwieniem dla tejże perspektywy jest
modułowa budowa systemu Neutrino, izolująca problematyczne procesy w systemie.
Perspektywa analizy pamięci QNX pokazuje jak nasz program wykorzystuje pamięć
pomagając upewnić się, że nie wywołuje problemów. Perspektywa ta pomaga szybko
wskazać błędy pamięciowe naszego środowiska testowego przed tym jak nasz klient
otrzyma produkt.
Należy pamiętać jednak, iż perspektywa analizy pamięci potrafi dawać
nieoczekiwane rezultaty, kiedy więcej niż jedno IDE komunikuje się z systemem docelowym.
Tak więc do używania omawianej perspektywy należy zawsze mieć pewność, iż tylko jedno
IDE jest podłączone pod system docelowy.
Wycieki pamięciowe
Wycieki pamięciowe polegają na nadmiernym zużywaniu pamięci przez aplikację,
bądź próbie zapisu danych w niedozwolonym obszarze. Działania takie mogą być
spowodowane przez alokację pamięci, która nie jest wolna, referencję na zły obszar
pamięci, bądź nie zwalnianie pamięci przez programistę. Typową reakcją zabezpieczeń
systemu przy wycieku aplikacji jest błąd krytyczny w momencie, gdy system identyfikuje
próbę zapisu w chronionym obszarze. Nie ma jednak zabezpieczeń przed sytuacjami, gdzie
programista nie zwalnia zarezerwowanej wcześniej pamięci. W takiej sytuacji, jeśli
rezerwacja wywoływana jest na zasadzie aktualnych potrzeb automatycznie może dojść do
sytuacji niekontrolowanego rozrastania się aplikacji w przestrzeni pamięciowej. (Sytuacje
takie wyklucza Java, która zaopatrzona jest w tzw. garbage collection, działający na
zasadzie regularnego sprawdzania i usuwania z pamięci niepotrzebnych elementów.
Jednak języki programowania systemów specjalistycznych jak C/C++ wymuszają na
programiście konieczność przykładania dodatkowej uwagi, co swoją drogą ma dobre strony
pod kątem oszczędności zasobów.
QNX Neutrino tropi zachowanie każdego programu oraz zarezerwowaną przez niego
pamięć, więc kiedy nastąpi zawieszenie programu system przywróci całą pamięć przez
niego zarezerwowaną, włączając tą utraconą przez wycieki.
Jeśli nasz program ma poważny wyciek, bądź wyciek powolny, ale niezawieszający
programu, może to prowadzić nawet do błędów głównych serwisów systemu.
Następujące elementy edytora analizy pamięci mogą pomóc odnaleźć błędy i uporać
się z nimi:
 Allocation tabs: pokazuje wszystkie instancje, w których nasz program alokuje,
realokuje czy też zwalnia pamięć, co pozwala określić, które elementy zostały
niepotrzebnie zarezerwowane w zły sposób.
18

Errors tabs: pokazuje wszystkie błędy pamięciowe, wliczając w to wycieki.
Aby uruchomić program z analizą pamięci, należy we właściwościach aplikacji
wybrać typ uruchamiania lub debbugowania, po czym odszukać opcje memory analisys.
Literatura
http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/ [dostęp [dostęp 22.05.2011]
http://www.qnx.com/developers/docs/6.3.2/momentics/quickstart/about.html
[dostęp 20.05.2011]
http://www.qnx.com/developers/docs/6.3.2/photon/prog_guide/about.html
[dostęp 23.05.2011]
http://www.qnx.com/developers/docs/6.3.0SP3/ide_en/user_guide/concepts.html
[dostęp 23.05.2011]
http://psy.swan.ac.uk/staff/carter/qnx/tut_nto_thread_ab.htm [dostęp 10.06.2011]
http://www.eetimes.com/design/embedded [dostęp 10.06.2011]
http://www.se.rit.edu/~rtembed/QNX-tutorials/Guides/OOThreads-tutorial.pdf
[dostęp 20.05.2011]
Hansen M., Rychlik A.: Przeglad systemów operacyjnych w systemach bezpieczenstwa.
[W:] Informatyka w dobie XXI wieku. Nauka, technika, edukacja a nowoczesne technologie
informatyczne. Pod red. Aleksandra Jastriebowa i Marii Raczynskiej. Radom 2011
19

Podobne dokumenty