Az ebben a fejezetben ismertetett kernel rutinokat kizárólag STREAMS device driverekben használjuk. Részben azért, mert csak a STREAMS queuekon tudunk velük dolgozni, részben pedig azért, hogy STREAMS driverjeink és moduljaink hordozhatóak legyenek.
--- - allocb - lefoglal egy üzenetblokkot - ---
struct msgb *
allocb(size)
register int size;
Ez a függvény lefoglal egy üzenetblokkot a STREAMS adatterületen,
amelynek a mérete legalább size byte. Az üzenet típusa
M_DATA
lesz (ezt a programban késobb meg lehet változtatni). Ha
nincs elég memória, akkor az eredmény egy NULL
pointer.
--- - bufcall - hívj meg egy eljárást, ha lesz szabad memória - ---
int bufcall(size, func, arg)
int size;
void (*func)();
long arg;
Ezzel az eljárással lehet kérni a kerneltol például egy sikertelen
allocb() hívás után, hogy ha felszabadul egy legalább size méretu
memóriaterület (STREAMS üzenetek számára), akkor hívja meg a func
paraméterben megadott függvényt arg paraméterrel (ez a
(*func)(arg); függvényhívást jelenti majd). Ha a kernel a
kérésünket tudomásul vette, akkor a függvény visszatérési értéke 1 lesz,
ha ezt a kérésünket visszautasította, akkor 0 lesz a függvény
visszatérési értéke.
FONTOS: Ha a megadott eljárást a kernel késobb majd meghívja,
akkor sem lesz garantálva az, hogy az allocb() hívással tudunk egy
megadott méretu területet lefoglalni, ugyanis a kernelben másoknak is
szükségük lehet memóriára, és lehet például az, hogy az épp felszabadult
memóriát egy nagyobb prioritású driver lefoglalja elolünk.
Megjegyzés: nagyon gondoljuk meg, hogy mikor használjuk ezt
a kernel rutint, mert ezt a hívási igényt a Release 3.2 UNIX
rendszerekben még nem tudjuk visszamondani. A veszély abban van, hogy
eloállhat az a helyzet, hogy egy STREAMS deviceot már lezártunk, esetleg
a queueja már más devicenak le lett foglalva, és csak ezután lesz
valamikor meghívva a megadott függvény ...
Ezt a hiányosságot az ATT is észrevette, ezért a Release 4.0 UNIX
rendszerben már van az unbufcall() kernel rutin, amellyel egy
korábban bejegyzett és a kernel által elfogadott bufcall() hívás
hatástalanítható.
--- - canput - van-e elég hely a streamben - ---
int canput(q)
register queue_t *q;
Ez a függvény ellenorzi, hogy van-e még hely a q message queueban.
Ha a q queuenak nincs service rutinja, akkor a canput()
függvény megkeresi az adott streamen soron következo legelso olyan
modult, amelynek van service rutinja. (Ha nem talál ilyen modult, akkor
a keresés a stream végén fejezodik be.) Végül ha még fér valami a
q queueba, akkor a függvény visszatérési értéke: 1 - ekkor lehet újabb
üzenetet rakni a queuera, ha a queue betelt, akkor pedig 0 a
visszatérési érték, és ekkor a hívó blokkolva lesz. (A blokkolás azt
jelenti, hogy nem kerül rá a futásra kész service folyamatok listájára.)
--- - enableok - egy eddig inaktiv queue aktivizálása - ---
void enableok(q)
queue_t *q;
A feladata egy korábban kiadott noenable() függvény
hatástalanítása, ami arra utasította a task schedulert, hogy a q
queuet iktassa ki. (Ez nem jelenti azt, hogy a qenable() kernel
függvényhez hasonlóan a sor service rutinja egybol végre is lesz
hajtva!)
--- - flushq - flush muvelet egy queuen - ---
void flushq(q,flag)
register queue_t *q;
int flag;
Ez a függvény töröl minden messaget a megadott q queueból, és
felszabadítja az üzenetek által lefoglalt területet a freemsg()
függvénnyel. A flag paraméter értéke, és ezek hatása (ld.
<sys/stream.h>
include filet) :
M_DATA
, M_PROTO
,
M_PCPROTO
és az M_DELAY
üzeneteket dobja el, a többit
meghagyja.
--- - freeb - egy darab üzenetblokk felszámolása - ---
void freeb(bp)
register struct msgb *bp;
A freeb függvény felszabadítja a bp pointer által mutatott
üzenetblokk által lefoglalt memóriaterületet, a hozzá tartozó
adatblokkal együtt. (Ha a hozzá tartozó az adatblokk db_ref
részének értéke 1-nél nagyobb, akkor csak ez a számláló fog csökkenni, a
lefoglalt adatterület nem lesz felszabadítva.)
--- - freemsg - egy teljes üzenet felszámolása - ---
void freemsg(bp)
register mblk_t *bp;
Végigmegy a megadott message minden egyes üzenetblokkján, és
felszabadítja (ha lehet) a message által lefoglalt teljes
memóriaterületet. Ha ez nem lehet (mert az adatblokk db_ref
részének értéke 1-nél nagyobb), akkor ez a számláló eggyel csökkenni
fog. (A freemsg() függvény végigmegy a message minden egyes
blokkján, és minden egyes blokkot felszabadít a freeb()
segítségével.)
--- - getmid - modul id. lekérdezése - ---
ushort getmid(name)
char *name;
A függvény eredménye a megadott nevu modul modul azonosító száma. (Ha
nincs ilyen modul, akkor az eredmény: 0
).
--- - getq - következo message leszedése a queueról - ---
mblk_t *getq(q)
register queue_t *q;
Leszedi a következo üzenetet (ha van) a q message queueról. A
függvény egy pointert ad vissza, ami a leszedett message címét
tartalmazza. Ha nincs már message a queuen, akkor a függvény
visszatérési értéke NULL pointer lesz, és a rendszer beállít a
queue adatstrukturájában egy QWANTR flaget, ami azt jelzi, hogy a
queueról olvasni akarnak. Ha ilyen állapotban egy üzenet érkezik a
queuera, akkor a kernel a qenable() függvény meghívásával
automatikusan újraindítja a service rutint.
Ha a getq() rutin leszedett egy üzenetet a q message
queueról, és ezután a queuen levo üzenetek összhossza kisebb, mint a
queuehoz megadott low water mark érték, és a queuera már próbáltak
korábban új üzenetet rakni, de ez sikertelen volt, akkor a q queue
mögötti sor service rutinja a qenable() függvény meghívásával újra
el lesz indítva.
--- - noenable - queue inaktivizálása - ---
void noenable(q)
queue_t *q;
A megadott q queuet inaktiv állapotba hozza - a STREAMS service
scheduler nem adja ennek a sornak a service rutinjára többet a
vezérlést. (Inverz muvelete: az enableok() függvény.)
--- - OTHERQ - megadja a queue párját - ---
#define OTHERQ(q) ((q)->q_flag&QREADR? (q)+1 : (q)-1)
A makro eredménye a q queue párjára mutató pointer. (Ha a q
a read queue, akkor az eredmény a hozzá tartozó write queuera mutató
pointer; ha q egy write queuera pointer, akkor az eredmény a read
queuera pointer.)
--- - putctl - kontroll-üzenet továbbítása - ---
int putctl(q, type)
queue_t *q;
int type;
A putctl() függvény lefoglal egy üzenet számára az allocb()
kernelhívás segítségével memóriát, az üzenet típusát beállítja a
type paraméterben megadottra, majd meghívja a q paraméter által
mutatott queue put rutinját. A függvény visszatérési értéke 1, ha
minden rendben ment. Nulla akkor lehet a visszatérési érték, ha a
rendszer nem tudott lefoglalni az üzenetblokk számára memóriát, vagy a
type paraméter értéke az M_DATA
, M_PROTO
,
M_PCPROTO
, vagy M_DELAY
értékek egyike.
--- - putbq - üzenet visszarakása a sorba - ---
int *putbq(q, bp)
register queue_t *q;
register mblk_t *bp;
A putbq() függvény a bp által mutatott üzenetet visszarakja
a q által mutatott queue elejére. (A queuban legelobbre kerülnek a
magas prioritású üzenetek, a normál prioritású üzenetek pedig a magas
prioritású üzenetek mögé, de a korábban már ott levo alacsony prioritású
üzenetek elé kerülnek.) A service rutin soha ne rakjon vissza magas
prioritású üzenetet a saját queuejába, mert ez végtelen ciklust
eredményezne a kernelen belül!
Sikeres végrehajtás esetén a függvény visszatérési értéke: 1, sikertelen
végrehajtás esetén a visszatérési érték 0 lesz.
--- - putnext - egy üzenetet a következo queuera rak - ---
#define putnext(q,mp) ((*(q)->q_next->q_qinfo->qi_putp)((q)->q_next,(mp)))
A putnext() egy makro, amely a q után közvetlenül következo
queue put() rutinját hívja meg, és átadja neki az mp által
mutatott üzenetet.
--- - putq - egy megadott üzenetet valamelyik queuera rakja - ---
int *putq(q, bp)
register queue_t *q;
register mblk_t *bp;
A putq() függvény a q paraméterben meghatározott queura
átadja az mp által mutatott üzenetet.
--- - qenable - queue aktivizálása - ---
void qenable(q)
register queue_t *q;
Ez a függvény a q paraméter által meghatározott sort a STREAMS
schedulernek arra a listájára rakja, amely a futásra kész sorok adatait
tartalmazza. Ez azt jelenti, hogy az adott queue service rutinja rövid
idon belül újból futni fog.
--- - qreply - üzenet visszaküldése ellentétes irányban - ---
void *qreply(q, bp)
register queue_t *q;
mblk_t *bp;
Ez a függvény meghatározza a q queue párját (a lefele meno
streamnek a párja a felfelé meno, ill. fordítva), és azon a
putnext() makro muködéséhez hasonlóan visszaküldi a bp pointer
által meghatározott üzenetet. Ezt a függvényt szokták használni az
M_IOCTL
üzenetekre küldendo válasz visszaküldésére.
--- - RD - megadja a read queuet - ---
#define RD(q) ((q)-1)
A makro paramétere ( q) egy write queuera mutató pointer, eredménye
pedig a q queue párjára (vagyis a read queuera) mutató pointer. Ez
a muvelet azért ilyen egyszeru, mert a kernel a queuekat nem egyenként
foglalja le, hanem párosával. Az alacsonyabb memóriacímen van a read
queue, a magasabbon pedig a write queue.
--- - splstr - átállítja az interrupt prioritási szintet - ---
#define splstr() spltty()
Az splstr() makro az spltty() kernelhívás segítségével
beállítja a processzor interrupt prioritási szintjét a STREAMS driverek
és modulok interrupt prioritási szintjére, a kritikus szakaszok védelme
érdekében. Ez azt jelenti, hogy az éppen futó driver muködését más
driverek vagy modulok nem tudják megszakítani. Ez a rutin visszatérési
értékként az addigi processzor interrupt prioritási szintet adja. A
kritikus szakasz végén az splx() kernelhívás segítségével vissza
kell állítani a processzor interrupt prioritási szintjét az elozo
értékre. Ezt a rutint csak igen indokolt esetben használjuk!
Megjegyzés: az Intel 80386-os UNIX rendszerek esetén ez
általában IPL=7 szintnek felel meg, és ekkor sem a soros vonalakról jövo
megszakítások, sem az óramegszakítások nem lesznek megengedve. Mivel a
rendszeróra is le lesz tiltva, ezért csak olyan rutinokat védjünk így,
aminek a végrehajtása nem igényel több idot, mint két órainterrupt közti
ido.
--- - unlinkb - egy üzenet elso blokkját törli - ---
mblk_t *
unlinkb(bp)
register mblk_t *bp;
Az unlinkb() függvény elválasztja a bp paraméter által
mutatott üzenet elso üzenetblokkját a mögötte lévo blokkoktól, és egy
pointert ad vissza az üzenet megmaradó részére. Az eredménye NULL
pointer lesz, ha nem maradt több üzenetblokk az üzenetben. (Az elso
üzenetblokk nem lesz automatikusan felszabadítva, így ez a programozó
feladata marad.)
--- - WR - megadja a write queuet - ---
#define WR(q) ((q)+1)
A WR makro paramétere ( q) egy read queuera mutató pointer,
eredménye pedig a q queue párjára (vagyis a hozzá tartozó write
queuera) mutató pointer.