Not 1 : Bu yazıyla ilgili
VxWorks 653 başlıklı yazıya göz atabilirsiniz.
Not 2 :
Windows'ta ARINC 653 Gerçekleştirimi başlıklı yazıya göz atabilirsiniz.
ARINC 653 Nedir ?
ARINC 653 , POSIX standardı gibi , işletim sisteminden bağımsız bir arayüz sağlar. Bu standart ilk olarak 1996 yılında yazılmış. Gerçek zamanlı işletim sistemlerinde kullanılır. Bu standardı kullanan bir uygulamanın bir başka işletim sistemine port edilebileceği söyleniyor. Aşağıdaki
şekilde ARINC 653 katmanı görülebilir.
Bu standart yurt dışında yaygın olarak kullanılsa da, benim bildiğim kadarıyla ülkemizde kullanıldığı ilk milli proje TAI'nin gerçekleştirdiği Erciyes C-130 modernizasyonu.
Standart iki kısımdan oluşuyor.
ARINC 653 Part 1 “Required Services”
Bu kısımda mutlaka olması gereken hizmetler tanımlı. Bunlar
Partition Management
Process Management
Time Management
Inter- Partition and Intra-Partition Communications
Health Monitor Services
ARINC 653 Part 2 “Extended Services”
Bu kısımda olması tavsiye edilen hizmetler tanımlı.
File System Access
Data Logging
Standardın sağladığı API'ye Application Executive (APEX) denilmektedir. Her standartta olduğu gibi (POSIX vs.) APEX te ilk önce type tanımları yaparak başlıyor.Type tanımlamaları örnek için
Pthreads on Microsoft Windows başlıklı yazıya bakılabilir.
APEX standardı ADA veya C tabanlı arayüzler sağlıyor. POSIX'ten farklı olarak type tanımları mat (opaque)
değil. Yani struct'ların içi standart ile tanımlanmış durumda. Bir diğer fark ise APEX ile yaratılan yapıları, yok etmenin imkanı
yok. Gerçek zamanlı işletim sistemlerinde bu yöntem benimsenmiş. Uygulama açılırken gereken kaynağı bir kere alıyor ve bir daha bırakmıyor. Örneğin bir mutex yaratıldıktan sonra silinemiyor.
Bir diğer önemli nokta ise, Buffer, Blackboard, Event, Process, Queuing Port, Sampling Port, Semaphore gibi yapıların "isim" ile yaratılması. Yani hepsi "named" yapılar ve gerek XML gerekse kod içinde isim ile erişilebiliyorlar.
ARINC 653 Aygıt Sürücüler
Aygıt sürücüleri diğer gerçek zamanlı işletim sistemlerinden farklı olarak kesme (interrupt) tabanlı değil, polling tabanlı yazılıyor.
Bölümlenme (Partition) İşlemleri
Bölümlenme bir Unix uygulaması ile aynıymış gibi
düşünülebilir. Sistem tasarımında yeni bir bölümlemenin oluşturulmasında diğer bölümleler ile ne kadar bağımlı olunduğu kuralına dikkat etmek
gerekir.
As was stated in section II, the ARINC 653 standard encourages the distribution of behavior (user functions) among partitions. Communications between partitions are set through the use of APplication EXecutive (APEX) channels which link statically a source partition with a target one. Though partitioning is expected to enhance reusability, portability and scalability, lots of interconnections tend to reduce all these capabilities. The main reason is that it would be less likely that a partition can work without the support of others (that is, the partitions would be strongly coupled), so that the system would act as it were monolithic.
Bölümlenme için önemli parametreler şunlar:
emniyet seviyesi (criticality level), periyodu (period) ve süresi (duration)
A partition is analogous to a Unix process, in the sense that it runs in its own, separate memory space that is not shared with that of other partitions.
Bölümlenme işlemleri şu konuları kapsar: Bölümlenmenin durumunu sorgulama (partition status), bölümlenmenin durumunu atama (partition operating mode).
Major Frame
A major frame is a repeating fixed-length period during which each partition is executed at least
once.
Örnek:
Bir başka
örnekte ise gerekirse zaman dilimleri arasında boşluklar (spare) olabileceği de gösterilmiş.
Burada yazdığına göre iyi tasarlanmış bir sistemde, Major Frame'in süresi bölümlenmelerin en küçük ortak katı olmalıymış.
For a well designed system, the duration of the MTF will correspond to the least common multiple of the partitions’ periods (so that it is a multiple of each individual partition’s period).
SET_PARTITION_MODE
Metodun imzası aşağıdaki gibi.
Bir bölümlenme aşağıdaki durumlardan birinde olabilir. NORMAL,IDLE,COLD_START ve WARM_START.
SET_PARTITION_MODE(
NORMAL)
çağrısı ile partition içi scheduler'ı çalışmaya başlıyor. Bu
noktadan sonra dinamik olarak başka process yaratılamaz. Böylece sistem
kararlı bir hale
gelir.
SET_PARTITION_MODE(
IDLE) çağrısı ile bölümlenme uygulamalarını çalıştırmayı durdurur. Bu çağrıyı bölümlenme içindeki herhangi bir uygulama yapabilir. Eğer bölümlenme IDLE durumuna geçerse, tekrar başlatmanın tek yolu bölümlenmeyi yeniden başlatmaktır.
COLD_START ve WARM_START ise tam olarak ne işe yarar bilmiyorum. Bir hata oluştuğunda bölümlenmeyi tekrar başlatmak için kullanılabilir diye düşünüyorum.
Process İşlemleri
Process ise thread ile aynıymış gibi
düşünülebilir.
ARINC-653 processes are analogous to POSIX threads. (Arguably, the usage of the word ‘process’ in the standard is unconventional, and can be confusing.) A partition may include one or more processes that share time and space resources. Processes have strictly applied priorities – if a process of higher priority than the current process is blocked and becomes able to run, it will preempt the running process immediately. Processes that have equal priority are round-robin scheduled. Memory is shared between all processes within a partition.
Process işlemleri şu konuları kapsar : Process bilgisinin alınması (identifier ve status), yeni process yaratılması, process'in önceliğinin değiştirilmesi, process'in yönetilmesi (suspend/resume, stop/start)
Aşağıda tanımlı olan PROCESS_ATTRIBUTE_TYPE yapısına bakarsak, Posix uygulamalarında bulunan başlatılan thread'e ek veri geçebilmek için bir alan olmadığını görüyoruz. Başlatılan process'e başlama verisi geçebilmenin tek yolu NAME alanına birşeyler yazma ve bunu thread için parse etmek ki bu çok ilkel bir yönteme dönüşüyor.
CREATE_PROCESS
Metodun imzası aşağıdaki gibi.
İlk parametre yaratılması istenen yeni process'in özelliklerini belirtir. İkinci parametre eğer yaratma işlemi başarılıysa yeni process'in numarasıdır. Üçüncü parametre ise metodun döndürdüğü sonuçtur. Çağrı başarılı ise NO_ERROR dönmesi gerekir. Hata değerleri aşağıda.
Buradan PROCESS_ATTRIBUTE_TYPE yapısı var.
ENTRY_POINT
Process'in başlama metodunu belirtir. Metodun imzası şöyle:
typedef void (* SYSTEM_ADDRESS_TYPE);
Burada dikkat edilmesi gereken nokta, normalde function pointer şöyle tanımlanır.
[return type] (*[name])([argument list]).
Örnek:
int (*x)();
// pointer to a function that returns an int
Yukarıdaki metod imzası ise function pointer gibi
tanımlanmıyor çünkü boş bile olsa () parantezleri eksik ancak yine de bir şekilde çalışıyor.
Bir function parametre olarak geçilirse, aynı array'ler gibi pointer olarak algılanır.Sebebi ise function pointer
decay. Dolayısıyla x.ENTRY_POINT = function çağrısı için = işaratinden sonra ampersand koyabiliriz veya koymayabiliriz. Her ikisi de aynı.
Örnek:
Yani void dönen ve parametresi olmayan bir metod. Bu alıştığımız POSIX thread başlama metodlarından farklı. POSIX'te void* dönen ve void * parametresi alan bir metod kullanılıyor.
STACK_SIZE
Process için kaç byte büyüklüğünde stack ayrılacağını gösterir.
BASE_PRIORITY
Bu alanın alabileceği değer platformdan platforma değişmektedir. Küçük sayır en düşük, büyük sayı ise en yüksek önceliği gösteriyor. MIN_PRIORITY_VALUE ve MAX_PRIORITY_VALUE değerleri alt ve üst sınırları gösterir.
PERIOD
Process'in kaç saniyede bir tekrar uyandırılacağını belirtir. Eğer bu değer 0 ise bu uygulama periyodik
değildir. Emin olmamakla beraber Eğer INIFITE_TIME_VALUE verilirse, process'in periodik olmaması
sağlanır. Aperiodik task'ın zaman süresi olmadığı için,
sürekli yaşayan böyle bir task'ı durdurmanın tek yolu, bir kaynak (resource) üzerinde bloke ettirmektir.
TIME_CAPACITY
En uzun olabilecek çalışma (
Worst-case execution) süresini belirtir. Bu sürenin tanımlanması WCE analizinin yapılmasını kolaylaştırır. Aşağıdaki şekilde tahmin edilen ve gerçekleşen WCE sürelerinin farklı olabileceği görülebilir. İşlemcinin daha verimli kullanılabilmesi için, tahmini WCE değerinin aşağıa çekilmesi gerekir.
Eğer process işini verilen süre içinde bitiremezse, deadline action
çağırılır. Çağırmanın sonucu aşağıda. Bu alan PERIOD alanının değerinden büyük olamaz. Eğer INIFITE_TIME_VALUE verilirse sanırım deadline tanımlanmamış anlamına geliyor. Bu da process'in periodik olmaması
demek.
DEADLINE
SOFT veye HARD olarak verilebiliyor.
typedef enum { SOFT = 0, HARD = 1 } DEADLINE_TYPE;
SOFT deadline, sadece hatayı kayıt eder. HARD deadline ise WARM_START'a sebep
olur.
Bu çağrı ile bir thread başlatılıyor.
Örnek:
Aşağıdaki şekilde daha görsel bir gösterim var.
CREATE_ERROR_HANDLER
Metodun imzası aşağıdaki gibi.
Bu task'ın deadline'ı yoktur. Örnek için VxWorks 653 başlıklı yazıya göz atabilirsiniz.
Bu task'a işletim sistemi tarafından en yüksek öncelik verilir.
START
Process yaratıldıktan sonra hemen başlamıyor. START veya DELAYED_START metodlarından birini çağırmak lazım. Metodları çağırırken ilk parametre olarak CREATE_PROCESS ile elde ettiğimiz numarayı kullanıyoruz. DELAYED_START belli bir süre bekledikten sonra process'i başlatmak için kullanılıyor.
Zaman İşlemleri (Time management)
Zaman işlemleri şu konuları kapsar: timed wait, periodic wait, replenishment (bitiş süresinin ertelenmesi) ve sistem saatinin sorgulanması.
GET_TIME
Konuyla ilgili
Hassas Süre Ölçümü ve API başlıklı yazıya göz atabilirsiniz.
TIMED_WAIT
Sleep ile aynı işlevi görür. Dikkat edilmesi gereken nokta, her sleep işleminde olduğu gibi verilen süre kadar değil sysClkRateGet (sistem clock) metodunun yukarı yuvarlanmış hali süre bekler. Uyuma işlemi bittikten sonra, task işletim sistemi tarafından "Ready" haline getirilir ancak çalıştırılması garanti değildir.
Bölümlenmeler Arası (Interpartition) Yapılar
Buraya taşıdım.
Bölümlenme İçi (Intrapartition) Yapılar
Buffer
Bir çeşit FIFO kuyruk.
CREATE_BUFFER : Yeni bir kuyruk yaratır.
SEND_BUFFER : Kuyruğa yeni bir eleman ekler.
Aşağıdaki şekilde aynı bölümlenme içindeki uygulamaların Buffer aracılığıyla haberleşebildikleri görülebilir.
Blackboard
Tek bir element alıyor. Her güncelleme işlemi bir önceki bilginin üzerine yazar.
CREATE_BLACKBOARD : Yeni bir blackboard yaratır
DISPLAY_BLACKBOARD : Tahtadaki tek elemanı günceller.
Semaphore
Semaphore kullanırken "Priority Inversion" problemine dikkat etmek
lazım. Problem düşük önceliğe sahip uygulamanın, daha yüksek önceliğe sahip uygulamayı semaphore'a sahip olmak için bekletmesinden kaynaklanıyor. Semaphore'un mümkün olduğunca eşit öncelikteki uygulamalar arasında kullanılması tavsiye edilmiş.
Health Monitoring
Health monitoring için kullanılan process'ler en yüksek ve değiştirilemez önceliğe sahiptirler. Preemptible olmadıkları için hataları işlerken başka bir uygulama tarafından engellenemezler.
ARINC 653 ve XML
ARINC 653 bir çok ayarın XML ile yapılmasını istiyor. XML yapısı aşağıdaki farklı renklerde gösterilen başlıklardan
oluşuyor. Bunlar <Partition>, <Schedules> ve <HealthMonitoring> başlıkları. Maalesef XML'de tanımlanan özellikleri kod içinde sorgulamak için API
mevcut değil.
XML derlenince Module OS içinde kaynaklar ayrılıyor. Daha sonra APEX API çağrıları ile
CREATE_XXX şeklinde bir çağrı yapılarak, istenilen kaynağın ismi verilir veModule OS'taki yapıya direkt erişmek için kullanılan bir ID alınır. Yani eşleşme için XML'deki kaynak ismi ile CREATE_XXX çağrısına verilen kaynak ismi
aynı olmak zorunda.
APEX ve Real-Time olmayan İşletim Sistemleri Arasındaki Farklar
APEX ile bir eş zamanlılık veri yapısı üzerinden bekleme yaparken, bekleyen threadlerden hangisinin uyandırılacağını belirtme imkanı var. Seçenekler, Priority veya FIFO.
Ancak Windows ve Unix ailesinde bu tür seçenekler
net olarak mevcut değil.
Posix Eşzamanlılık Yapıları başlıklı yazıda, Linux'ta bekleme yapan threadlerin önceliğine göre uyandırıldığı yazılı. Ancak Posix'te standartta bu şekilde olmasını gerektiren bir zorunluluk yok.
Yazılımı geliştirirken geliştirme ortamı Windows ise, hedef ortamda olmayan Windows'a mahsus bazı kodları kullanmak için aşağıdaki macro bloku kullanılabilir.
#
if defined _WIN32
//Windows'a mahsus kod
#
endif
ARINC 653 ve Dinamik Hafıza Kullanımı
Dinamik hafıza kullanımını engellemek için Array tabanlı bazı veri yapıları aşağıda.
Array Tabanlı Fabrika Örüntüsü
Aşağıdaki
örnekte Fabrika (Factory) örüntüsü gösteriliyor. Nesneler bir dizi içinden çekiliyorlar. Örnekte fabrika son nesneyi de üretince, artık NULL döndürüyor. Ancak bir çok sistemde, nesnenin işinin bittiği farz edilip, sayacın tekrar başa dönecek şekilde kullanıldığını da gördüm.
Array tabanlı Dequeue
Başa ve sonra ekleme/çıkarma işlemlerini O(1)'de yapabilen, sınırlı kapasitesi olan array tabanlı dequeue örneği. Diğer ismiyle Circular Buffer. Bu veri yapısında head ve tail sadece kuyruk boş iken aynı indeksi gösterirler. Kuyruk tam dolu iken tail head'in bir mantıksal olarak bir arkasındadır.
Enqueue işleminde m_Size değişkenini tutmak istemiyorsak, tail bir artırılınca, head'den farklı ise halen yer vardır.
Dequeue işleminde head != tail ise halen okunacak elaman vardır diye de kodlanabilirdi.
class Queue{
Object** m_pBuffer;
uint16_t m_Capacity,m_Head,m_Tail,m_Size;
};
Queue::Queue(){
m_ pBuffer =
NULL;
m_Head =
NULL;
m_Tail =
NULL;
m_Size = 0;
m_Capacity= 0;
}
void Queue::SetCapacity(
uint16_t capacity){
m_pBuffer =
new Object*[capacity];
memset (m_pBuffer,0,
sizeof(Object*) * capacity);
//Reset array
m_Head = m_Tail = m_Size = 0;
m_Capacity = capacity;
}
Object* Queue::Dequeue (){
Object* pResult =
NULL;
if (m_Size > 0) {
//If not empty
pResult = m_pBuffer [ m_Head ];
m_Head ++;
m_Size --;
if ( m _Head == m_Capacity ) {
//Rollover
m_Head = 0;
}
}
return pResult;
}
Object* Queue:Enqueue (
void* ptr){
bool result =
false;
if (m_Size < m_Capacity){
//If has space
m_pBuffer [ m_Tail ] = ptr;
m_Tail ++;
m_Size ++;
if (m_Tail == m_Capacity) {
//Rollover
m_Tail = 0;
}
result =
true;
}
return result;
}
Array Tabanlı Kuyruk
Bu veri yapısında, ortadan eleman çıkartmak mümkün. Bu durumda ortada boşluk oluşuyor. Boşluğu gidermek için ya silinenen indeksten sonraki herşeyi memmove ile bir öne taşımak lazım (defragmentation, bu durum std::vector kullanımına benziyor) ya da boşlukları saklayan bir ikinci veri yapısı (örneğin yukarıdaki dequeue gibi) kullanarak O(1) zamanda boşluğa erişim sağlayabilmek gerekiyor.
İkinci kullanım şeklinde veri herhangi bir özelliğe göre dizilmez, tüm verilerin bir küme şeklinde sıralamaya bakılmaksızın işlendiği farz edilir.
ARINC 653 ve Mimari
Gömülü mimarilerde genellikle aşağıdakine benzer mimarisel katmanlar
bulunur.
Hardware Abstraction Layer
Device Driver Layer
RTOS layer
Application Layer
ARINC 653 ve Dosya Sistemi
ARINC 653 Required Services dosya sistemi ile ilgili hiç bir API tanımlamıyor. Dolayısıyla bir çok işletim sistemi sadece temel hizmetleri saladığı için dosya sistemine erişim kodları genellikle, native API kulllanılarak yapılıyor. Loglama gibi hizmetleri ayrı bir bölümlenme üzerinden yönetmek çok kullanılan bir yaklaşım.
ARINC 653 ve Scheduling
Konuyu
ARINC 653 Scheduler başlıklı yazıya taşıdım.
Tübitak ve Gerçek Zamanlı İşletim Sistemi (GIS)
Tübitak BİLGEM de
GIS adını verdiği ve ARINC 653'ü destekleyen bir işletim sistemi geliştirdi. Gazetelerde
yazanın aksine, anladığım kadarıyla bu işletim sistemi henüz bir projede kullanılmış değil.
Bu işletim sistemi, ek olarak POSIX (PSE51, PSE52, PSE53) standartlarını da destekliyor. Aşağıdaki şekilde bu standartların birbirleri ile ilgisini görebilirsiniz.
Burada yazdığına göre PSE51 287 API'den oluşuyor. PSE52 626 ve PSE53 ise 754 API'ye sahip. GIS'in tüm bu API'leri desteklediği yazılmış. Ancak her ne olursa olsun ARINC 653'e kıyasla çok fazla API var.
VxWorks 6.4 PSE52 uyumluluk sertifikasını 2006 senesinde
aldı. GIS'in sertifikası varmı bilmiyorum.
PSE51'in kapsamı aşağıdaki
şekide görülebilir.
threads, fixed-priority schedul-ing, mutexes with priority inheritance, condition variables, semaphores, timing services including CPU-time clocks, simple device I/O, signals, and memory management.
Aralarındaki temel farkları gösteren bir şekli ise
buradan aldım.
GIS ile ilgili gazete haberi de
burada.
Not : Yazının ilk halinde şöyle yazmıştım. Ancak gelen uyarı üzerine aşağıdaki gibi düzelttim.
GIS'in teknik şu anda sadece 2 işlemciyi destekliyor.
GIS şu anda sadece Freescale MPC74xx işlemcilerde çalışıyor.
Freescale 2004 yılında Motorola'dan ayrılan bir firma. Dünyanın en büyük ticari PowerPC işlemci üreticisi. Board
olarak da sadece Curtiss-Wright'ın DY4-181 board'unda çalisabiliyor. VxWorks 653 ise çok daha fazla işlemciyi
destekliyor.
Aşağıdaki mpc7448'in karşılaştırmasını
görebilirsiniz. Tablodaki MIPS (Million Instructions per second) anlamına
geliyor.
Bu İşletim Sistemi Uzayda Kullanılabilir mi ?
Uzayda kullanılan işlemciler radyasyona dayanıklı olmak zorunda. COTS işlemciler bu isteri karşılamıyor. Dolayısıyla ya mevcut bir işlemciyi radyasyona dayanıklı hale getirmek, ya da yeni bir işlemci tasarlamak gerekiyor. Örneğin
RAD 750 PowerPC 750 tabanlı bir işlemci. İşletim sistemi de haliyle bu işlemci ile çalışabilmeli. Avrupada uzay alanında genellikle
PikeOS veya
RTEMS kullanılıyor. GIS böyle bir işlemciyi desteklemediği müddetçe uzayda kullanılamaz.