Süreçlerarası İletişim

Önceki bölümlerde gördüğümüz örnek program bir gerçek zamanlı süreç olarak bilinen süreçtir. Bir uygulama programının her bir parçası gerçek zamanlı olmak zorunda değildir. Programın sadece hassas zaman kısıtlamaları gerektiren bölümleri bir gerçek zamanlı süreç gibi yazılmalıdır. Diğer bölümleri kullanıcı seviyesinde yazılıp çalıştırılabilir. Kullanıcı seviyesinde çalışan süreçleri yazmak, çalıştırmak ve hatalarını ayıklamak gerçek zamanlı evrelerden çoğunlukla daha kolaydır. Fakat tam bu noktada, kullanıcı seviyesindeki Linux süreçleri ile gerçek zamanlı evreler arasında iletişimi sağlayacak bir yöntem ihtiyacı ortaya çıkar.

Süreçlerarası iletişimin çeşitli yolları vardır. Biz en önemli ve en ortak iletişim yolundan, gerçek zamanlı FIFO'dan bahsedeceğiz.

Gerçek Zamanlı FIFO

Gerçek zamanlı FIFOlar tek yönlü kuyruklardır (First In First Out - ilk giren ilk çıkar). Yani bir süreç FIFOnun bir ucunda veri yazarken diğer süreçler FIFOnun diğer ucundan bilgileri okuyabilir. Genellikle bu süreçlerin bir tanesi gerçek zamanlı evre, diğeri kullanıcı seviyesindeki süreçtir.

Gerçek zamanlı FIFOlar aslında, ana numarası 150 olan karakter aygıtlarıdır (/dev/rtf*). Gerçek zamanlı evreler kullanacakları FIFO'ları belirtmek için bir tamsayı kullanır (örneğin, /dev/rtf2 için 2). FIFOların numaraları için bir sınır vardır. FIFOlarla çalışmak için rtf_create(), rtf_destroy(), rtf_get(), rtf_put() vb işlevler vardır.

Diğer taraftan, Linux kullanıcı süreci gerçek zamanlı FIFOları normal karakter aygıtları gibi görür. Bu yüzden open(), close(), read() ve write() gibi işlevler bu aygıtlarda kullanılabilir.

FIFO Kullanan Bir Uygulama

İlk olarak, PC hoparlöründen müzik çalan (sadece iki notalı) basit bir C programını (dosya adı pcaudio.c olan) göz önüne alalım. Şimdi, nota çalmak için sadece /dev/rtf3 karakter aygıtına yazmamız gerektiğini varsayalım. (Sonra, bir gerçek zamanlı sürecin FIFOdan (/dev/rtf3) okumasını ve PC hoparlörüne göndermesini göreceğiz)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define DELAY 30000

void make_tone1(int fd)
{
        static char buf = 0;
        write (fd, &buf, 1);
}

void make_tone2(int fd)
{
        static char buf = 0xff;
        write (fd, &buf, 1);
}

main()
{
        int i, fd = open ("/dev/rtf3", O_WRONLY);
        while (1)
        {
                for (i=0;i<DELAY;i++);
                make_tone1(fd);
                for (i=0;i<DELAY;i++);
                make_tone2(fd);
        }
}

Şimdi, yukarda görünen program (pcaudio.c) derlenir ve çalıştırılırsa, bir kare dalgaya uygun düzenli pıtırtılar oluşturmalı. Fakat bundan önce '/dev/rtf3'ten okumak için bir modüle ve uygun veriyi PC hoparlörüne göndermeye ihtiyacımız var. Bu gerçek zamanlı programı rtlinux kaynak ağacında (/usr/src/rtlinux/examples/sound/) bulabilirsiniz. sound.o modülünü 'insmod' komutunu kullanarak çekirdeğe ekleyin.

Aygıttan okumak için modülü ekledikten sonra, programımızı artık çalıştırabiliriz ('gcc' kullanarak derleyin) ve sonra oluşan 'a.out'u çalıştırın. Bu şekilde süreç, sistemde başka süreç olmadığı zaman (zamanın tükenmesi) biraz daha düzenli tonlar üretir. Fakat diğer konsolda X sunucusu başlatıldığı zaman tonda sessizlik daha uzun süreli olmaya başlar. Sonunda bir 'find' komutu çalıştırıldığı zaman (/usr dizininde bir dosya için) örnek ses tamamen bozulur. Bunun ardındaki sebep, veriyi gerçek zamanlı olmayan FIFO üstünde yazmamızdır.

Seste herhangi bir karışıklık meydana gelmesin diye biz şimdi bu süreç gerçek zamanlı nasıl çalışır, onu göreceğiz. Önce yukarıdaki programı bir gerçek zamanlı programa dönüştürelim. (Dosya adı rtaudio.c)

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

#define FIFO_NO 3
#define DELAY 30000
pthread_t thread;

void * sound_thread(int fd)
{
        int i;
        static char buf = 0;
        while (1)
        {
                for(i=0; i<DELAY; i++);
                buf = 0xff;
                rtf_put(FIFO_NO, &buf, 1);

                for(i=0;i<DELAY;i++);
                buf = 0x0;
                rtf_put(FIFO_NO, &buf, 1);
        }
        return 0;
}

int init_module(void)
{
        return pthread_create(&thread, NULL, sound_thread, NULL);
}

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

Eğer hala yapmadıysanız sound.o modülünü çekirdeğe ekleyin. Yukarıdaki programı bir Makefile yazarak (daha önce söylediğimiz gibi) derleyin, böylece rtaudio.o modülü üretilir. Bu modülü eklemeden önce birkaç şey daha lazım. Yukarıdaki programın sonsuz döngü içinde çalıştığına dikkat edelim. Evreyi uyutmak ya da sonlandırmak için kodumuz olmadığı için evre çalışmasını durdurmayacaktır. Bu yolla sizin PC hoparlörünüz bu tonu üretmeye devam edecek ve siz başka bir şeyler yapmak için bilgisayarınızı yeniden başlatmak zorunda kalacaksınız.

Bu yüzden evrenin kendi kendine tonlar arasında gecikme yapmayı soran küçük bir kod değişikliği (sadece sound_thread() işlevinde) yapalım.

void * sound_thread(int fd)
{
        static char buf = 0;
        pthread_make_periodic_np (pthread_self(), gethrtime(), 500000000);

        while (1)
        {
                pthread_wait_np();
                buf = (int)buf^0xff;
                rtf_put(FIFO_NO, &buf, 1);
        }
        return 0;

}

Artık 'rmmod' komutu ile modülü yalnızca kaldırarak süreci sonlandırabiliriz.

Burada süreçlerarası iletişim için gerçek zamanlı FIFOların nasıl kullanılacağını gördük. Ayrıca RTLinux'a olan gerçek ihtiyaç yukarıdaki örnekten anlaşılabilir.