DioneOS

DioneOS (wymowa /djoneos/) – wielowątkowy system operacyjny czasu rzeczywistego z wywłaszczaniem. Przeznaczony jest dla 16-bitowych mikrokontrolerów Texas Instruments MSP430x.

System DioneOS charakteryzuje się zwartością kodu i efektywnością. Cechy te są istotne dla programów uruchamianych na platformach o nierozbudowanych zasobach (takich jak msp430): tzn. niezbyt dużej częstotliwości oscylatora (do 25 MHz) i ograniczonej ilości pamięci. Efektywność rozumiana jest tutaj jako niewielkie dodatkowe obciążenie procesora wynikające z użycia systemu. Według takiej definicji: im mniejsze jest to dodatkowe obciążenie, tym system jest bardziej efektywny.

System DioneOS jest przeznaczony do urządzeń autonomicznych z ograniczonym bezpośrednim dostępem użytkownika. Głównym rdzeniem systemu są elementy pozwalające na tworzenie wielowątkowego oprogramowania przy wykorzystaniu standardowych, dobrze znanych pojęć. System nie dostarcza graficznego interfejsu użytkownika (np. systemu okienkowego).

Model pamięci

[edytuj | edytuj kod]

Firma Texas Instruments produkuje wiele rodzin mikrokontrolerów wykorzystujących rdzeń msp430. W zależności od wersji, układy te są wyposażone w różną ilość pamięci FLASH i pamięci RAM (np. msp430f2201 posiada odpowiednio 1KB/128B, a msp430f5438 - 256KB/16KB). Gdy rozmiar pamięci przekracza[1] 64KB, adresowanie 16 bitowe staje się niewystarczające. Z tego powodu producent wprowadził rozszerzenie podstawowej architektury oznaczając ją msp430x. Posiada ona większe rejestry (20 bitowe) oraz dodatkowe instrukcje pozwalające na operowanie na takich danych.

Podczas budowania programu dla procesora msp430 decyduje się jaki model pamięci ('near' albo 'far') będzie używany w odniesieniu do pamięci FLASH jak i RAM. Wybór modelu ma wpływ na zakres dostępnej pamięci programu oraz danych. Dlatego też aby wykorzystać pamięć FLASH umieszczoną ponad 64 kB granicą, niezbędne jest wykorzystanie modelu 'far' dla kodu. Skutkuje to użyciem 20-bitowych rejestrów i adresów funkcji.

System DioneOS jest przystosowany do współpracy z modelem 'far' dla kodu oraz 'near' dla danych. Z tego względu możliwe jest uruchamianie pod jego kontrolą firmware'u o znacznym rozmiarze, wykorzystującym całą dostępną pamięć FLASH.

Zarządzanie wątkami

[edytuj | edytuj kod]

Program uruchamiany pod systemem DioneOS jest podzielony na wątki, które są wykonywane pseudo-równolegle. Wątkom są przypisane unikalne priorytety, które są wykorzystywane do ustalenia ich istotności i szeregowania wykonania.

W systemie DioneOS wątek może być w jednym z następujących stanów:

  • RUNNING - wątek jest wykonywany przez procesor,
  • READY - wątek jest gotowy do uruchomienia,
  • WAITING - wątek jest zablokowany, oczekuje na jakimś obiekcie synchronizującym.

W danym momencie wykonywany jest tylko jeden wątek. Jest to ten, który posiada najwyższy priorytet i nie jest zablokowany. Zmiana stanu wątku może nastąpić m.in. z powodu:

  • wyzwolenia obiektu, na którym wątek oczekuje,
  • próbie przywłaszczenia obiektu, który jest zablokowany (np. mutex, który jest już przywłaszczony),
  • upłynięcia timeoutu,
  • zmiany stanu innego wątku, co może prowadzić do jego wywłaszczenia.

System DioneOS pozwala na uruchomienie do 16 wątków, z czego jeden, posiadający najniższy priorytet, jest wątkiem typu 'bezczynny' [ang. idle]. Ten szczególny wątek powinien być zawsze gotowy do uruchomienia, więc nie można w nim używać funkcji blokujących, które mogłyby doprowadzić do jego wstrzymania (tzn. przejścia w stan WAITING). Wątek bezczynny może być wykorzystany do określenia stopnia obciążenia systemu.

Elementy systemu

[edytuj | edytuj kod]

System DioneOS dostarcza następujące elementy i metody:

  • obiekty synchronizujące: mutexy i semafory, przeznaczone do synchronizacji pomiędzy wątkami, sygnalizacji z procedury przerwania do wątku oraz do ochrony dostępu do wspólnych zasobów,
  • kontrola czasu: timery, usypianie wątku na dany okres, przeterminowanie,
  • obiekty do komunikacji pomiędzy wątkami. Do przekazywania wiadomości używane są niewielkie struktury danych, które mogą być buforowane w kolejkach implementowanych jako bufory cykliczne.
  • alokator pamięci dynamicznej w postaci partycji ang. memory pool. Ten sposób przydzielania pamięci opiera się na blokach o stałej wielkości, co może prowadzić do większego zużycia pamięci ale jest odporne na problem fragmentacji, który występuje przy wykorzystaniu sterty. Klasyczne metody alokacji (malloc/free) na stercie są również dostępne i wynikają ze standardowych bibliotek języka C.
  • mechanizmy wspomagające testowanie, np. sygnalizacja zdarzeń na końcówkach procesora, wyjątki krytyczne, oznaczanie usuniętych elementów wspomagające wykrywanie błędów: użycia zwolnionego obiektu, podwójnego zwolnienia, itp.

