Þessi grein lýsir útfærslu leiðslna í Unix kjarnanum. Ég varð fyrir nokkrum vonbrigðum með að nýleg grein bar yfirskriftina "
Hvað erum við að tala um?
Leiðslur, „sennilega mikilvægasta uppfinningin í Unix,“ eru einkennandi einkenni undirliggjandi Unix heimspeki um að tengja lítil forrit saman, auk kunnuglegs tákns á skipanalínunni:
$ echo hello | wc -c
6
Þessi virkni er háð kerfiskallinu sem útvegað er kjarna pipe
, sem lýst er á skjalasíðunum
Leiðslur veita einstefnurás fyrir samskipti milli vinnsluferla. Leiðslan hefur inntak (skrifenda) og úttak (lesenda). Gögn sem eru skrifuð á inntak leiðslunnar má lesa við úttakið.
Leiðslan er búin til með því að nota símtalið
pipe(2)
, sem skilar tveimur skráarlýsingum: annar vísar til inntaks leiðslunnar, hinnar til úttaksins.
Rekja úttakið frá ofangreindri skipun sýnir sköpun leiðslunnar og flæði gagna í gegnum hana frá einu ferli til annars:
$ strace -qf -e execve,pipe,dup2,read,write
sh -c 'echo hello | wc -c'
execve("/bin/sh", ["sh", "-c", "echo hello | wc -c"], …)
pipe([3, 4]) = 0
[pid 2604795] dup2(4, 1) = 1
[pid 2604795] write(1, "hellon", 6) = 6
[pid 2604796] dup2(3, 0) = 0
[pid 2604796] execve("/usr/bin/wc", ["wc", "-c"], …)
[pid 2604796] read(0, "hellon", 16384) = 6
[pid 2604796] write(1, "6n", 2) = 2
Foreldraferlið kallar pipe()
til að fá uppsetta skráarlýsingar. Eitt undirferli skrifar í eitt handfang og annað ferli les sömu gögn úr öðru handfangi. Skelin notar dup2 til að „endurnefna“ lýsingar 3 og 4 til að passa við stdin og stdout.
Án pípa þyrfti skelin að skrifa niðurstöðu eins ferlis í skrá og senda það í annað ferli til að lesa gögnin úr skránni. Fyrir vikið myndum við sóa meira fjármagni og plássi. Hins vegar eru leiðslur góðar ekki aðeins vegna þess að þær leyfa þér að forðast notkun tímabundinna skráa:
Ef ferli er að reyna að lesa úr tómri leiðslu þá
read(2)
mun loka þar til gögnin verða aðgengileg. Ef ferli reynir að skrifa í fulla leiðslu, þáwrite(2)
mun loka þar til næg gögn hafa verið lesin úr leiðslunni til að framkvæma ritunina.
Eins og POSIX krafan er þetta mikilvægur eiginleiki: að skrifa í leiðsluna upp að PIPE_BUF
bæti (að minnsta kosti 512) verða að vera atóm þannig að ferli geti átt samskipti sín á milli í gegnum leiðsluna á þann hátt sem venjulegar skrár (sem veita ekki slíkar tryggingar) geta ekki.
Þegar venjuleg skrá er notuð getur ferli skrifað allt úttak sitt á hana og sent það áfram í annað ferli. Eða ferli geta starfað í mjög samhliða ham, með því að nota utanaðkomandi merkjakerfi (eins og semafór) til að láta hvert annað vita þegar ritun eða lestri er lokið. Færibönd bjarga okkur frá öllu þessu veseni.
Hvað erum við að leita að?
Ég mun útskýra það á einfaldan hátt svo að það sé auðveldara fyrir þig að ímynda þér hvernig færiband getur virkað. Þú þarft að úthluta biðminni og einhverju ástandi í minni. Þú þarft aðgerðir til að bæta við og fjarlægja gögn úr biðminni. Þú þarft einhverja leið til að hringja í aðgerðir meðan á lestri og ritun stendur á skráarlýsingum. Og þú þarft læsingar til að framkvæma sérstaka hegðun sem lýst er hér að ofan.
Nú erum við tilbúin að yfirheyra frumkóðann kjarna undir björtu lampaljósi til að staðfesta eða afsanna óljósa andlega líkanið okkar. En vertu alltaf viðbúinn hinu óvænta.
Hvert erum við að leita?
Ég veit ekki hvar mitt eintak af bókinni frægu er “
Að ráfa í gegnum skjalasafn TUHS er eins og að heimsækja safn. Við getum litið á sameiginlega sögu okkar og ég ber virðingu fyrir margra ára viðleitni til að endurheimta allt þetta efni smátt og smátt af gömlum segulböndum og prentum. Og ég geri mér fulla grein fyrir þessum brotum sem enn vantar.
Eftir að hafa fullnægt forvitni okkar um forna sögu færibanda, getum við litið á nútíma kjarna til samanburðar.
Tilviljun, pipe
er kerfissímtal númer 42 í töflunni sysent[]
. Tilviljun?
Hefðbundnir Unix kjarna (1970–1974)
Ég fann engin ummerki pipe(2)
né inn
TUHS segir það
Unix 1973rd Edition var síðasta útgáfan með kjarna skrifuðum á samsetningartungumáli, en einnig fyrsta útgáfan með leiðslum. Árið XNUMX var unnið að endurbótum á þriðju útgáfunni, kjarninn var endurskrifaður í C og því kom fjórða útgáfan af Unix.
Einn lesandi fann skanna af skjali þar sem Doug McIlroy lagði fram hugmyndina um að „tengja forrit eins og garðslöngu“.
Í bók Brian Kernighan
Þegar Unix kom út leiddi hrifning mín af coroutines til þess að ég bað höfund stýrikerfisins, Ken Thompson, um að leyfa gögnum sem skrifuð voru í ferli að fara ekki aðeins í tækið heldur einnig til úttaks í annað ferli. Ken ákvað að það væri mögulegt. Hins vegar, sem naumhyggjumaður, vildi hann að allar kerfisaðgerðir gegndu mikilvægu hlutverki. Er ritun beint á milli ferla í raun stór kostur fram yfir að skrifa í milliskrá? Það var aðeins þegar ég lagði fram ákveðna tillögu með grípandi nafninu „pípalína“ og lýsingu á setningafræðinni fyrir samskipti milli ferla sem Ken hrópaði að lokum: „Ég geri það!
Og gerði. Eitt örlagaríkt kvöld breytti Ken um kjarna og skel, lagaði nokkur stöðluð forrit til að staðla hvernig þau samþykktu inntak (sem gæti komið úr leiðslu) og breytti einnig skráarnöfnum. Daginn eftir var farið að nota leiðslur mjög víða í notkun. Í lok vikunnar voru ritarar að nota þá til að senda skjöl úr ritvinnslum í prentarann. Nokkru síðar skipti Ken út upprunalegu API og setningafræði til að vefja notkun leiðslna með hreinni venjum, sem hafa verið notaðar síðan.
Því miður hefur frumkóði fyrir þriðju útgáfu Unix kjarna glatast. Og þó að við höfum frumkóðann fyrir kjarnann skrifaðan í C
Við höfum textaskjöl fyrir pipe(2)
úr báðum útgáfunum, svo þú getur byrjað á því að leita í skjölunum pipe(2)
er skrifað á samsetningartungumáli og skilar aðeins einum skráarlýsingu, en veitir nú þegar væntanlega grunnvirkni:
Kerfiskall pípa býr til inntaks/úttakskerfi sem kallast leiðsla. Hægt er að nota skilaða skráarlýsingu til að lesa og skrifa. Þegar eitthvað er skrifað í leiðsluna eru allt að 504 bæti af gögnum í biðminni, eftir það er skrifferlið stöðvað. Þegar lesið er úr leiðslunni eru biðminni gögnin fjarlægð.
Árið eftir hafði kjarninn verið endurskrifaður í C, og pipe(fildes)
'
Kerfiskall pípa býr til inntaks/úttakskerfi sem kallast leiðsla. Hægt er að nota skilaða skráarlýsingar í lestrar- og skrifaðgerðum. Þegar eitthvað er skrifað í leiðsluna er handfangið sem skilað er í r1 (resp. fildes[1]), notað í biðminni í 4096 bæti af gögnum, eftir það er skrifferlið stöðvað. Þegar lesið er úr leiðslunni tekur handfangið aftur í r0 (resp. fildes[0]) gögnin.
Gert er ráð fyrir að þegar leiðsla hefur verið skilgreind séu tveir (eða fleiri) samskiptaferli (búnir til með síðari símtölum til Fork) mun flytja gögn úr leiðslunni með símtölum lesa и skrifa.
Skelin hefur setningafræði til að skilgreina línulega fylki ferla sem tengd eru með leiðslu.
Símtöl til að lesa úr tómri leiðslu (sem inniheldur engin biðminni gögn) sem hefur aðeins einn enda (allir ritskráarlýsingar eru lokaðar) skila „enda skráar“. Símtöl um að skrifa í svipuðum aðstæðum eru hunsuð.
Elstu
Sjötta útgáfa af Unix (1975)
Við skulum byrja að lesa Unix frumkóða
Í mörg ár bókin Lions var eina skjalið um Unix kjarnann sem er fáanlegt utan Bell Labs. Þrátt fyrir að sjötta útgáfan leyfi kennurum að nota frumkóðann, útilokaði sjöunda útgáfan þennan möguleika, svo bókinni var dreift í formi ólöglegra vélritaðra eintaka.
Í dag er hægt að kaupa endurútgáfu af bókinni en kápa hennar sýnir nemendur við ljósritunarvél. Og þökk sé Warren Toomey (sem byrjaði TUHS verkefnið) er hægt að hlaða niður
Fyrir meira en 15 árum síðan skrifaði ég afrit af frumkóðanum sem gefinn er inn Lions, vegna þess að mér líkaði ekki gæði eintaksins míns frá óþekktum fjölda annarra eintaka. TUHS var ekki til ennþá og ég hafði ekki aðgang að gömlu heimildunum. En árið 1988 fann ég gamla 9 laga spólu sem innihélt öryggisafrit úr PDP11 tölvu. Það var erfitt að segja til um hvort það virkaði, en það var ósnortið /usr/src/ tré þar sem flestar skrárnar voru merktar með ártalinu 1979, sem jafnvel þá leit fornt út. Það var sjöunda útgáfan eða afleidd PWB hennar, eins og ég trúði.
Ég tók fundinn til grundvallar og handstýrði heimildunum í sjöttu útgáfuna. Sumt af kóðanum var óbreytt, en sumum þurfti að breyta örlítið og breytti nútíma += tákninu í úrelt =+. Sumt var einfaldlega eytt og sumt þurfti að endurskrifa alveg en ekki of mikið.
Og í dag getum við lesið á netinu á TUHS frumkóðann sjöttu útgáfunnar frá
Við the vegur, við fyrstu sýn, er aðalatriðið í C-kóðanum fyrir tímabilið Kernighan og Ritchie. stuttorð. Það er ekki oft sem ég get sett inn kóðastykki án mikillar breytinga til að passa við tiltölulega þröngt skjásvæði á síðunni minni.
Snemma
/*
* Max allowable buffering per pipe.
* This is also the max size of the
* file created to implement the pipe.
* If this size is bigger than 4096,
* pipes will be implemented in LARG
* files, which is probably not good.
*/
#define PIPSIZ 4096
Stærð biðminni hefur ekki breyst síðan í fjórðu útgáfunni. En hér sjáum við, án nokkurra opinberra gagna, að leiðslur notuðu einu sinni skrár sem öryggisafrit!
Hvað LARG skrár varðar, þá samsvara þær
Hér er hið raunverulega kerfiskall pipe
:
/*
* The sys-pipe entry.
* Allocate an inode on the root device.
* Allocate 2 file structures.
* Put it all together with flags.
*/
pipe()
{
register *ip, *rf, *wf;
int r;
ip = ialloc(rootdev);
if(ip == NULL)
return;
rf = falloc();
if(rf == NULL) {
iput(ip);
return;
}
r = u.u_ar0[R0];
wf = falloc();
if(wf == NULL) {
rf->f_count = 0;
u.u_ofile[r] = NULL;
iput(ip);
return;
}
u.u_ar0[R1] = u.u_ar0[R0]; /* wf's fd */
u.u_ar0[R0] = r; /* rf's fd */
wf->f_flag = FWRITE|FPIPE;
wf->f_inode = ip;
rf->f_flag = FREAD|FPIPE;
rf->f_inode = ip;
ip->i_count = 2;
ip->i_flag = IACC|IUPD;
ip->i_mode = IALLOC;
}
Athugasemdin lýsir vel því sem er að gerast hér. En að skilja kóðann er ekki svo auðvelt, að hluta til vegna þess hvernig "R0
и R1
færibreytur kerfiskalla og skilagildi eru send.
Við skulum reyna með
pipe()
verður í gegnum R0
и R1
skila skráarlýsingarnúmerum fyrir lestur og ritun. falloc()
skilar bendi í skráarskipulagið, en „skilar“ líka í gegnum u.u_ar0[R0]
og skráarlýsingu. Það er, kóðinn vistar inn r
skráarlýsing til að lesa og úthlutar skráarlýsingu til að skrifa beint úr u.u_ar0[R0]
eftir seinna símtalið falloc()
.
Flagga FPIPE
, sem við stillum þegar leiðslan er búin til, stjórnar hegðun aðgerðarinnar
/*
* common code for read and write calls:
* check permissions, set base, count, and offset,
* and switch out to readi, writei, or pipe code.
*/
rdwr(mode)
{
register *fp, m;
m = mode;
fp = getf(u.u_ar0[R0]);
/* … */
if(fp->f_flag&FPIPE) {
if(m==FREAD)
readp(fp); else
writep(fp);
}
/* … */
}
Síðan aðgerðin readp()
в pipe.c
les gögn úr leiðslunni. En það er betra að rekja framkvæmdina frá og með writep()
. Aftur hefur kóðinn orðið flóknari vegna hefðbundinnar röksemdafærslu, en hægt er að sleppa nokkrum smáatriðum.
writep(fp)
{
register *rp, *ip, c;
rp = fp;
ip = rp->f_inode;
c = u.u_count;
loop:
/* If all done, return. */
plock(ip);
if(c == 0) {
prele(ip);
u.u_count = 0;
return;
}
/*
* If there are not both read and write sides of the
* pipe active, return error and signal too.
*/
if(ip->i_count < 2) {
prele(ip);
u.u_error = EPIPE;
psignal(u.u_procp, SIGPIPE);
return;
}
/*
* If the pipe is full, wait for reads to deplete
* and truncate it.
*/
if(ip->i_size1 == PIPSIZ) {
ip->i_mode =| IWRITE;
prele(ip);
sleep(ip+1, PPIPE);
goto loop;
}
/* Write what is possible and loop back. */
u.u_offset[0] = 0;
u.u_offset[1] = ip->i_size1;
u.u_count = min(c, PIPSIZ-u.u_offset[1]);
c =- u.u_count;
writei(ip);
prele(ip);
if(ip->i_mode&IREAD) {
ip->i_mode =& ~IREAD;
wakeup(ip+2);
}
goto loop;
}
Við viljum skrifa bæti í leiðsluinntakið u.u_count
. Fyrst þurfum við að læsa inode (sjá hér að neðan plock
/prele
).
Þá athugum við inode tilvísunarteljarann. Svo lengi sem báðir endar leiðslunnar eru opnir, ætti teljarinn að vera jafn 2. Við höldum einum hlekk (frá kl. rp->f_inode
), þannig að ef teljarinn er minni en 2 hlýtur það að þýða að lestrarferlið hafi lokað leiðslunni. Með öðrum orðum, við erum að reyna að skrifa í lokaða leiðslu og þetta er villa. Fyrsta skipti villukóði EPIPE
og merki SIGPIPE
birtist í sjöttu útgáfu Unix.
En jafnvel þótt færibandið sé opið getur það verið fullt. Í þessu tilviki losum við lásinn og förum að sofa í von um að annað ferli lesi úr leiðslunni og losi nóg pláss í henni. Eftir að hafa vaknað förum við aftur til byrjunar, hengjum upp lásinn aftur og byrjum nýja upptökulotu.
Ef það er nóg laust pláss í leiðslunni, þá skrifum við gögn til þess með því að nota i_size1
at inode (ef leiðslan er tóm getur hún verið jöfn 0) gefur til kynna lok gagna sem hún inniheldur þegar. Ef það er nóg upptökupláss getum við fyllt leiðsluna frá i_size1
í PIPESIZ
. Síðan sleppum við lásnum og reynum að vekja hvaða ferli sem bíður þess að lesa úr leiðslunni. Við förum aftur til upphafsins til að sjá hvort við gætum skrifað eins mörg bæti og við þurftum. Ef það mistekst, þá byrjum við nýja upptökulotu.
Venjulega færibreytan i_mode
inode er notað til að geyma heimildir r
, w
и x
. En þegar um leiðslur er að ræða, gefum við merki um að eitthvað ferli bíði eftir skrifum eða lestri með því að nota bita IREAD
и IWRITE
í sömu röð. Ferlið setur fána og kallar sleep()
, og gert er ráð fyrir að eitthvað annað ferli í framtíðinni muni valda wakeup()
.
Hinn raunverulegi galdur gerist í sleep()
и wakeup()
. Þau eru innleidd í
/*
* Give up the processor till a wakeup occurs
* on chan, at which time the process
* enters the scheduling queue at priority pri.
* The most important effect of pri is that when
* pri<0 a signal cannot disturb the sleep;
* if pri>=0 signals will be processed.
* Callers of this routine must be prepared for
* premature return, and check that the reason for
* sleeping has gone away.
*/
sleep(chan, pri) /* … */
/*
* Wake up all processes sleeping on chan.
*/
wakeup(chan) /* … */
Ferlið sem veldur sleep()
fyrir tiltekna rás, getur seinna verið vakin með öðru ferli, sem mun valda wakeup()
fyrir sömu rás. writep()
и readp()
samræma aðgerðir sínar með slíkum pöruðum símtölum. athugið að pipe.c
hefur alltaf forgang PPIPE
þegar hringt er í sleep()
, svo það er komið sleep()
getur verið truflað af merki.
Nú höfum við allt til að skilja virknina readp()
:
readp(fp)
int *fp;
{
register *rp, *ip;
rp = fp;
ip = rp->f_inode;
loop:
/* Very conservative locking. */
plock(ip);
/*
* If the head (read) has caught up with
* the tail (write), reset both to 0.
*/
if(rp->f_offset[1] == ip->i_size1) {
if(rp->f_offset[1] != 0) {
rp->f_offset[1] = 0;
ip->i_size1 = 0;
if(ip->i_mode&IWRITE) {
ip->i_mode =& ~IWRITE;
wakeup(ip+1);
}
}
/*
* If there are not both reader and
* writer active, return without
* satisfying read.
*/
prele(ip);
if(ip->i_count < 2)
return;
ip->i_mode =| IREAD;
sleep(ip+2, PPIPE);
goto loop;
}
/* Read and return */
u.u_offset[0] = 0;
u.u_offset[1] = rp->f_offset[1];
readi(ip);
rp->f_offset[1] = u.u_offset[1];
prele(ip);
}
Þú gætir átt auðveldara með að lesa þessa aðgerð frá botni til topps. „Lesa og skila“ greinin er venjulega notuð þegar einhver gögn eru í pípunum. Í þessu tilfelli notum við f_offset
lestur, og uppfærðu síðan gildi samsvarandi offset.
Við síðari lestur verður leiðslan tóm ef lesjöfnun hefur náð i_size1
á inode. Við endurstillum stöðuna á 0 og reynum að vekja hvaða ferli sem vill skrifa í leiðsluna. Við vitum að þegar færibandið er fullt, writep()
mun sofna á ip+1
. Og nú þegar leiðslan er tóm, getum við vakið hana til að hefja ritferilinn aftur.
Ef þú hefur ekkert að lesa, þá readp()
getur sett fána IREAD
og sofna áfram ip+2
. Við vitum hvað mun vekja hann writep()
, þegar það skrifar nokkur gögn í leiðsluna.
Athugasemdir við u
„Við getum meðhöndlað þau eins og venjulegar I/O aðgerðir sem taka skrá, staðsetningu, biðminni í minni og telja fjölda bæta til að lesa eða skrifa.
/*
* Read the file corresponding to
* the inode pointed at by the argument.
* The actual read arguments are found
* in the variables:
* u_base core address for destination
* u_offset byte offset in file
* u_count number of bytes to read
* u_segflg read to kernel/user
*/
readi(aip)
struct inode *aip;
/* … */
/*
* Write the file corresponding to
* the inode pointed at by the argument.
* The actual write arguments are found
* in the variables:
* u_base core address for source
* u_offset byte offset in file
* u_count number of bytes to write
* u_segflg write to kernel/user
*/
writei(aip)
struct inode *aip;
/* … */
Eins og fyrir "íhaldssama" blokkun, þá readp()
и writep()
loka fyrir inode þar til þeir klára vinnu sína eða fá niðurstöðu (þ.e. hringja wakeup
). plock()
и prele()
vinna einfaldlega: nota annað sett af símtölum sleep
и wakeup
leyfðu okkur að vekja upp hvaða ferli sem er sem þarf á lásnum sem við gáfum út:
/*
* Lock a pipe.
* If its already locked, set the WANT bit and sleep.
*/
plock(ip)
int *ip;
{
register *rp;
rp = ip;
while(rp->i_flag&ILOCK) {
rp->i_flag =| IWANT;
sleep(rp, PPIPE);
}
rp->i_flag =| ILOCK;
}
/*
* Unlock a pipe.
* If WANT bit is on, wakeup.
* This routine is also used to unlock inodes in general.
*/
prele(ip)
int *ip;
{
register *rp;
rp = ip;
rp->i_flag =& ~ILOCK;
if(rp->i_flag&IWANT) {
rp->i_flag =& ~IWANT;
wakeup(rp);
}
}
Í fyrstu gat ég ekki skilið hvers vegna readp()
veldur ekki prele(ip)
fyrir símtalið wakeup(ip+1)
. Það fyrsta er writep()
veldur í hringrás sinni, þetta plock(ip)
, sem leiðir til dauðastöðu ef readp()
hef ekki fjarlægt blokkina mína ennþá, svo einhvern veginn verður kóðinn að virka rétt. Ef þú horfir á wakeup()
, þá kemur í ljós að það markar aðeins svefnferlið sem tilbúið til framkvæmdar, svo að í framtíðinni sched()
setti það í alvörunni af stað. Svo readp()
orsakir wakeup()
, fjarlægir læsinguna, setur IREAD
og hringingar sleep(ip+2)
- allt þetta áður writep()
byrjar hringrásina aftur.
Þetta lýkur lýsingu á færiböndum í sjöttu útgáfunni. Einfaldur kóða, víðtækar afleiðingar.
Xv6, einfaldur Unix-líkur kjarni
Til að búa til kjarnann
Kóðinn inniheldur skýra og yfirvegaða útfærslu pipealloc()
:
#define PIPESIZE 512
struct pipe {
struct spinlock lock;
char data[PIPESIZE];
uint nread; // number of bytes read
uint nwrite; // number of bytes written
int readopen; // read fd is still open
int writeopen; // write fd is still open
};
int
pipealloc(struct file **f0, struct file **f1)
{
struct pipe *p;
p = 0;
*f0 = *f1 = 0;
if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
goto bad;
if((p = (struct pipe*)kalloc()) == 0)
goto bad;
p->readopen = 1;
p->writeopen = 1;
p->nwrite = 0;
p->nread = 0;
initlock(&p->lock, "pipe");
(*f0)->type = FD_PIPE;
(*f0)->readable = 1;
(*f0)->writable = 0;
(*f0)->pipe = p;
(*f1)->type = FD_PIPE;
(*f1)->readable = 0;
(*f1)->writable = 1;
(*f1)->pipe = p;
return 0;
bad:
if(p)
kfree((char*)p);
if(*f0)
fileclose(*f0);
if(*f1)
fileclose(*f1);
return -1;
}
pipealloc()
setur stöðu restarinnar af útfærslunni, sem inniheldur aðgerðirnar piperead()
, pipewrite()
и pipeclose()
. Raunverulegt kerfiskall sys_pipe
er umbúðir útfærðar í
Linux 0.01
Linux 0.01 frumkóða er að finna. Það verður fróðlegt að kynna sér útfærslu lagna í hans fs
/pipe.c
. Þetta notar inode til að tákna leiðsluna, en leiðslan sjálf er skrifuð í nútíma C. Ef þú hefur unnið þig í gegnum 6. útgáfu kóða, munt þú ekki eiga í neinum vandræðum hér. Svona lítur aðgerðin út write_pipe()
:
int write_pipe(struct m_inode * inode, char * buf, int count)
{
char * b=buf;
wake_up(&inode->i_wait);
if (inode->i_count != 2) { /* no readers */
current->signal |= (1<<(SIGPIPE-1));
return -1;
}
while (count-->0) {
while (PIPE_FULL(*inode)) {
wake_up(&inode->i_wait);
if (inode->i_count != 2) {
current->signal |= (1<<(SIGPIPE-1));
return b-buf;
}
sleep_on(&inode->i_wait);
}
((char *)inode->i_size)[PIPE_HEAD(*inode)] =
get_fs_byte(b++);
INC_PIPE( PIPE_HEAD(*inode) );
wake_up(&inode->i_wait);
}
wake_up(&inode->i_wait);
return b-buf;
}
Án þess að skoða byggingarskilgreiningarnar, geturðu fundið út hvernig inode tilvísunarfjöldi er notaður til að athuga hvort ritaðgerð leiði til SIGPIPE
. Auk þess að vinna bæti fyrir bæti er auðvelt að bera þessa aðgerð saman við hugmyndirnar sem lýst er hér að ofan. Jafnvel rökfræði sleep_on
/wake_up
lítur ekki svo framandi út.
Nútíma Linux kjarna, FreeBSD, NetBSD, OpenBSD
Ég fór fljótt í gegnum nokkra nútímakjarna. Enginn þeirra er lengur með diskútfærslu (ekki á óvart). Linux hefur sína eigin útfærslu. Þrátt fyrir að þrír nútíma BSD kjarnarnir innihaldi útfærslur byggðar á kóða sem var skrifaður af John Dyson, hafa þeir í gegnum árin orðið of ólíkir hver öðrum.
Að lesa fs
/pipe.c
(á Linux) eða sys
/kern
/sys_pipe.c
(á *BSD), það krefst alvöru vígslu. Kóðinn í dag snýst um frammistöðu og stuðning við eiginleika eins og vektor og ósamstillt I/O. Og upplýsingar um minnisúthlutun, læsingar og kjarnastillingar eru mjög mismunandi. Þetta er ekki það sem framhaldsskólar þurfa fyrir kynningarnámskeið í stýrikerfum.
Allavega, ég hafði áhuga á að grafa upp nokkur gömul mynstur (eins og að búa til SIGPIPE
og skila EPIPE
þegar skrifað er í lokaða leiðslu) í öllum þessum mismunandi nútímakjarna. Ég mun sennilega aldrei sjá PDP-11 tölvu í raunveruleikanum, en það er samt margt að læra af kóða sem var skrifaður árum áður en ég fæddist.
Grein skrifuð af Divi Kapoor árið 2011:
Heimild: www.habr.com