A STREAMS driverekben a driver megnyitását, az adatok továbbítását és a
driver lezárását más-más eljárás végzi. Ezeket az eljárásokat a kernel a
neki átadott táblázatok alapján tudja elérni, és amikor végrehajtja
oket, akkor paraméterként átad az eljárásoknak információkat, ami
megkönnyíti a munkájukat. A leggyakrabban használt rutinok és feladatuk
leírása a következo pontok témája.
Általában külön eljárásokat írhatunk a lefelé és a felfelé haladó
streamhez, de írhatunk a két stream által közösen használt rutint is. Ha
valamelyik szolgáltatásra nincs szükség, akkor azt nem kell kódolni (ld.
késobb).
--- - Driver/modul megnyitása (open) - ---
Szintaxis :
int xxopen(queue_ptr,dev,flag,sflag)
queue_t *queue_ptr; /* A read-queuera a pointer */
dev_t dev;
int flag,sflag;
Ez a rutin STREAMS drivereknél a driver megnyitásánál, a STREAMS
moduloknál a modulra vonatkozó I_PUSH
hívásnál lesz
végrehajtva. A hagyományos UNIX device driverekhez hasonlóan ennek az
eljárásnak inicializálási feladatai vannak. A queue_ptr
paraméter az új streamre egy pointer. A dev paraméter a device
numbert tartalmazza, a flag paraméter megegyezik a hagyományos
UNIX device drivereknél használt flag-gel jelölt paraméterrel
( open flagek, ld. oflags az open rendszerhívás paraméterei
között). A dev paraméter mind a major mind a minor device numbert
tartalmazza. Ha szükségünk van ezek közül valamelyikre, akkor az a
major() illetve minor() kernel segédrutinnal (legtöbb helyen ez
egy makro) kinyerheto a dev paraméterbol. Az sflag a stream
megnyitásának speciális jellemzoit tartalmazza. Értéke lehet :
Ha az xcln filet megnyitjuk, aminek a major device numberje egyenlo a clone driver major device numberjével, akkor a clone driver lesz eloször végrehajtva, és (mint egy diszpécser) keres egy üres minor devicet, és ezt adja tovább a driver open rutinnak. A megnyitó rutin egy nulla visszatérési értékkel jelzi, ha nem volt hiba a futása közben, vagy OPENFAIL értékkel térjen vissza, ha a megnyitás eredménytelen volt. Az open és a close rutinok végrehajtásakor a kernel lokkolja a device i-nodeját, így egyszerre csak egy open vagy close rutin lehet aktív major/minor deviceonként. Megjegyzés: Ha a felhasználói programokból megnyitjuk egy STREAMS device driver valamelyik minor device-ját, majd késobb ismét kiadunk egy open rednszerhívást ugyanarra a minor devicera, akkor a második open rendszerhívásnál az open rutin nem lesz újra meghívva.
--- - Driver/modul lezárása (close) - ---
Szintaxis :
xxclose(queue_ptr)
queue_t *queue_ptr; /* Pointer a read queuera */
A rutin a STREAMS driverre vonatkozó close rendszerhívásnál és az
I_POP
ioctl hívásnál lesz végrehajtva. Ezután a felhasználói
program már nem tudja elérni a device drivert (vagy modult). Sikeres
végrehajtás esetén a visszatérési érték: 0
, sikertelen
végrehajtás esetén pedig az errno változóba rakandó érték legyen.
Megjegyzés: a close rutin csak akkor lesz meghívva, amikor
az adott minor devicera vonatkozó legutolsó filet is lezárták.
--- - Üzenet fogadása (put rutin) - ---
Szintaxis :
int xxput(qp,mp)
queue_t *qp;
mblk_t *mp;
Ez az eljárás akkor lesz végrehajtva, amikor a drivernek (vagy modulnak)
adatot kell fogadnia a qp
paraméterében megadott streamrol.
A mp
paraméter a beérkezett üzenetre pointer. Az üzenetet
vagy el kell dobnia, vagy módosítva tovább kell adnia. Ha
továbbadja, akkor vagy egy saját sorába ( putq() függvénnyel), vagy
a streamen levo következo modulnak ( putnext() makróval), vagy
pedig az ellenkezo irányú sorba ( qreply() függvénnyel) adhatja
tovább. Ha egy saját sorába adja tovább, akkor az üzenet még átmegy egy
service rutinon is (ld. késobb). Az üzenettovábbítás általában az
üzenetre mutató pointer továbbadását jelenti.
--- - A service rutin - ---
Szintaxis :
int xxsrv(qp)
queue_t *qp;
A service rutin csak a saját sorára mutató pointert kapja meg
paraméterként. A getq függvénnyel tudja a sorából a következo
üzenetet megszerezni, majd ezután ha tudja, akkor továbbadhatja a
streamen következo modulnak. Ez alapján egy service rutin vázlatos
felépítése a következo lehet :
int xxsrv(qp)
queue_t *qp;
{
/* Lokalis deklaraciok - reentrans kod erdekeben */
mblk_t *mp;
while (mp=getq(qp) != NULL)
{
if (canput(qp->q_next) || (a message magas prioritasu))
{
dolgozd_fel_az_uzenetet();
if (tovabb_kell_adni_az_uzenetet())
{
putnext(qp,mp);
}
} else {
putbq(qp,mp);
return;
}
}
}
Az üzenettípusok értékei úgy vannak kiosztva, hogy azok az üzenetek
alacsony prioritásúak, amelyeknek adatblokkjában a db_type mezo értéke
QPCTL-nél kisebb (a QPCTL makro a saját operációs rendszerünk valamelyik
headerfile-jában van definiálva).
--- - Service rutin vs. put rutin - ---
A service rutin opcionális, csak akkor szükséges, ha a put rutin az
üzenetet nem tudja a beérkezésének "
pillanatában "
rögtön
feldolgozni (mert például a hardware periféria még nem ért el egy
bizonyos belso állapotot) vagy a stream már túl van terhelve és nem fér
bele az üzenet. Minden modulhoz és driverhez meg lehet adni egy low
water mark és egy high water mark értéket. Ez azért jó, mert el
lehet vele érni egy nagyjából egyenletes adatáramlást (nem alakul ki
adatdugó). Ha az üzenetek által lefoglalt byte-ok száma meghaladja
a modulhoz megadott high water mark értéket, akkor egy QFULL flag
be lesz állítva. Ennek a flagnek az állapotát az elotte levo modul a
canput kernelfüggvénnyel lekérdezheti, és ha a flag be van
állítva, akkor normál (alacsony) prioritású üzeneteket már nem adhat
tovább. (Ezeket a saját sorába visszarakhatja a putbq STREAMS
kernel segédfüggvénnyel.) A service rutinra csak akkor jut a vezérlés,
ha az addig üres sorba egy új üzenet került, vagy az alatta következo
modulban elérte az üzenetek által lefoglalt byte-ok száma a low water
markot. Ezen kívül máskor is megkaphatja a vezérlést, de errol saját
magának kell gondoskodnia (a qenable és az enableok STREAMS
kernel segédrutinok segítségével).
--- - Driver ioctl rutin - ---
A hagyományos karakteres UNIX device driverekben egy külön belépési
pont az ioctl hívásokat feldolgozó eljárás. Ezzel szemben a
STREAMS device driverek esetében az ioctl hívásokat többnyire a
stream-fej dolgozza fel, azokból bizonyos típusú üzeneteket generál, ami
le lesz küldve a STREAMS drivernek (vagy modulnak). Az I_STR
hívás például arra utasítja a stream-fejet, hogy egy M_IOCTL
típusú üzenetet küldjön le a streamen. Ekkor az ioctl hívások
feldolgozása az M_IOCTL
típusú üzenetek driveren belüli
feldolgozását jelenti.