Déanann an t-alt seo cur síos ar chur i bhfeidhm píblínte san eithne Unix. Bhí díomá beag orm go raibh alt le déanaí dar teideal “
Cad faoi a bhfuilimid ag caint?
Is sainairíonna iad píblínte, “an t-aireagán is tábhachtaí in Unix, is dócha,” d’fhealsúnacht bhunúsach Unix maidir le cláir bheaga a nascadh le chéile, chomh maith le comhartha coitianta ar an líne ceannais:
$ echo hello | wc -c
6
Braitheann an fheidhmiúlacht seo ar an nglao córais a sholáthair an eithne pipe
a bhfuil cur síos air ar na leathanaigh doiciméadaithe
Soláthraíonn píblínte cainéal aontreoch le haghaidh cumarsáide idirphróisis. Tá ionchur (deireadh scríofa) agus aschur (deireadh léite) ag an bpíblíne. Is féidir sonraí a scríobhtar chuig ionchur na píblíne a léamh ag an aschur.
Cruthaítear an phíblíne ag baint úsáide as an nglao
pipe(2)
, a thugann dhá thuairisceoir comhaid ar ais: ceann amháin ag tagairt d'ionchur na píblíne, an dara ceann don aschur.
Léiríonn an t-aschur rian ón ordú thuas cruthú na píblíne agus an sreabhadh sonraí tríd ó phróiseas amháin go próiseas eile:
$ 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
Glaonn an próiseas tuismitheora pipe()
chun tuairisceoirí comhaid gléasta a fháil. Scríobhann próiseas páiste amháin chuig hanla amháin, agus léann próiseas eile na sonraí céanna ó láimhseáil eile. Úsáideann an bhlaosc dup2 chun tuairisceoirí 3 agus 4 a "athainmniú" chun stdin agus stdout a mheaitseáil.
Gan píopaí, bheadh ar an mblaosc aschur próiseas amháin a scríobh chuig comhad agus é a chur ar aghaidh chuig próiseas eile chun na sonraí ón gcomhad a léamh. Mar thoradh air sin, chuirfimis níos mó acmhainní agus spás diosca amú. Mar sin féin, tá píblínte go maith, ní hamháin toisc go gceadaíonn siad duit úsáid comhaid shealadacha a sheachaint:
Má tá próiseas ag iarraidh léamh ó phíblíne folamh ansin
read(2)
bacfaidh sé go dtí go mbeidh na sonraí ar fáil. Má dhéanann próiseas iarracht scríobh chuig píblíne iomlán, ansinwrite(2)
blocfaidh sé go dtí go mbeidh go leor sonraí léite ón bpíblíne chun an scríobh a dhéanamh.
Cosúil le ceanglas POSIX, is maoin thábhachtach é seo: scríobh chuig an bpíblíne suas go dtí PIPE_BUF
caithfidh beart (512 ar a laghad) a bheith adamhach ionas gur féidir le próisis cumarsáid a dhéanamh lena chéile tríd an bpíblíne ar bhealach nach féidir le comhaid rialta (nach dtugann ráthaíochtaí dá leithéid).
Agus gnáthchomhad á úsáid, is féidir le próiseas a aschur go léir a scríobh chuige agus é a chur ar aghaidh chuig próiseas eile. Nó is féidir le próisis oibriú ar mhodh an-chomhthreomhar, ag baint úsáide as meicníocht chomharthaíochta sheachtrach (cosúil le semaphore) chun fógra a thabhairt dá chéile nuair a bhíonn scríobh nó léamh críochnaithe. Sábhálann iompróirí sinn ón hassle seo go léir.
Cad atá á lorg againn?
Míneoidh mé i dtéarmaí simplí é ionas go mbeidh sé níos éasca duit a shamhlú conas is féidir le iompróir oibriú. Beidh ort maolán agus staid éigin a leithdháileadh i gcuimhne. Beidh feidhmeanna uait chun sonraí a chur leis agus a bhaint as an maolán. Beidh roinnt bealaí ag teastáil uait chun feidhmeanna a ghlaoch le linn oibríochtaí léite agus scríofa ar thuairisceoirí comhaid. Agus beidh glais ag teastáil uait chun an iompar speisialta a thuairiscítear thuas a chur i bhfeidhm.
Táimid réidh anois an cód foinse eithne a cheistiú faoi sholas lampa geal chun ár samhail mheabhrach doiléir a dhearbhú nó a bhréagnú. Ach a ullmhú i gcónaí le haghaidh an gan choinne.
Cá bhfuil muid ag féachaint?
Níl a fhios agam cá bhfuil mo chóip den leabhar cáiliúil “
Is ionann siúl trí chartlanna TUHS agus cuairt a thabhairt ar mhúsaem. Is féidir linn breathnú ar ár stair chomhroinnte, agus tá meas agam ar na blianta fada a rinne mé iarracht an t-ábhar seo go léir a aisghabháil beagán ar bheagán ó shean-téipeanna agus priontaí. Agus is eol dom go géar na blúirí sin atá fós in easnamh.
Tar éis dúinn ár bhfiosracht faoi stair ársa na n-iompróirí a shásamh, is féidir linn breathnú ar eithne nua-aimseartha chun comparáid a dhéanamh.
Dála an scéil, pipe
is é córas glao-uimhir 42 sa tábla sysent[]
. Chomhtharlú?
Eithne Traidisiúnta Unix (1970–1974)
Ní bhfuair mé aon rian pipe(2)
ná i
Deir TUHS go bhfuil
Ba é Unix 1973rd Edition an leagan deireanach le eithne scríofa i dteanga tionóil, ach freisin an chéad leagan le píblínte. Le linn XNUMX, rinneadh obair chun an tríú eagrán a fheabhsú, athscríobhadh an eithne i C, agus mar sin bhí an ceathrú eagrán de Unix le feiceáil.
Fuair léitheoir amháin scanadh ar dhoiciméad inar mhol Doug McIlroy an smaoineamh “cláir a nascadh cosúil le hose gairdín.”
I leabhar Brian Kernighan
Nuair a tháinig Unix amach, thug mo spéis le coroutines orm iarraidh ar údar an OS, Ken Thompson, cead a thabhairt do shonraí scríofa chuig próiseas dul ní hamháin chuig an bhfeiste, ach freisin le haschur chuig próiseas eile. Chinn Ken go raibh sé indéanta. Mar íoslach, áfach, bhí sé ag iarraidh go mbeadh ról suntasach ag gach feidhm chórais. An buntáiste mór é scríobh go díreach idir próisis seachas scríobh chuig comhad idirmheánach? Is nuair a rinne mé moladh sonrach leis an ainm catchy “píblíne” agus cur síos ar an chomhréir don idirghníomhaíocht idir próisis a d’éiligh Ken ar deireadh: “Déanfaidh mé é!”
Agus rinne. Tráthnóna cinniúnach amháin, d'athraigh Ken an t-eithne agus an bhlaosc, shocraigh sé roinnt clár caighdeánach chun caighdeánú a dhéanamh ar an gcaoi ar ghlac siad le hionchur (a d'fhéadfadh teacht ó phíblíne), agus d'athraigh sé ainmneacha comhaid freisin. An lá dár gcionn, thosaigh píblínte a úsáid go forleathan in iarratais. Faoi dheireadh na seachtaine, bhí rúnaithe ag baint úsáide as iad chun doiciméid a sheoladh ó phróiseálaithe focal chuig an printéir. Beagán níos déanaí, chuir Ken in ionad an API bunaidh agus an chomhréir chun úsáid píblínte a fhilleadh le coinbhinsiúin níos glaine, a úsáideadh ó shin i leith.
Ar an drochuair, tá an cód foinse don tríú eagrán Unix eithne caillte. Agus cé go bhfuil an cód foinse eithne againn scríofa i C
Tá doiciméadú téacs againn le haghaidh pipe(2)
ón dá eisiúint, ionas gur féidir leat tosú trí chuardach a dhéanamh ar an doiciméadú pipe(2)
scríofa i dteanga tionóil agus ní sheolann sé ach tuairisceoir comhaid amháin ar ais, ach cuireann sé an chroífheidhmíocht ionchais ar fáil cheana féin:
Glao córais píopa cruthaíonn sé meicníocht ionchuir/aschuir ar a dtugtar píblíne. Is féidir an tuairisceoir comhaid a cuireadh ar ais a úsáid le haghaidh oibríochtaí léamh agus scríobh. Nuair a scríobhtar rud éigin chuig an bpíblíne, maolaítear suas le 504 bytes de shonraí, agus cuirtear an próiseas scríbhneoireachta ar fionraí ina dhiaidh sin. Nuair a bhíonn tú ag léamh ón bpíblíne, tógtar na sonraí maolánacha ar shiúl.
Faoin mbliain ina dhiaidh sin bhí an eithne athscríofa in C, agus pipe(fildes)
»:
Glao córais píopa cruthaíonn sé meicníocht ionchuir/aschuir ar a dtugtar píblíne. Is féidir na tuairisceoirí comhaid a cuireadh ar ais a úsáid in oibríochtaí léite agus scríofa. Nuair a scríobhtar rud éigin chuig an bpíblíne, úsáidtear an hanla a chuirtear ar ais in r1 (resp. fildes[1]), arna mhaolánú go 4096 beart sonraí, agus ina dhiaidh sin cuirtear an próiseas scríofa ar fionraí. Agus tú ag léamh ón bpíblíne, glacann an hanla a chuirtear ar ais go r0 (resp. fildes[0]) na sonraí.
Glactar leis, a luaithe a shainmhínítear píblíne, go ndéantar dhá phróiseas cumarsáide (nó níos mó) (a chruthaítear le glaonna ina dhiaidh sin chuig forc) aistreoidh sé sonraí ón bpíblíne trí úsáid a bhaint as glaonna léamh и scríobh.
Tá comhréir ag an mblaosc chun sraith líneach próiseas a shainiú atá nasctha le píblíne.
Glaonna le léamh ó phíblíne folamh (nach bhfuil aon sonraí maolánacha ann) nach bhfuil ach foirceann amháin aici (tá gach tuairisceoir comhaid scríofa dúnta) “deireadh comhaid” ar ais. Déantar neamhaird de ghlaonna chun scríobh i gcás comhchosúil.
is luaithe
An séú eagrán de Unix (1975)
Tosaímid ag léamh cód foinse Unix
Le blianta fada a an leabhar Lions an t-aon doiciméad ar an eithne Unix atá ar fáil lasmuigh de Bell Labs. Cé gur thug ceadúnas an séú heagrán cead do mhúinteoirí a cód foinse a úsáid, níor cuireadh an fhéidearthacht seo as an gceadúnas seachtú heagrán, mar sin dáileadh an leabhar i bhfoirm cóipeanna mídhleathacha clóscríofa.
Sa lá atá inniu is féidir leat athchló den leabhar a cheannach, agus taispeánann a chlúdach na mic léinn ag meaisín cóipe. Agus buíochas le Warren Toomey (a chuir tús leis an tionscadal TUHS) is féidir leat a íoslódáil
Breis is 15 bliain ó shin, chlóscríobh mé cóip den chód foinse a tugadh isteach Lions, mar níor thaitin cáilíocht mo chóip liom ó líon anaithnid cóipeanna eile. Ní raibh TUHS ann go fóill agus ní raibh rochtain agam ar na seanfhoinsí. Ach i 1988, fuair mé sean-téip 9-rian ina raibh cúltaca ó ríomhaire PDP11. Ba dheacair a rá an raibh sé ag obair, ach bhí crann /usr/src/ slán ann inar lipéadaíodh an chuid is mó de na comhaid leis an mbliain 1979, a bhí cuma ársa fiú ansin. Ba é an seachtú eagrán nó a dhíorthaigh PWB, mar a chreid mé.
Ghlac mé leis an bhfionnachtain mar bhonn agus chuir mé na foinsí in eagar go dtí an séú eagrán de láimh. D’fhan cuid den chód mar a chéile, ach b’éigean roinnt eile a chur in eagar, rud a d’athraigh an comhartha += nua-aimseartha go dtí an seanfhocal =+. Scriosadh roinnt rudaí go simplí, agus b'éigean roinnt eile a athscríobh go hiomlán, ach ní raibh an iomarca.
Agus inniu is féidir linn cód foinse an séú eagrán a léamh ar líne ar TUHS
Dála an scéil, ar an gcéad amharc, is é príomhghné an chóid C roimh thréimhse Kernighan agus Ritchie a gontacht. Ní minic a bhíonn mé in ann píosaí cód a chur isteach gan eagarthóireacht fhairsing chun limistéar taispeána sách cúng a chur ar mo shuíomh.
Luath
/*
* 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
Níl aon athrú ar an méid maoláin ón gceathrú eagrán. Ach anseo feicimid, gan aon doiciméadú poiblí, gur úsáideadh píblínte comhaid uair amháin mar stóráil chúltaca!
Maidir le comhaid LARG, comhfhreagraíonn siad do
Seo é an fíorghlao córais 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;
}
Déanann an trácht cur síos go soiléir ar a bhfuil ar siúl anseo. Ach níl sé chomh héasca an cód a thuiscint, i bpáirt mar gheall ar an mbealach "R0
и R1
déantar paraiméadair ghlao córais agus luachanna tuairisceáin a rith.
Déanaimis iarracht le
pipe()
ní mór tríd R0
и R1
uimhreacha tuairisceora comhaid a sheoladh ar ais le haghaidh léamh agus scríobh. falloc()
cuireann sé pointeoir ar ais chuig an struchtúr comhaid, ach freisin "tuairiscíonn" via u.u_ar0[R0]
agus tuairisceoir comhaid. Is é sin, sábhálann an cód i r
tuairisceoir comhaid le léamh agus sannann sé tuairisceoir comhaid lena scríobh go díreach uaidh u.u_ar0[R0]
tar éis an dara glaoch falloc()
.
Bratach FPIPE
, a shocraigh muid nuair a chruthaíonn an phíblíne, rialaíonn iompar na feidhme
/*
* 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);
}
/* … */
}
Ansin an fheidhm readp()
в pipe.c
léann sonraí ón bpíblíne. Ach is fearr an cur i bhfeidhm a rianú ag tosú ó writep()
. Arís, tá an cód tar éis éirí níos casta mar gheall ar choinbhinsiúin na hargóintí a rith, ach is féidir roinnt sonraí a fhágáil ar lár.
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;
}
Ba mhaith linn bearta a scríobh chuig an ionchur píblíne u.u_count
. Ar dtús ní mór dúinn an t-ionóid a ghlasadh (féach thíos plock
/prele
).
Ansin déanaimid seiceáil ar an gcuntar tagartha inode. Chomh fada agus a fhanann an dá cheann den phíblíne ar oscailt, ba chóir go mbeadh an gcuntar comhionann le 2. Coinnímid nasc amháin (ó rp->f_inode
), mar sin má tá an gcuntar níos lú ná 2, caithfidh sé a chiallaíonn go bhfuil deireadh an phíblíne dúnta ag an bpróiseas léitheoireachta. I bhfocail eile, táimid ag iarraidh scríobh chuig píblíne dúnta, agus is earráid é seo. Cód earráide don chéad uair EPIPE
agus comhartha SIGPIPE
le feiceáil sa séú eagrán de Unix.
Ach fiú má tá an conveyor oscailte, féadfaidh sé a bheith iomlán. Sa chás seo, scaoilimid an glas agus téann muid a chodladh le súil go léifear próiseas eile ón bpíblíne agus go scaoilfear go leor spáis ann. Tar éis dúinn dúiseacht, filleann muid ar an tús, crochaimid an glas arís agus cuirimid tús le timthriall taifeadta nua.
Má tá go leor spáis saor in aisce ar an bpíblíne, scríobhaimid sonraí chuige ag baint úsáide as i_size1
Léiríonn an inóid (má tá an phíblíne folamh is féidir é a bheith comhionann le 0) deireadh na sonraí atá ann cheana féin. Má tá go leor spáis taifeadta ann, is féidir linn an phíblíne a líonadh ó i_size1
до PIPESIZ
. Ansin scaoilimid an glas agus déanaimid iarracht aon phróiseas atá ag fanacht le léamh ón bpíblíne a mhúscailt. Téim ar ais go dtí an tús féachaint an raibh muid in ann a scríobh oiread beart agus is gá dúinn. Má theipeann air, ansin cuirimid tús le timthriall taifeadta nua.
De ghnáth an paraiméadar i_mode
úsáidtear inode chun ceadanna a stóráil r
, w
и x
. Ach i gcás píblínte, tugaimid le fios go bhfuil próiseas éigin ag fanacht le scríobh nó léamh ag baint úsáide as giotán IREAD
и IWRITE
faoi seach. Leagann an próiseas an bhratach agus glaonna sleep()
, agus táthar ag súil go gcuirfidh próiseas éigin eile sa todhchaí faoi deara wakeup()
.
Tarlaíonn an draíocht fíor i sleep()
и wakeup()
. Cuirtear i bhfeidhm iad i
/*
* 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) /* … */
An próiseas is cúis le sleep()
le haghaidh cainéal ar leith is féidir, a dhúiseacht níos déanaí le próiseas eile, rud a chuirfidh faoi deara wakeup()
don chainéal céanna. writep()
и readp()
a gcuid gníomhaíochtaí a chomhordú trí ghlaonna péireáilte den sórt sin. tabhair faoi deara go pipe.c
tugann tosaíocht i gcónaí PPIPE
nuair a ghlaoitear air sleep()
, mar sin sin é sleep()
féadfaidh comhartha cur isteach air.
Anois tá gach rud againn chun an fheidhm a thuiscint 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);
}
Seans go mbeidh sé níos fusa duit an fheidhm seo a léamh ó bhun go barr. Úsáidtear an brainse "léamh agus filleadh" de ghnáth nuair a bhíonn roinnt sonraí ar an bpíblíne. Sa chás seo, úsáidimid f_offset
léamh, agus ansin nuashonraigh luach an fhritháireamh comhfhreagrach.
Ar léamha ina dhiaidh sin, beidh an phíblíne folamh má tá an fritháireamh léite sroichte i_size1
ag inóid. Déanaimid an seasamh a athshocrú go 0 agus déanaimid iarracht aon phróiseas atá ag iarraidh scríobh chuig an bpíblíne a mhúscailt. Tá a fhios againn nuair a bhíonn an iompair lán. writep()
beidh titim ina chodladh ar ip+1
. Agus anois go bhfuil an phíblíne folamh, is féidir linn é a mhúscailt chun a timthriall scríbhneoireachta a atosú.
Mura bhfuil aon rud le léamh agat, ansin readp()
is féidir bratach a shocrú IREAD
agus titim ina chodladh ar ip+2
. Tá a fhios againn cad a dhúisíonn sé writep()
, nuair a scríobhann sé roinnt sonraí chuig an bpíblíne.
Tuairimí chuig u
“Is féidir linn caitheamh leo mar ghnáthfheidhmeanna I/O a thógann comhad, suíomh, maolán sa chuimhne, agus líon na mbeart atá le léamh nó le scríobh a chomhaireamh.
/*
* 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;
/* … */
Maidir leis an "coimeádach" blocáil, mar sin readp()
и writep()
bac a chur ar an inode go dtí go gcríochnóidh siad a gcuid oibre nó go bhfaighidh siad toradh (is é sin, glaoigh wakeup
). plock()
и prele()
oibriú go simplí: ag baint úsáide as sraith eile glaonna sleep
и wakeup
lig dúinn aon phróiseas a mhúscailt a dteastaíonn an glas a scaoileadh uainn:
/*
* 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);
}
}
Ar dtús ní raibh mé in ann a thuiscint cén fáth readp()
ní cúis prele(ip)
roimh an nglao wakeup(ip+1)
. Is é an chéad rud writep()
cúiseanna ina timthriall, seo plock(ip)
, as a dtagann tsáinn má readp()
níor bhain mé mo bhloc fós, mar sin caithfidh an cód oibriú i gceart ar bhealach éigin. Má fhéachann tú ar wakeup()
, ansin bíonn sé soiléir go marcálann sé ach an próiseas codlata mar réidh le forghníomhú, ionas go mbeidh sa todhchaí sched()
sheol sé i ndáiríre. Mar sin readp()
cúiseanna wakeup()
, baintear an glas, leagann sé IREAD
agus glaonna sleep(ip+2)
- seo go léir roimhe seo writep()
atosaíonn an timthriall.
Críochnaíonn sé seo an cur síos ar iompróirí sa séú eagrán. Cód simplí, iarmhairtí forleathana.
Xv6, eithne simplí cosúil le Unix
Chun an eithne a chruthú
Tá cur i bhfeidhm soiléir agus tuisceanach sa chód 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()
leagann sé amach staid an chuid eile den chur i bhfeidhm, lena n-áirítear na feidhmeanna piperead()
, pipewrite()
и pipeclose()
. Fíorghlao córais sys_pipe
is wrapper i bhfeidhm i
Linux 0.01
Is féidir cód foinse Linux 0.01 a fháil. Beidh sé oiliúnach chun staidéar a dhéanamh ar chur i bhfeidhm píblínte ina fs
/pipe.c
. Úsáideann sé seo inóid chun an phíblíne a léiriú, ach tá an phíblíne féin scríofa i C nua-aimseartha. Má d'oibrigh tú do bhealach a dhéanamh tríd an gcód 6ú eagrán, ní bheidh aon deacracht agat anseo. Seo mar a bhreathnaíonn an fheidhm 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;
}
Gan fiú breathnú ar na sainmhínithe struchtúir, is féidir leat a dhéanamh amach conas a úsáidtear an comhaireamh tagartha ionóid chun a sheiceáil cibé an dtagann oibríocht scríofa SIGPIPE
. Chomh maith le beart-ar-beart a oibriú, is furasta an fheidhm seo a chur i gcomparáid leis na smaointe a gcuirtear síos orthu thuas. Fiú loighic sleep_on
/wake_up
cuma chomh coimhthíoch sin.
Eithne Linux nua-aimseartha, FreeBSD, NetBSD, OpenBSD
Rith mé go tapa trí roinnt kernels nua-aimseartha. Níl aon cheann acu i bhfeidhm diosca níos mó (ní nach ionadh). Tá a fhorfheidhmiú féin ag Linux. Cé go bhfuil feidhmiúcháin bunaithe ar chód a scríobh John Dyson sna trí eithne BSD nua-aimseartha, thar na blianta tá siad tar éis éirí ró-dhifriúil óna chéile.
A léamh fs
/pipe.c
(ar Linux) nó sys
/kern
/sys_pipe.c
(ar *BSD), caithfidh sé fíor-thiomantas. Baineann cód an lae inniu le feidhmíocht agus tacaíocht do ghnéithe cosúil le veicteoir agus I/O asincrónach. Agus tá éagsúlacht mhór idir na sonraí maidir le leithdháileadh cuimhne, glais agus cumraíocht eithne. Ní hé seo an rud a theastaíonn ó choláistí le haghaidh cúrsa tosaigh ar chórais oibriúcháin.
Ar aon nós, bhí suim agam roinnt seanphatrúin a thochailt (cosúil le giniúint SIGPIPE
agus ar ais EPIPE
agus tú ag scríobh chuig píblíne dúnta) sna kernels nua-aimseartha éagsúla seo go léir. Is dócha nach bhfeicfidh mé ríomhaire PDP-11 sa saol fíor, ach tá go leor le foghlaim fós ó chód a scríobhadh blianta sular rugadh mé.
Alt a scríobh Divi Kapoor in 2011:
Foinse: will.com