original in en Ismael Ripoll
en to tr Berfin Kalay
1998 başlarında dağıtımı başlanan Linux üzerine kurulu KURT,yumuşak bir gerçek zamanlı işletim sistemidir.Örnek vermek gerekirse;çizelgeleyici istenilen program yürütme zamanlarını sağlamaya çalışırken,herhangi bir görevin zamanından önce sonlanması gerçek bir trajediye sebep olmaz.RT-Linux görevlerinin aksine KURT gerçek zamanlı görevleri,Linux'un faydalarının avantajını taşıyabilirler.Çekirdeğe yapılan ilaveler ve değişiklikler şöyledir:
Gerçek zaman görevleri dinamik olarak yüklenmiş modüllerdir.
KURT'un en karakteristik özelliklerinden birisi sahip olduğu "çizelgeleme kuralları"dır.Bir çevrimsel çizelge yürütülmesi için bir karar alınır.Bu tür çizelgeler,işlem zamanı,yürütme görevi, görev süresi vb. gibi zamana göre programlanmış tüm eylemleri içeren,plan olarak adlandırılmış bir tablo kullanırlar.Bu tablo,sistemin tasarım aşamasında oluşturulur.Daha sonra,çalışma süresi boyunca, çizelgeleyicinin tek görevi tabloyu okuyup,talimatları takip etmektir.Tablonun sonuna ulaşıldığında çizelgeleyici başa döner ve görevleri yerine getirme işini tamamlar.Bu tip çizelgenin pek çok avantajları vardır:
Yürütülmesi kolaydır
Etkilidir.
Bir plan oluşturulduktan sonra sistemin fizibilitesi hızlı bir şekilde belirlenir.
Asıl zorluk planın kendisini oluşturmaktır.Bundan başka görev paremetrelerinden herhangi biri yeniden düzenlendiğinde planın yeniden oluşturulması gerekir.Ayrıca hafızada çok yer kaplar.
Belki birçokları gerçek zaman tekniklerinin yalnızca NASAda veya füzelerde kullanıldığını düşünüyorlar.Birkaç yıl öncesine kadar bu düşünce yanlış sayılmazdı,ancak günümüzde durum oldukça değişmiştir ve bilişim sistemlerinin,elektroniğin günlük yaşamda kullanımındaki artışa paralel olarak hızla değişmektedir.Gerçek zamanlı uygulamalar günlük hayatımızda telekomünükasyon ve multimedya alanlarında yer alır.Örneğin bilgisayarımızın hard diskinde kayıtlı bir ses dosyasını çalmasını istediğimizde,bir programın sürekli olarak dosyayı okuması,açması ve verileri ses kartına göndermesi gerekir.Eğer aynı anda başka bir uygulama çalışır durumda ise,işlemci bu diğer görevleri yürütürken seste periodik kesilmeler oluşur.Örneğin eğer müzik dinlemek yerine sistemimize video kaydı yapıyorsak;sonuç ara ara donan görüntüye eşlik eden ve görüntüyle eşzamanlı olmayan seslendirme olur.Bu tip sistemler soft Real-Time olarak bilinir.
RT-Linux uygulamaları normal gerçek zaman uygulamalarının ötesindedir.RT-Linux ile MSDOS da olduğu gibi PC nin tüm kontrolü elimizdedir( PC diyorum,çünkü henüz RT-Linux'un başka herhangi bir yapıda uygulaması yok.)Bir gerçek zamanlı görev boyunca,PCnin tüm portlarına ulaşım mümkündür.
RT-Linux'u anlamak ve kullanabilmek için Linux'un dinamik olarak yüklenebilir modüllerini bilmek gerekir.Matt Welsh modülleri içeren her sürüm hakkında detaylı anlatımı olan bir makale yazmıştır.
Pek çok UNIX uygulamasında, donanıma erişim için tek yol bazı özel dosyalardan ve donanım parçalarının sürücülerinin kurulu olmasından geçer.Parça sürücülerinin nasıl yazılacağını anlatan pek çok kitap bulunsa da,sisteme sürücüyü dahil etmek için yazılması gereken nümerik fonksiyonlar dolayısıyla,bu uzun ve büyük oranda sıkıcı bir iştir.
Modüllerçalışma zamanı içinde eklenebilen ve çıkartılabilen "işletim sistemi parçalarıdır" Pek çok kaynak dosyanın derlenmesiyle bir program oluşturmada önce her dosya ayrı ayrı derlenerek obje dosyasına dönüştürülür,daha sonra tüm bu dosyalar çalıştırılabilir tek bir dosya oluşturmak için birleştirilir. main fonksiyonunu içeren obje dosyasının çalışabilir olduğunu ve işletim sisteminin geri kalan obje dosyalarını hafızada tutabildiğini ve yalnızca gerekli olduğunda biraraya getirdiğini farzedelim.Kernel(çekirdek) bunu tekbaşına yapabilir.Linux çalıştırıldığında,yalnızca çalıştırılabilir vmlinuz hafızaya yüklenir.İçeriğinde gerekli kernelin elemanları vardır,daha sonra çalışma süresince modülün herhangi bir ihtiyacını seçerek yükleyebilir.
Modüller,çekirdeğin derlenmesi sırasında çağırılması gereken,Linux çekirdeğindeki opsiyonel özelliklerdir.Bildiğim tüm Linux dağıtımlarının çekirdekleri, modül opsiyonları aktif olarak derlenir.
Ayrıca sistemi yeniden derlemeye veya yeniden çalıştırmaya gerek olmaksızın yeni modüller oluşturmak ve yüklemek mümkündür.
Bir modül yüklendiğinde,işletim sisteminin bir parçasını oluşturur:
Bütün fonksiyonları kullanabilir,bütün değişkenlere ve çekirdek yapılarına erişebilir.
Modül kodu işlemcinin en üst öncelik seviyesi ile çalışır.i386 yapısında,tüm giriş-çıkış erişim tiplerine sahip olabilmesinin ve özel komutları çalıştırabilmesinin bir sonucu olarak "ring level 0" seviyesinde çalıştırılır.
Hem program hem de veri için sayfalama yapmanın mümkün olmadığı fiziksel hafıza kullanılır.Böylelikle modülün çalışma süresince bir sayfa hatası oluşmaz.
Gördüğümüz gibi,dinamik olarak yüklenmiş bir modül bir gerçek zamanlı programın bazı özelliklerine sahiptir:Sayfa hataları sonucu oluşan gecikmeleri önler ve tüm donanım kaynaklarına erişimi vardır.
Bir modül C kodlarıyla yapılandırılır.Aşağıda çok küçük bir modül örneği görülmektedir(Aşağıdaki komutları icra edebilmek için üst kullanıcı(süper user) olmak gerekir):
example1.c
#define MODULE #include <linux/module.h> #include <linux/cons.h> static int output=1; int init_module(void) { printk("Output= %d\n",output); return 0; } void cleanup_module(void){ printk("Adiós, Bye, Chao, Ovuar, \n"); }
Derlemek için şu parametreler kullanılır:
# gcc -I /usr/src/linux/include/linux -O2 -Wall -D__KERNEL__ -c example1.c-c opsiyonu gcc ye obje dosyasını oluşturduktan sonra durmasını ve bağlantı safhasını atlamasını söyler.Sonuç example1.o şeklinde isimlendirilmiş bir dosyadır.
Çekirdek standart çıkıştan yoksundur,dolayısıyla printf() fonksiyonunu kullanamayız.Bunun yerine,printf gibi çalışan,fark olarak çıktıyı çekirdeğin tamponuna gönderen printk()fonksiyonu vardır.Bu çekirdek tampon belleğinde sistem kapanırken oluşan mesajlar saklanır ki bu mesajlar sistem çalıştırıldığında gördüğümüz mesajlardır.İstediğimiz an tamponun içeriğini görüntüleyebiliriz,bunun için dmseg komutunu kullanabilir veya doğrudan /prog/kmsg dosyasına göz atabiliriz.
Burada main() fonksiyonunun bulunmadığına, yerine hiç bir parametresi bulunmayan init_module() fonksiyonunu bulacağımıza dikkat edelim. cleanup_module bir modülü boşlatmadan önce çağırdığımız son fonksiyondur. Modül yüklemesi insmod komutu ile gerçekleşir.
# insmod example1.o
Bu şekilde example1 modülünü kurduk ve init_module() fonksiyonunu çalıştırdık. Sonuçları görmek için şu komutu girin:
# dmesg | tail -1 Output= 1
lsmod komutu çekirdekte elektriksel olarak yüklü modülleri listeler:
# lsmod Module Pages Used by: example1 1 0 sb 6 1 uart401 2 [sb] 1 sound 16 [sb uart401] 0 (autoclean)
Ve bir modülü silmek için rmmod komutunu kullanırız.
# rmmod example1 # dmesg | tail -2 Output= 1 Adiós, Bye, Chao, Orvua,
dmesg komutunun çıktısı bize cleanup_module()fonksiyonunu çalıştığını gösterir. ;
Tek bilmemiz gereken bir modüle paametreleri nasıl aayacağımızdır. Bundan şaşırıcı düzeyde kolay olan başka bir şey yoktur. Örneğin:
# insmod ejemplo1.o output=4 # dmesg | tail -3 Output= 1 Adíos, Bye, Chao, Orvua, Output= 4
Şimdi modüllerle ilgili bilmemiz gereken her şeyi biliyoruz.Gerçek Zamanlı Linux'a geri dönelim.
Öncelikle hatırlamamız gereken,RT-Linux'u kullanmak için,Linux çekirdeğini Gerçek Zamanlı modülleri destekleyecek şekilde hazırlamış olmamızdır. bir önceki makalede bu işlemi anlatmıştık.
RT-Linux kullanımı için iki yol vardır:
Belirlenmiş öncelikler üzerine kurulu bir çizelgeleyiciye sahip klasik bir Gerçek ZamanSistemi olarak.
DOS kullanımına yakın bir kullanım olarak.
Şimdi,RT-Linux'u sabit öncelikli bir sistem olarak nasıl kullanmak gerektiği üzerinde duracağım.Birazdan göreceğimiz örnek işe yarar birşey yapmamakta,yalnızca bir gerçek zaman görevini ayarlamaktadır:
example2.c#define MODULE #include <linux/module.h> #include <linux/kernel.h> #include <linux/version.h> #include <linux/rt_sched.h> RT_TASK task; void fun(int computo) { int loop,x,limit; limit = 10; while(1){ for (loop=0; loop<computo; loop++) for (x=1; x<limit; x++); rt_task_wait(); } } int init_module(void) { RTIME now = rt_get_time(); rt_task_init(&task,fun, 50 , 3000, 1); rt_task_make_periodic(&task, now+(RTIME)(RT_TICKS_PER_SEC*4000)/1000000, (RTIME)(RT_TICKS_PER_SEC * 100)/1000000); return 0; } void cleanup_module(void){ rt_task_delete(&task); }
Bir kere daha bu örneği aşağıdaki komutla derleyelim:
# gcc -I /usr/src/linux/include/linux -O2 -Wall -D__KERNEL__ -D__RT__ -c example2.cProgram bir modül olduğundan,giriş noktası init_module()fonksiyonudur.İlk yaptığı akım zamanını okumak ve lokal bir değişkene atamaktır;rt_get_time() fonksiyonu yüklenme zamanından beri geçen zamanda RT_TICKS_PER_SEC değerini döndürür. rt_task_init()ile'görev' yapılandırılır ama henüz başlatılmaz.Son olarak oluşturulmuş görevin ana programı fun(), ikinci paremetredir.Onu takip eden paremetre çalıştırılması sırasında yeni göreve atanacak olan veri değeridir.Dikkat edilmesi gereken nokta fun() fonksiyonunun int paremetre kullandığıdır.Bir sonraki paremetre görev yığınının boyutudur.Her görev kendi yürütüm izleğine sahip olduğundan,her biri kendisine ait yığına ihtiyaç duyar.Son paremetre öncelik parametresidir.Böylelikle,sistemde tek bir görevle,istediğimiz değeri ayarlayabiliriz.
rt_task_make_periodic() komutu görevi periyodik bir göreve dönüştürür.Bu durumda görev iki zaman değerine sahip olur,ilki görevin ilk olarak etkinleştirileceği mutlak zamandaki andır,diğeri aktivasyonlar arasındaki periyottur.
Gerçek zamanlı görev(fun() fonksiyonu ),yalnızca iki işlem içeren içeren sonsuz bir döngüdür:sadece zaman harcar ve sonra rt_task_wait() fonksiyonunu çağıran bir döngü..rt_task_wait,kendisini bir sonraki aktivasyon zamanına kadar çağıran görevin yürütülmesini geçici olarak durduran bir fonksiyondur.Program rt_task_wait satırından hemen sonra çalışmaya devam eder.Okuyucu şunu iyi anlamalıdır ki görev her aktivasyon zamanında çalışmaya en baştan başlamaz,bunun yerine görev,çalışmasını kendi kendine geçici olarak durdurmalı ve bir sonraki aktivasyonu beklemelidir.Bu da ilk çağırıldığında yalnızca birkaç başlatım yürütülen bir görev yazmayı olanaklı kılar.
example2 yi çalıştırmak için,rt_prio_sched modülünü kurmalıyız,çünkü programımızı rt_task_make_periodic(), rt_task_delete() ve rt_task_init() fonksiyonlarına ihtiyacı var. rt_get_time() fonksiyonu modülde bulunmaz fakat Linux çekirdeğinde yerleşiktir ve bu yüzden bu fonksiyonu kurmamıza gerek yoktur.
# modprobe rt_prio_sched # insmod ./example2.o
Verilmiş rt_prio_sched bir sistem modülüdür.Linux çekirdeğinin derlenmesi sırasında yaratılır ve /var/modules/2.0.33/ dizinine kopyalanır.Modülleri yüklemede daha kolay bir araç olduğundan,modprobe komutunu kullanırız.
Eğer her şey yolunda gittiyse,lsmod komutu ile her iki modülün de doğru biçimde yüklendiğini göreceğiz.
Bu noktada okuyucu çalışan bir gerçek zamanlı programa sahiptir.Özel herhangi birşey dikkatinizi çekiyor mu?İşlemci biraz yavaş ise, okuyucu Linux'un herzamankinden daha yavaş çalıştığını farkedecektir.fun() fonksiyonunun iç döngüsündeki iterasyon sayısını arttırmayı deneyebilirsiniz.Bunun için rt_task_init fonksiyonundaki üçüncü parametreyi değiştirmelisiniz.Size ico programını çalıştırarak ne kadar az işlemci zamanı kaldığını değerlendirmenizi tavsiye ederim.Çünkü Gerçek Zamanlı programlar tarafından kullanılan zaman işlemciyi düşük hızda çalışıyormuş gibi etkiler.Linux bütün işlemlerini aynı şekilde işlemesi için daha fazla zamana ihtiyacı olduğuna inanır.Eğer hesap zamanı 100 mikrosaniyeden fazlaysa Linux "kitlenecektir",çünkü Linux arka plan görevidir ve gerçek görev zamanın tamamını almaktadır.Aslında Linux kitlenmez sadece işlemci zamanı yoktur.
RT-Linux tltında iletişim için tek bir yol vardır: Real-Time FIFO.Çalışma şekli UNIX PIPE larınınkine çok benzer. Unix PIPEları yapısı olmayan veri akımıyla sağlanan bir iletişimdir. .FIFO yazma ve okuma operasyonlarının yürütüldüğü sabit büyüklükte bir arabellektir.
FIFOS kullanarak gerçek zamazlı görevler arasında ve normal Linux görevleri arasında inter-haberleşme kurmak mümkündür.
Bir Normal İşlem Bakımından r özel karakter dosyasıdır.Normal olarak Linux'un içermediği /dev/rtf0, /dev/rtfl,vs. dosyaları olarak bulunduklarından aşağıdaki şekilde yaratılmaları gerekir:
# for i in 0 1 2 3; do mknod /dev/rtf$i c 63 $i; doneeğer daha fazla FIFO dosyasına ihtiyaç varsa aynı rtf4,rtf5,.. prosedürü kullanılarak kolaylıkla yaratılabilirler.Özel dosyalar işletim sistemindeki bir işleyiciye arayüz gibi davranırlar,eğer işleyici bulunmuyorsa bu özel dosyaların bir kullanım alanı yoktur.Nitekim ilişkilendirilmiş işleyicinin yokluğunda bu dosyalardan herhangibirini açmak mümkün değildir.
FIFOlar normal dosyalar gibi kullanılırlar(open, read/write, close).Bir normal Linux işleminin bo dosyaları kullanabilmesi için öncelikle bir gerçek zamanlı programın uygun FIFOyu yaratması gerekir.
Bir gerçek zamanlı görev bakımından, FIFOlar özel fonksiyonlar aracılığıyla kullanılırlar:
rt_create(unsigned int fifo, int sise):size boyutunda bir arabellek ile bir FIFO yaratır.Bu andan yokedilme anına kadar /dev/rtf[fifo] tarafından kabul edilen sürücü kullanılabilir.
rt_destroy(unsigned int fifo):Uygun FIFO yokedilir ve hafızası geri kazanılır.
rt_fifo_put(fifo, char *buf, int count): countbitlerini buf arabelleğinden yazmayı dener.FIFOnun arabelleğinde yeterli yer yoksa geri döner.
rt_fifo_get(fifo, char *buf, count): count baytlarını FIFOdan okumayı dener.
Şimdi bu fonksiyonları kullanan bir örnek görelim.Bu örnek RT-Linux dağıtımında yer alan örneklerin küçük bir modifikasyonudur:
example3.c#define MODULE #ünclude <linux/module.h> #include <linux/rt_sched.h> #include <linux/rtf.h> #include <asm/io.h> RT_TASK task; static int filter(int x){ static int oldx; int ret; if (x & 0x80) { x = 382 - x; } ret = x > oldx; oldx = x; return ret; } void fun(int dummy) { char data; char temp; while (1) { if (rtf_get(0, &data, 1) > 0) { data = filter(data); temp = inb(0x61); temp &= 0xfd; temp |= (data & 1) << 1; outb(temp,0x61); } rt_task_wait(); } } int init_module(void){ rtf_create(0, 4000); /* enable counter 2 */ outb_p(inb_p(0x61)|3, 0x61); /* to ensure that the output of the counter is 1 */ outb_p(0xb0, 0x43); outb_p(3, 0x42); outb_p(00, 0x42); rt_task_init(&task, fun, 0 , 3000, 1); rt_task_make_periodic(&task, (RTIME)rt_get_time()+(RTIME)1000LL, (RTIME)(RT_TICKS_PER_SEC / 8192LL)); return 0; } void cleanup_module(void){ rt_task_delete(&task); rtf_destroy(0); }
İkinci örnekte ,rt_prio_sched modülünün hizmetlerini istemiştik, bu defa FIFO nunkileri kullanmak için rt_fifo_new yüklemeliyiz.
8192 Hz frekansında bir periyodik gerçek zamanlı görev yaratılır ve bu görev FIFO 0 dan baytları okur.Eğer birşey bulursa PCnin girişine gönderir.Bir ses dosyasını, /dev/rtf0 üzerine ".au" formatında kopyaladığımız takdirde dinleyebiliriz.PC donanımının sinyali modüle etmek için yalnızca 1 bayt kullanımına izin vermesinin bir sonucu olarak ses kalitesinin berbat olacağını söylemeye gerek yok.Dağıtımıntesting/sound dizini,testler için kullanılanlinux.au dosyasını içerir.
Bu dosyayı derlemek ve çalıştırmak için :
# gcc -I /usr/src/linux/include/linux -O2 -Wall -D__KERNEL__ -D__RT__ -c example3.cÖzel dosyalar dahil herhangi bir dosyanın üzerine yazmak için cat aracının nasıl kullanılacağına dikkat edin.Burada cp komutunu da kullanabilirdik.
Gerçek zaman özelliklerinin röprodiksiyon kalitesini nasıl etkilediğini kıyaslayabilmek için, aynı operasyonu yürüten fakat normal bir Linux kullanıcı işleminden yürüten bir program yazmalıyız.
example4.c#include <unistd.h> #include <asm/io.h> #include <time.h> static int filter(int x){ static int oldx; int ret; if (x & 0x80) x = 382 - x; ret = x > oldx; oldx = x; return ret; } espera(int x){ int v; for (v=0; v<x; v++); } void fun() { char data; char temp; while (1) { if (read(0, &data, 1) > 0) { data = filter(data); temp = inb(0x61); temp &= 0xfd; temp |= (data & 1) << 1; outb(temp,0x61); } espera(3000); } } int main(void){ unsigned char dummy,x; ioperm(0x42, 0x3,1); ioperm(0x61, 0x1,1); dummy= inb(0x61);espera(10); outb(dummy|3, 0x61); outb(0xb0, 0x43);espera(10); outb(3, 0x42);espera(10); outb(00, 0x42); fun(); }
Bu program herhangi normal program gibi derlenebilir:
# gcc -O2 example4.c -o example4
Ve çalıştırmak için:
# cat linux.au | example4
Normal bir Linux programından bilgisayarın donanım girişlerine erişim için,işletim sistemine izin çağrısında bulunmalıyız.Bu hard diske direkt program erişimini önlemek için gerekli ve basit bir koruma ölçütüdür.ioperm çağrısı ,işletim sistemine ,verilmiş bir giriş-çıkış adresleri sırasına erişmek istediğimizi söyler.Sadece root ayrıcalığı ile çalışan programlar böyle bir izni alabilirler.Not etmeye değer bir detay, sesi modüle eden 8192Hz frekansının nasıl oluşturulduğudur.nanodelay isimli milisaniyelik çözünürlüğe sahip bir sistem çağrısınınvarlığına rağmen, bekleme döngüsü kullanan geçici bir saat kullanmalıyız. Döngü, aşağı yukarı, 100Mhz lik pentium üzerinde çalışacak şekilde ayarlanmalıdır.
Şimdi okuyucunun example4'ü ico programıyla test etmesini istiyorum. Şimdi kulağınıza nasıl geliyor?. Gerçek zamanlı ile farkı hissedebiliyormusunuz?Gerçek zaman bir şeye değdi mi?
Bu ikinci makale gerçek zamanlı uygulamaların programlama detayları üzerine konsantre olmuşur. Örnekler çok basit ve prtaik kullanımdan uzaktır. Önümüzdeki makalede daha kullanışlı bir uygulama vereceğim. Tv'nizi linux ile kontrol edebileceksiniz hatta daha da ötesi linuxunuzu uzaktan kumanda ile kontrol edeceksiniz.