Przełączanie kontekstu

[edytuj | edytuj kod]

Tak jak to zostało opisane w podrozdziale 'Zarządzanie wątkami' program pracujący w systemie składa się z pseudo-równoległych wątków. Każdy z nich posiada swój własny kontekst, na który składa się stan rejestrów procesora, adres wykonywania oraz własny stos. Podczas przełączenia pomiędzy wątkami system dokonuje zachowania kontekstu bieżącego wątku i przywraca kontekst wątku uruchamianego. Dzięki temu możliwe jest przerwanie wykonania wątku w dowolnym momencie i późniejsza kontynuacja od tego punktu, nawet gdy te dwie operacje są rozdzielone wykonaniem kodu dla innego wątku. Trzeba pamiętać, że wywłaszczanie, a w konsekwencji przełączenie kontekstu może nastąpić w dowolnym momencie, nawet gdy nie wywołuje się żadnej funkcji systemowej w danym wątku. Może stać się to w miejscu nieoczekiwanym przez wykonywany kod, a mimo to dzięki działaniu systemu i zachowywaniu kontekstu, wykonywanie kodu wątku jest niezakłócone. Z punktu widzenia wątku przełączenie może odbywać się w tle.

Operacja przełączania kontekstu jest kluczowym elementem systemu a czas wykonania tej operacji decyduje o jego efektywności. Z tego powodu w systemie DioneOS ten fragment został zoptymalizowany pod względem czasu działania. Najważniejsze elementy zostały napisane w asemblerze pozwalając uzyskać przełączenie w czasie od 12-17 μs (dla fosc = 25 MHz)[2].

W systemie DioneOS przełączenie z jednego wątku na drugi może być wywołane z procedury obsługi przerwania. Tego typu operacja jest przydatna do przeniesienia obsługi zdarzenia do wątku, a wykorzystywana najczęściej przy dwuwarstwowej strukturze:

  1. funkcja obsługi przerwania (ISR), która jest wywoływana po wystąpieniu przerwania sprzętowego. W trakcie jej wykonywania przerwania zostają wyłączone. Z tego względu nie może być wykonywana zbyt długo, aby nie utracić responsywności systemu. W takiej części programu wykonuje się zazwyczaj operacje wymagające szybkiej reakcji a inne przekazuje się do warstwy drugiej,
  2. druga warstwa - przetwarzanie zdarzenia w osobnym wątku, tego rodzaju fragment nie blokuje przerwań i może być wywłaszczony. W tej warstwie nie ma tak silnych ograniczeń na czas wykonywania operacji jak w pierwszej, ponieważ wykonywanie kodu nie powoduje zablokowania systemu.

Przełączenie kontekstu liczone od miejsca sygnalizacji w ISR do przywrócenia innego wątku jest wykonywane w systemie DioneOS w ciągu około 10 μs (dla fosc=25 MHz).

Konfiguracja

[edytuj | edytuj kod]

System DioneOS posiada wiele opcji wpływających na kod, który pojawia się w jego obrazie po kompilacji, duża część z nich ma charakter przełączników. Są one zgromadzone w jednym pliku konfiguracyjnym i mogą być modyfikowane przez programistę. W ten sposób możliwe jest włączanie m.in. dodatkowych elementów wspomagających testowanie lub ich pominięcie. Uzyskuje się więc obraz systemu przystosowany do debugowania z wieloma dodatkowymi warunkami poprawności albo obraz zoptymalizowany do końcowej produkcji urządzenia.

Poniżej przedstawiony jest fragment pliku konfiguracyjnego:

[...]
#define CFG_CHECK_OVERFLOW 	        /* testowanie przepełnienia w semaforach/mutexach */
#define CFG_CHECK_LOCK		        /* testowanie zablokowania z powodu wywłaszczenia podczas blokady */
#define CFG_LISTDEL_WITH_POISON         /* wprowadza oznaczanie usuniętych elementów listy w os_list1_del()*/
#define CFG_MEM_POOL_POISON_FILL 0xDAAB /* wzór do oznaczania zwalnianych elementów pamięci */
#define CFG_LISTDEL_POISON     0xABBA   /* wzór do oznaczania zwalnianych elementów listy */
#define CFG_CHECK_EMPTY_SEM_DESTROY     /* sprawdzanie semafora przy niszczeniu w os_sleep()*/ 
#define CFG_FILL_EMPTY_MEM_POOL         /* wypełnianie nieużywanej pamięci wzorem */
[...]

Przypisy

[edytuj | edytuj kod]
  1. w zasadzie gdy pamięć nie mieści się w przestrzeni 0-64KB
  2. czas przełączania zależy od konfiguracji systemu i tego czy wtrąci się przerwanie zegarowe w środek przełączania kontekstu

Bibliografia

[edytuj | edytuj kod]

Linki zewnętrzne

[edytuj | edytuj kod]