RTLinux Programları Yazmak

Modül Yazımına Giriş

Modül nedir, dersek? Bir Linux modülü gcc'nin -c seçeneği ile kullanılması sonucu oluşan nesne dosyasından başka birşey değildir. Bir modül, sıradan bir C dili dosyasının main() işlevi olmaksızın derlenmesiyle oluşur. main() işlevi yerine init_module/cleanup_module işlev çifti vardır:

  • init_module() işlevi, modül çekirdeğe eklenirken çağrılır. Bu işlev başarı halinde 0, başarısızlık halinde negatif değer döndürmelidir.
  • cleanup_module() işlevi, tam modül kaldırılırken çağrılır.

Genellikle, init_module() ya çekirdekle bir şeyler için bir eylemcinin varlığını bildirir ya da bir çekirdek işlevini kendi kodu ile değiştirir (genellikle kod bir şeyler yaptıktan sonra orjinal işlevi çağırır). cleanup_module() işlevinin init_module() işlevinin yaptığını geri aldığı kabul edilir, böylece modül emniyetle kaldırılabilir.

Örneğin, eğer siz module.c diye bir C dosyası yazarsanız (main() işlevi init_module() ve cleanup_module() işlevleriyle değiştirilerek), bu kod,

$ gcc -c {BAZI-SEÇENEKLER} my_module.c

ile bir modüle dönüştürülebilir. Bu komut;

$ insmod module.o

gibi bir 'insmod' komutuyla çekirdeğe eklenebilen module.o isimli bir modül dosyası oluşturur. Benzer biçimde, bu modülü kaldırmak için 'rmmod' komutunu kullanabilirsiniz:

$ rmmod module

RTLinux Evrelerinin Oluşturulması

Bir gerçek zamanlı uygulama genellikle çeşitli evrelerin çalışmalarının birleşimidir. Evreler bir ortak adres uzayını paylaşan hafif süreçlerdir. RTLinux'da, bütün evreler Linux çekirdeğinin adres uzayını paylaşır. Evrelerin kullanmanın avantajı, evreler arasındaki geçişin bağlamsal geçişlere göre oldukça ucuz olmasıdır. Aşağıdaki örnekte görüleceği gibi farklı işlevler kullanarak bir evrenin çalışması üzerinde tam bir denetim kurabiliriz.

Örnek Bir Program

Bir evrenin çalışmasını anlamanın en iyi yolu, bir gerçek zamanlı programı izlemektir. Örneğin, aşağıda görünen program her saniye bir kez çalışacak ve her bir yineleme sırasında 'Merhaba Dunya' yazacak.

Örnek 3.1. hello.c dosyası

#include <rtl.h>
#include <time.h>
#include <pthread.h>

pthread_t evre;

void * evre_kodu(void)
{
        pthread_make_periodic_np(pthread_self(), gethrtime(), 1000000000);

        while (1)
        {
                pthread_wait_np ();
                rtl_printf("Merhaba Dunya\n");
        }

        return 0;
}

int init_module(void)
{
   return pthread_create(&evre, NULL, evre_kodu, NULL);
}

void cleanup_module(void)
{
   pthread_delete_np(evre);
}

Şöyle init_module() ile başlayalım. init_module(), pthread_create() işlevini çağırır. Bu, çağrılan evre ile aynı anda çalışan yeni bir evre oluşturmak içindir. Bu işlev sadece Linux çekirdek evresinden çağrılabilir (init_module() kullanılarak).

int  pthread_create(pthread_t      *evre,
                    pthread_attr_t *attr,
                    void           * (*thread_code)(void *),
                    void           *arg);

Oluşturulan yeni evre pthread.h başlık dosyasında tanımlanan pthread_t türündedir. Bu evre, evre_kodu() işlevini argümanını arg ile aktararak çalıştırır. attr değişkeni yeni evreye uygulanacak evre özniteliklerini belirler. Eğer attr NULL ise, öntanımlı öznitelikler kullanılır.

Bundan dolayı burada, evre_kodu() argümansız çağrılır. evre_kodu üç bileşenden (ilklendirme, çalışma ve sonlandırma) oluşur.

İlkllendirme aşamasında pthread_make_periodic_np() çağrısı yapılır.

int pthread_make_periodic_np(pthread_t evre,
                             hrtime_t  başlatma_anı,
                             hrtime_t  süre);

pthread_make_periodic_np evre'yi çalışmaya hazır olarak imler. Evre başlatma_anı'nda çalışmasına başlayacak ve nanosaniyelerle belirlenmiş süre'yle çalışacaktır.

gethrtime işlevi sistemin başlamasından beri geçen zamanı nanosaniyeler cinsinden döndürür.

hrtime_t gethrtime(void);

Bu zaman asla sıfırlanamaz ya da ayarlanamaz. gethrtime, daima monoton artan değerler verir. hrtime_t türü, 64 bitlik işaretli tamsayı belirtir.

pthread_make_periodic_np() çağrısıyla evre, işlemci zamanlayıcısına bu evreyi bir saniyede bir çalıştırmasını söyler. Bu, evre için ilklendirme bölümünün sonudur.

while() döngüsü, çalışmakta olan gerçek zamanlı evreyi sonraki süre'nin başlamasına kadar beklemeye alacak pthread_wait_np() işlevine bir çağrı ile başlar. Bu evre önceki bir pthread_make_periodic_np çağrısını ile devreye alınır. Evre tekrar çağrılır çağrılmaz, başka bir pthread_wait_np() çağrısıyla karşılaşana kadar while döngüsünde kalanlar çalıştırılır.

Bizim döngüden çıkmamızı sağlayacak bir yol olmadığından bu evre 1Hz'lik sıklıkla çalıştırılmaya devam edecektir. Programı sonlandırmanın tek yolu rmmod komutu ile onu çekirdekten çıkarmaktır. Bu, evreye ayrılan özkaynakları serbest bırakarak evreyi iptal eden pthread_delete_np() işlevini çağıran cleanup_module() işlevini çağıracaktır.