Tha an artaigil seo a’ toirt cunntas air buileachadh pìoban ann an kernel Unix. Bha mi car diombach gun robh artaigil o chionn ghoirid leis an tiotal "
Cò mu dheidhinn a tha thu a ’bruidhinn?
Is dòcha gur e pìoban “an innleachd as cudromaiche ann an Unix” - feart sònraichte den fheallsanachd bhunaiteach aig Unix a thaobh a bhith a’ cur phrògraman beaga ri chèile, agus an sluagh-ghairm air a bheil sinn eòlach:
$ echo hello | wc -c
6
Tha an gnìomh seo an urra ris a’ ghairm siostam a tha air a sholarachadh le kernel pipe
, a tha air a mhìneachadh air na duilleagan sgrìobhainnean
Bidh pìoban a 'toirt seachad sianal aon-shligheach airson conaltradh eadar-phròiseas. Tha cuir a-steach aig an loidhne-phìoban (crìoch sgrìobhaidh) agus toradh (deireadh leughaidh). Faodar dàta a chaidh a sgrìobhadh gu cuir a-steach na loidhne-phìoban a leughadh aig an toradh.
Tha an loidhne-phìoban air a chruthachadh le bhith a 'gairm
pipe(2)
, a thilleas dà thuairisgeul faidhle: tha aon a’ toirt iomradh air cuir a-steach na loidhne-phìoban, an dàrna fear air an toradh.
Tha an toradh lorg bhon àithne gu h-àrd a’ sealltainn cruthachadh loidhne-phìoban agus sruthadh dàta troimhe bho aon phròiseas gu 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
Bidh am pròiseas pàrant a 'gairm pipe()
gus tuairisgeulan faidhle ceangailte. Bidh aon phròiseas pàiste a’ sgrìobhadh gu aon tuairisgeul agus pròiseas eile a’ leughadh an aon dàta bho thuairisgeul eile. Tha an t-slige “ag ath-ainmeachadh” tuairisgeulan 2 agus 3 le dup4 gus stdin agus stdout a mhaidseadh.
Às aonais pìoban, dh'fheumadh an t-slige toradh aon phròiseas a sgrìobhadh gu faidhle agus a phìobadh gu pròiseas eile gus an dàta bhon fhaidhle a leughadh. Mar thoradh air an sin, bhiodh sinn a’ caitheamh barrachd ghoireasan agus àite diosc. Ach, tha pìoban math airson barrachd air dìreach faidhlichean sealach a sheachnadh:
Ma dh'fheuchas pròiseas ri leughadh bho loidhne-phìoban falamh, an uairsin
read(2)
bacadh gus am bi an dàta ri fhaighinn. Ma tha pròiseas a 'feuchainn ri sgrìobhadh gu loidhne-phìoban slàn, an uairsinwrite(2)
bacadh gus am bi dàta gu leòr air a leughadh bhon loidhne-phìoban gus an sgrìobhadh a chrìochnachadh.
Coltach ris an riatanas POSIX, is e seilbh chudromach a tha seo: sgrìobhadh chun loidhne-phìoban suas gu PIPE_BUF
feumaidh bytes (co-dhiù 512) a bhith atamach gus an urrainn do phròiseasan conaltradh le chèile tron loidhne-phìoban ann an dòigh nach urrainn do fhaidhlichean àbhaisteach (nach eil a’ toirt seachad geallaidhean mar sin).
Le faidhle cunbhalach, faodaidh pròiseas a thoraidhean gu lèir a sgrìobhadh thuige agus a chuir air adhart gu pròiseas eile. No faodaidh pròiseasan obrachadh ann am modh cruaidh co-shìnte, a’ cleachdadh inneal comharran bhon taobh a-muigh (mar semaphore) gus innse dha chèile mu bhith a’ crìochnachadh sgrìobhadh no leughadh. Sàbhalaidh luchd-giùlain sinn bhon duilgheadas seo gu lèir.
Dè tha sinn a’ sireadh?
Mìnichidh mi air mo chorragan gus a dhèanamh nas fhasa dhut smaoineachadh air mar as urrainn do inneal-giùlain obrachadh. Feumaidh tu bufair agus cuid de staid a riarachadh mar chuimhne. Bidh feum agad air gnìomhan gus dàta a chur ris agus a thoirt air falbh bhon bhufair. Bidh feum agad air goireas airson gnìomhan a ghairm rè obair leughaidh is sgrìobhaidh air tuairisgeulan faidhle. Agus tha feum air glasan gus an giùlan sònraichte a tha air a mhìneachadh gu h-àrd a chur an gnìomh.
Tha sinn a-nis deiseil airson còd stòr an kernel a cheasnachadh fo sholas lampa soilleir gus ar modal inntinn neo-shoilleir a dhearbhadh no a dhearbhadh. Ach bi an-còmhnaidh deiseil airson an fheadhainn ris nach robh dùil.
Càit a bheil sinn a’ coimhead?
Chan eil fios agam càite a bheil an leth-bhreac agam den leabhar ainmeil.
Tha siubhal tro thasglannan TUHS coltach ri tadhal air taigh-tasgaidh. Faodaidh sinn coimhead air ar n-eachdraidh cho-roinnte agus tha spèis agam do na bliadhnaichean de dh’ oidhirp gus an stuth seo gu lèir fhaighinn air ais mean air mhean bho sheann chèiseagan agus clò-bhualaidhean. Agus tha mi gu math mothachail air na criomagan sin a tha fhathast a dhìth.
Às deidh dhuinn ar feòrachas a shàsachadh mu sheann eachdraidh nam pìoban, is urrainn dhuinn coimhead air coraichean an latha an-diugh airson coimeas a dhèanamh.
Air an t-slighe, pipe
tha àireamh gairm siostam 42 sa chlàr sysent[]
. Co-thuiteamas?
Craobhan Unix traidiseanta (1970-1974)
Cha do lorg mi lorg sam bith pipe(2)
ni a-steach
Tha TUHS ag agairt sin
B 'e an treas deasachadh de Unix an dreach mu dheireadh le kernel sgrìobhte ann an assembler, ach cuideachd a' chiad dreach le pìoban. Ann an 1973, bha obair a 'dol air adhart gus an treas deasachadh a leasachadh, chaidh an kernel ath-sgrìobhadh ann an C, agus mar sin rugadh an ceathramh deasachadh de Unix.
Lorg aon leughadair scan de sgrìobhainn anns an do mhol Doug McIlroy am beachd “prògraman a cheangal mar hose gàrraidh.”
Anns an leabhar aig Brian Kernighan
Nuair a nochd Unix, thug mo dhealas airson coroutines orm iarraidh air ùghdar an OS, Ken Thompson, leigeil le dàta a chaidh a sgrìobhadh gu pròiseas air choreigin a dhol chan ann a-mhàin chun inneal, ach cuideachd chun t-slighe a-mach gu pròiseas eile. Cho-dhùin Coinneach gun robh e comasach. Ach, mar minimalist, bha e airson gum biodh àite cudromach aig a h-uile feart siostam. A bheil sgrìobhadh dìreach eadar pròiseasan na bhuannachd mhòr dha-rìribh seach sgrìobhadh gu faidhle eadar-mheadhanach? Agus dìreach nuair a rinn mi moladh sònraichte leis an ainm tarraingeach “pìob-loidhne” agus tuairisgeul air co-chòrdadh eadar-obrachadh phròiseasan, thuirt Ken mu dheireadh: “Nì mi e!”.
Agus rinn. Aon fheasgar uamhasach, dh’ atharraich Ken an kernel agus an t-slige, shuidhich e grunn phrògraman àbhaisteach gus gnàthachadh a dhèanamh air mar a ghabhas iad ri cuir a-steach (a dh’ fhaodadh tighinn bho loidhne-phìoban), agus dh’ atharraich e ainmean faidhle. An ath latha, chaidh pìoban a chleachdadh gu farsaing ann an tagraidhean. Ro dheireadh na seachdain, chleachd na rùnairean iad airson sgrìobhainnean a chuir bho luchd-deasachaidh fhaclan chun chlò-bhualadair. Beagan nas fhaide air adhart, chuir Ken an àite an API agus an co-chòrdadh tùsail airson cleachdadh pìoban a chòmhdach le gnàthasan nas glaine a chaidh a chleachdadh bhon uair sin.
Gu mì-fhortanach, chaidh an còd tùsail airson an treas deasachadh Unix kernel air chall. Agus ged a tha an còd stòr kernel againn sgrìobhte ann an C
Tha teacsa sgrìobhainnean againn airson pipe(2)
bhon dà fhoillseachadh, gus an urrainn dhut tòiseachadh le bhith a’ sgrùdadh nan sgrìobhainnean pipe(2)
air a sgrìobhadh ann an assembler agus a’ tilleadh dìreach aon tuairisgeul faidhle, ach mar-thà a’ toirt seachad am prìomh ghnìomhachd ris a bheil dùil:
Call siostam pìoba a’ cruthachadh inneal I/O ris an canar loidhne-phìoban. Faodar an tuairisgeul faidhle a chaidh a thilleadh a chleachdadh airson obair leughaidh is sgrìobhaidh. Nuair a thèid rudeigin a sgrìobhadh chun loidhne-phìoban, bidh e a ’bufair suas ri 504 bytes de dhàta, às deidh sin tha am pròiseas sgrìobhaidh air a chuir dheth. Nuair a leughas tu bhon loidhne-phìoban, thèid an dàta bufair a thoirt.
Ron ath bhliadhna, bha an kernel air ath-sgrìobhadh ann an C, agus pipe(fildes)
"
Call siostam pìoba a’ cruthachadh uidheamachd I/O ris an canar loidhne-phìoban. Faodar na tuairisgeulan faidhle a chaidh a thilleadh a chleachdadh ann an obair leughaidh is sgrìobhaidh. Nuair a thèid rudeigin a sgrìobhadh chun loidhne-phìoban, thathas a’ cleachdadh an tuairisgeul air a thilleadh ann an r1 (rep. fildes [1]), air a bhufair suas gu 4096 bytes de dhàta, agus às deidh sin tha am pròiseas sgrìobhaidh air a chuir dheth. Nuair a leughas tu bhon loidhne-phìoban, thill an tuairisgeul gu r0 (rep. fildes[0]) an dàta.
Thathas a’ gabhail ris, aon uair ‘s gu bheil loidhne-phìoban air a mhìneachadh, dà phròiseas eadar-obrachaidh (no barrachd) (air an cruthachadh le fiosan às deidh sin Fork) a’ dol seachad air dàta bhon loidhne-phìoban a’ cleachdadh fiosan leughadh и sgrìobhadh.
Tha co-chòrdadh aig an t-slige airson sreath sreathach de phròiseasan a tha ceangailte tro loidhne-phìoban a mhìneachadh.
Bidh gairmean airson leughadh bho loidhne-phìoban falamh (anns nach eil dàta bufair) aig nach eil ach aon cheann (sgrìobh tuairisgeulan faidhle dùinte) a’ tilleadh “deireadh faidhle”. Thathas a’ seachnadh gairmean sgrìobhte ann an suidheachadh coltach ris.
Na bu tràithe
Unix san t-siathamh deasachadh (1975)
A’ tòiseachadh a’ leughadh còd stòr Unix
Airson iomadh bliadhna an leabhar air a Lions an aon sgrìobhainn air an kernel Unix a bha ri fhaighinn taobh a-muigh Bell Labs. Ged a leig cead an t-siathamh deasachadh le tidsearan an còd stòr aca a chleachdadh, cha do chuir cead an t-seachdamh deasachadh a-mach an comas seo, agus mar sin chaidh an leabhar a sgaoileadh ann an lethbhric clò-sgrìobhaidh mì-laghail.
An-diugh faodaidh tu leth-bhreac ath-chlò-bhualaidh den leabhar a cheannach, agus tha an còmhdach a’ sealltainn oileanaich aig an neach-copaidh. Agus taing dha Warren Toomey (a thòisich am pròiseact TUHS), faodaidh tu luchdachadh sìos
O chionn còrr air 15 bliadhna, thapaidh mi leth-bhreac den chòd stòr a chaidh a thoirt seachad Lionsoir cha bu toil leam càileachd mo leth-bhreac bho àireamh neo-aithnichte de leth-bhreacan eile. Cha robh TUHS ann fhathast, agus cha robh cothrom agam air na seann stòran. Ach ann an 1988 lorg mi seann teip le 9 slighean aig an robh cùl-taic bho choimpiutair PDP11. Bha e duilich faighinn a-mach an obraich e, ach bha craobh slàn / usr/src/ anns an robh a’ mhòr-chuid de na faidhlichean air an comharrachadh 1979, a bha eadhon an uairsin a’ coimhead aosta. B’ e an seachdamh deasachadh a bh’ ann, no derivative PWB, shaoil mi.
Ghabh mi an lorg mar bhunait agus dheasaich mi na stòran le làimh gu staid an t-siathamh deasachadh. Dh'fhuirich pàirt den chòd mar a bha e, dh'fheumadh pàirt a bhith air a dheasachadh beagan, ag atharrachadh an tòcan ùr-nodha += gu seann-fhasanta =+. Bha rudeigin dìreach air a dhubhadh às, agus dh'fheumadh rudeigin a bhith air ath-sgrìobhadh gu tur, ach cha robh cus.
Agus an-diugh is urrainn dhuinn còd tùsail an t-siathamh deasachadh de TUHS a leughadh air-loidhne
Co-dhiù, aig a’ chiad sealladh, is e prìomh fheart a’ chòd-C ro àm Kernighan agus Ritchie a giorrad. Chan ann tric a bhios e comasach dhomh criomagan de chòd a chuir a-steach gun deasachadh farsaing gus a bhith iomchaidh airson raon taisbeanaidh caran cumhang air an làrach agam.
Aig an toiseach
/*
* 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
Chan eil meud bufair air atharrachadh bhon cheathramh deasachadh. Ach an seo chì sinn, às aonais sgrìobhainnean poblach sam bith, gun robh pìoban uaireigin a’ cleachdadh faidhlichean mar stòradh air ais!
A thaobh faidhlichean LARG, tha iad a’ freagairt
Seo an fhìor ghairm siostam 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;
}
Tha am beachd a’ toirt cunntas soilleir air na tha a’ tachairt an seo. Ach chan eil e cho furasta an còd a thuigsinn, gu ìre air sgàth mar a “R0
и R1
thèid paramadairean gairm siostam agus luachan tilleadh seachad.
Feuchaidh sinn le
pipe()
air sgàth R0
и R1
thoir air ais àireamhan tuairisgeul faidhle airson leughadh agus sgrìobhadh. falloc()
a 'tilleadh puing gu structar faidhle, ach cuideachd "tilleadh" tro u.u_ar0[R0]
agus tuairisgeul faidhle. Is e sin, tha an còd air a stòradh a-steach r
tuairisgeul faidhle airson leughadh agus sònraichidh e tuairisgeul airson sgrìobhadh dìreach bho u.u_ar0[R0]
às deidh an dàrna gairm falloc()
.
Didòmhnaich FPIPE
, a shuidhich sinn nuair a bhios sinn a 'cruthachadh an loidhne-phìoban, a' cumail smachd air giùlan a 'ghnìomh
/*
* 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);
}
/* … */
}
An uairsin an gnìomh readp()
в pipe.c
a’ leughadh dàta bhon loidhne-phìoban. Ach tha e nas fheàrr am buileachadh a lorg a’ tòiseachadh bho writep()
. A-rithist, tha an còd air fàs nas toinnte air sgàth cho sònraichte sa tha an argamaid a’ dol seachad air a’ chùmhnant, ach faodar cuid de mhion-fhiosrachadh fhàgail air falbh.
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;
}
Tha sinn airson bytes a sgrìobhadh gu cuir a-steach na loidhne-phìoban u.u_count
. An toiseach feumaidh sinn an inode a ghlasadh (faic gu h-ìosal plock
/prele
).
An uairsin nì sinn sgrùdadh air an àireamh iomraidh inode. Cho fad 's a bhios dà cheann na loidhne-phìoban fosgailte, bu chòir gum biodh an cuntair 2. Cumaidh sinn air adhart gu aon cheangal (bho rp->f_inode
), mar sin ma tha an cuntair nas lugha na 2, bu chòir seo a bhith a’ ciallachadh gu bheil am pròiseas leughaidh air deireadh na loidhne-phìoban a dhùnadh. Ann am faclan eile, tha sinn a 'feuchainn ri sgrìobhadh gu loidhne-phìoban dùinte, rud a tha na mhearachd. Còd na mearachd a ' chiad EPIPE
agus comharradh SIGPIPE
nochdadh anns an t-siathamh deasachadh de Unix.
Ach eadhon ma tha an inneal-giùlain fosgailte, faodaidh e a bhith làn. Anns a 'chùis seo, bidh sinn a' leigeil a-mach a 'ghlas agus a' dol a chadal an dòchas gun leugh pròiseas eile bhon loidhne-phìoban agus gun saor sinn àite gu leòr ann. Nuair a dhùisgeas sinn, tillidh sinn chun toiseach, croch a’ ghlas a-rithist agus tòisichidh sinn cearcall sgrìobhaidh ùr.
Ma tha àite gu leòr an-asgaidh san loidhne-phìoban, bidh sinn a’ sgrìobhadh dàta thuige a’ cleachdadh i_size1
faodaidh an inode'a (le loidhne-phìoban falamh a bhith co-ionann ri 0) puingean gu deireadh an dàta a tha ann mu thràth. Ma tha àite gu leòr ann airson sgrìobhadh, is urrainn dhuinn an loidhne-phìoban a lìonadh bho i_size1
gu PIPESIZ
. An uairsin bidh sinn a 'leigeil a-mach a' ghlas agus a 'feuchainn ri pròiseas sam bith a tha a' feitheamh ri leughadh bhon loidhne-phìoban a dhùsgadh. Bidh sinn a’ dol air ais chun toiseach feuch an deach againn air na h-uimhir de bytes a sgrìobhadh ’s a bha a dhìth oirnn. Mura h-eil, an uairsin tòisichidh sinn cearcall clàraidh ùr.
Mar as trice paramadair i_mode
inode air a chleachdadh gus ceadan a stòradh r
, w
и x
. Ach a thaobh loidhnichean-phìoban, bidh sinn a’ comharrachadh gu bheil pròiseas air choireigin a’ feitheamh ri sgrìobhadh no leughadh a’ cleachdadh pìosan IREAD
и IWRITE
fa leth. Bidh am pròiseas a 'suidheachadh a' bhratach agus na gairmean sleep()
, agus thathar an dùil gun tig pròiseas air choireigin eile san àm ri teachd wakeup()
.
Bidh an fhìor dhraoidheachd a’ tachairt ann an sleep()
и wakeup()
. Tha iad air an cur an gnìomh ann an
/*
* 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) /* … */
Am pròiseas a tha a 'gairm sleep()
airson sianal sònraichte, faodar a dhùsgadh nas fhaide air adhart le pròiseas eile, a dh’ ainmicheas wakeup()
airson an aon sianal. writep()
и readp()
co-òrdanachadh an gnìomhan tro na gairmean càraideach sin. thoir an aire sin pipe.c
prìomhachas an-còmhnaidh PPIPE
nuair a chaidh a ghairm sleep()
, mar sin uile sleep()
faodar stad a chuir air le comharra.
A-nis tha a h-uile dad againn airson an gnìomh a thuigsinn 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);
}
Is dòcha gum bi e nas fhasa dhut an gnìomh seo a leughadh bho bhonn gu mullach. Mar as trice bidh am meur "leugh is tilleadh" air a chleachdadh nuair a tha beagan dàta san loidhne-phìoban. Anns a 'chùis seo, bidh sinn a' cleachdadh f_offset
leugh, agus an uairsin ùraich luach an chothromachadh co-fhreagarrach.
Air leughaidhean às deidh sin, bidh an loidhne-phìoban falamh ma tha an tomhas leughaidh air ruighinn i_size1
aig an inode. Bidh sinn ag ath-shuidheachadh an t-suidheachaidh gu 0 agus a’ feuchainn ri pròiseas sam bith a dhùsgadh a tha airson sgrìobhadh chun loidhne-phìoban. Tha fios againn nuair a bhios an inneal-giùlain làn, writep()
tuiteam na chadal ip+1
. Agus a-nis gu bheil an loidhne-phìoban falamh, is urrainn dhuinn a dhùsgadh gus a chearcall sgrìobhaidh ath-thòiseachadh.
Mura h-eil dad ri leughadh, an uairsin readp()
urrainn bratach a shuidheachadh IREAD
agus tuit 'na chadal ip+2
. Tha fios againn dè a dhùisgeas e writep()
nuair a sgrìobhas e beagan dàta chun loidhne-phìoban.
Beachdan air u
» is urrainn dhuinn an làimhseachadh mar ghnìomhan I/O cunbhalach a bhios a’ gabhail faidhle, suidheachadh, bufair mar chuimhneachan, agus a’ cunntadh àireamh nam bytes ri leughadh no sgrìobhadh.
/*
* 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;
/* … */
A thaobh bacadh "glèidhidh", mar sin readp()
и writep()
glas inodes gus an crìochnaich iad no gus am faigh iad toradh (ie call wakeup
). plock()
и prele()
obraich gu sìmplidh: a’ cleachdadh seata gairmean eadar-dhealaichte sleep
и wakeup
leig leinn pròiseas sam bith a dhùsgadh a dh’ fheumas a’ ghlas a tha sinn dìreach air a leigeil ma sgaoil:
/*
* 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);
}
}
An toiseach cha robh mi a 'tuigsinn carson readp()
chan eil ag adhbhrachadh prele(ip)
ron ghairm wakeup(ip+1)
. A' chiad rud writep()
glaodh na lùib, seo plock(ip)
, a thig gu crìch ma tha readp()
chan eil e air a bhloc a thoirt air falbh fhathast, agus mar sin feumaidh an còd obrachadh ceart dòigh air choireigin. Ma sheallas tu air wakeup()
, bidh e soilleir gu bheil e a-mhàin a 'comharrachadh a' phròiseas cadail mar deiseil airson a chur gu bàs, mar sin san àm ri teachd sched()
dha-rìribh a chuir air bhog e. Mar sin readp()
adhbharan wakeup()
, fuasgladh, suidhich IREAD
agus gairmean sleep(ip+2)
- seo uile roimhe writep()
ath-thòisich an cearcall.
Tha seo a’ cur crìoch air an tuairisgeul air pìoban san t-siathamh deasachadh. Còd sìmplidh, buaidhean farsaing.
Xv6, kernel sìmplidh coltach ri Unix
Gus niuclas a chruthachadh
Tha buileachadh soilleir agus smaoineachail anns a’ 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()
a 'suidheachadh staid a' chòrr den bhuileachadh, a tha a 'gabhail a-steach gnìomhan piperead()
, pipewrite()
и pipeclose()
. Dìreach gairm an t-siostam sys_pipe
tha e na phasgan air a chuir an gnìomh
Linux 0.01
Gheibh thu an còd tùsail airson Linux 0.01. Bidh e feumail sgrùdadh a dhèanamh air buileachadh nan loidhnichean-phìoban na fs
/pipe.c
. An seo, thathas a' cleachdadh inode airson an loidhne-phìoban a riochdachadh, ach tha an loidhne-phìoban fhèin sgrìobhte ann an C an latha an-diugh. Ma tha thu air do shlighe tron chòd siathamh deasachadh, cha bhith duilgheadas sam bith agad an seo. Seo mar a tha an gnìomh coltach 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;
}
Fiù ‘s gun a bhith a’ coimhead air na mìneachaidhean structarail, faodaidh tu obrachadh a-mach mar a tha an cunntas iomraidh inode air a chleachdadh gus faighinn a-mach a bheil gnìomhachd sgrìobhaidh a’ leantainn SIGPIPE
. A bharrachd air obair byte-by-byte, tha an gnìomh seo furasta a choimeas ris na beachdan gu h-àrd. Fiù 's loidsig sleep_on
/wake_up
chan eil e a’ coimhead cho coimheach.
Kernels Linux ùr-nodha, FreeBSD, NetBSD, OpenBSD
Chaidh mi gu sgiobalta thairis air cuid de kernels an latha an-diugh. Chan eil buileachadh stèidhichte air diosc aig gin dhiubh mu thràth (chan eil e na iongnadh). Tha a bhuileachadh fhèin aig Linux. Agus ged a tha buileachadh anns na trì kernels BSD ùr-nodha stèidhichte air còd a chaidh a sgrìobhadh le John Dyson, thar nam bliadhnaichean tha iad air fàs ro eadar-dhealaichte bho chèile.
A leughadh fs
/pipe.c
(air Linux) no sys
/kern
/sys_pipe.c
(air * BSD), feumaidh e fìor dhealas. Tha coileanadh agus taic airson feartan leithid vectar agus I/O asyncronach cudromach ann an còd an-diugh. Agus tha mion-fhiosrachadh mu riarachadh cuimhne, glasan, agus rèiteachadh kernel uile ag atharrachadh gu mòr. Chan e seo a dh’ fheumas oilthighean airson cùrsa tòiseachaidh air siostaman obrachaidh.
Ann an suidheachadh sam bith, bha e inntinneach dhomh beagan seann phàtranan a lorg (mar eisimpleir, gineadh SIGPIPE
agus tilleadh EPIPE
nuair a bhios tu a’ sgrìobhadh gu loidhne-phìoban dùinte) anns na kernels sin uile, cho eadar-dhealaichte, ùr-nodha. Is dòcha nach fhaic mi coimpiutair PDP-11 beò gu bràth, ach tha tòrr ri ionnsachadh fhathast bhon chòd a chaidh a sgrìobhadh beagan bhliadhnaichean mus do rugadh mi.
Air a sgrìobhadh le Divi Kapoor ann an 2011, tha an artaigil "
Source: www.habr.com