Lesi sihloko sichaza ukusetshenziswa kwamapayipi ku-Unix kernel. Ngidumele ngandlela thize ngokuthi isihloko sakamuva esinesihloko esithi "
Sikhuluma ngani?
Amapayipi, "mhlawumbe okuqanjiwe okubaluleke kakhulu ku-Unix," ayisici esichazayo sefilosofi ye-Unix eyisisekelo yokuxhumanisa izinhlelo ezincane ndawonye, kanye nophawu olujwayelekile emugqeni womyalo:
$ echo hello | wc -c
6
Lokhu kusebenza kuncike ocingweni lwesistimu oluhlinzekwe yi-kernel pipe
, echazwe emakhasini amadokhumenti
Amapayipi ahlinzeka ngeshaneli engaqondile yokuxhumana phakathi kwezinqubo. Ipayipi linokufaka (ukuphela kokubhala) kanye nokuphumayo (ukufunda ekugcineni). Idatha ebhalwe okokufaka kwepayipi ingafundwa lapho kuphuma khona.
Iphayiphi idalwe kusetshenziswa ikholi
pipe(2)
, ebuyisela izichazi zefayela ezimbili: eyodwa ibhekisele kokokufaka kwepayipi, okwesibili kokuphumayo.
Umphumela wokulandela umkhondo osuka kumyalo ongenhla ubonisa ukudalwa kwepayipi nokugeleza kwedatha kulo lisuka kwinqubo eyodwa liye kwenye:
$ 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
Inqubo yomzali ibiza pipe()
ukuze uthole izichazi zefayela ezikhweziwe. Inqubo eyodwa yengane ibhalela isibambo esisodwa, futhi enye inqubo ifunda idatha efanayo kwesinye isibambo. Igobolondo lisebenzisa i-dup2 "ukuqamba kabusha" izichazi 3 no-4 ukuze lifane ne-stdin ne-stdout.
Ngaphandle kwamapayipi, igobolondo bekuzodingeka libhale umphumela wenqubo eyodwa efayeleni futhi liwudlulisele kwenye inqubo ukuze lifunde idatha evela kufayela. Ngenxa yalokho, sizomosha izinsiza ezengeziwe kanye nesikhala sediski. Kodwa-ke, amapayipi mahle hhayi kuphela ngoba akuvumela ukuthi ugweme ukusetshenziswa kwamafayela esikhashana:
Uma inqubo izama ukufunda epayipini elingenalutho ke
read(2)
izovimba kuze kube yilapho idatha isitholakala. Uma inqubo izama ukubhala emgqeni ogcwele, kewrite(2)
izovimba kuze kube yilapho idatha eyanele isifundiwe epayipini ukuze kubhalwe.
Njengemfuneko ye-POSIX, lokhu kuyimpahla ebalulekile: ukubhala kuphayiphi kuze kufike PIPE_BUF
amabhayithi (okungenani angu-512) kufanele abe yi-athomu ukuze izinqubo zikwazi ukuxhumana ngepayipi ngendlela amafayela avamile (anganikeli iziqinisekiso ezinjalo) angeke akwazi ngayo.
Uma usebenzisa ifayela elivamile, inqubo ingabhala konke okukhiphayo kulo futhi ikudlulisele kwenye inqubo. Noma izinqubo zingasebenza ngemodi ehambisana kakhulu, kusetshenziswa indlela yokubonisa yangaphandle (njenge-semaphore) ukuze zaziswe lapho ukubhala noma ukufunda kuqediwe. Amaconveyor asisindise kukho konke lokhu kuhlupheka.
Sifunani?
Ngizokuchaza ngamagama alula ukuze kube lula kuwe ukuthi ucabange ukuthi isidluliseli singasebenza kanjani. Uzodinga ukunikeza isigcinalwazi kanye nesimo esithile enkumbulweni. Uzodinga imisebenzi ukuze wengeze futhi ususe idatha ku-buffer. Uzodinga izindlela ezithile zokubiza imisebenzi ngesikhathi sokusebenza kokufunda nokubhala kuzichazi zefayela. Futhi uzodinga izingidi ukuze usebenzise ukuziphatha okukhethekile okuchazwe ngenhla.
Manje sesilungele ukuphenya ngekhodi yomthombo we-kernel ngaphansi kwesibani esikhanyayo ukuze siqinisekise noma siphikisane nemodeli yethu yengqondo engacacile. Kodwa hlala ukulungele okungalindelekile.
Sibheke kuphi?
Angazi ukuthi ikuphi ikhophi yami yencwadi edumile “
Ukuzulazula ezinqolobaneni ze-TUHS kufana nokuvakashela imnyuziyamu. Singabheka umlando wethu esabelana ngawo, futhi ngiyayihlonipha iminyaka eminingi yomzamo wokubuyisa konke lokhu okubalulekile kancane kancane kumakhasethi namaphrinti amadala. Futhi ngizazi kahle lezo zingcezu ezingakatholakali.
Ngemva kokwanelisa ilukuluku lethu lokwazi ngomlando wakudala wamaconveyor, singabheka izinkozo zesimanje ukuze siqhathanise.
Ngendlela, pipe
inombolo yocingo yesistimu 42 etafuleni sysent[]
. Ukuqondana?
Izinhlamvu ze-Unix zendabuko (1970-1974)
Angitholanga mikhondo pipe(2)
akukho phakathi
I-TUHS isho lokho
I-Unix 1973rd Edition kwakuyinguqulo yokugcina ene-kernel ebhalwe ngolimi lomhlangano, kodwa futhi inguqulo yokuqala enamapayipi. Ngo-XNUMX, kwenziwa umsebenzi wokuthuthukisa uhlelo lwesithathu, i-kernel yabhalwa kabusha ngo-C, kwase kuvela uhlelo lwesine lwe-Unix.
Omunye umfundi uthole ukuskena kombhalo lapho u-Doug McIlroy ehlongoze khona umbono “wokuxhuma izinhlelo ezifana nepayipi lengadi.”
Encwadini kaBrian Kernighan
Lapho i-Unix iphuma, ukuthakasela kwami ama-coroutines kwangiholela ekuceleni umbhali we-OS, u-Ken Thompson, ukuthi avumele idatha ebhalwe ngenqubo ukuthi ingahambi kuphela kudivayisi, kodwa futhi ikhiphe kwenye inqubo. UKen wanquma ukuthi kungenzeka. Kodwa-ke, njenge-minimalist, wayefuna yonke imisebenzi yesistimu idlale indima ebalulekile. Ingabe ukubhala ngokuqondile phakathi kwezinqubo kuyinzuzo enkulu ngempela ngokubhalela ifayela eliphakathi? Kwaba yilapho kuphela ngenza isiphakamiso esikhethekile ngegama elihehayo elithi “ipayipi” kanye nencazelo ye-syntax yokusebenzelana phakathi kwezinqubo lapho u-Ken agcina ebabaza khona: “Ngizokwenza!”
Futhi wenza. Ngobunye ubusuku obujabulisayo, u-Ken washintsha i-kernel negobolondo, walungisa izinhlelo ezimbalwa ezijwayelekile ukuze amise indlela abakwamukela ngayo okokufaka (okungase kuvele epayipini), waphinde washintsha amagama amafayela. Ngosuku olulandelayo, amapayipi aqala ukusetshenziswa kakhulu ekufakeni izicelo. Ekupheleni kwesonto, onobhala base bewasebenzisela ukuthumela amadokhumenti esuka kubacubunguli bamagama ukuya kumphrinta. Kamuva, u-Ken washintsha i-API yokuqala kanye ne-syntax yokugoqa ukusetshenziswa kwamapayipi ngezimiso ezihlanzekile, ezisetshenziswe kusukela ngaleso sikhathi.
Ngeshwa, ikhodi yomthombo yenguqulo yesithathu ye-Unix kernel ilahlekile. Futhi yize sinekhodi yomthombo we-kernel ebhalwe ku-C
Sinemibhalo yemibhalo pipe(2)
kukho kokubili ukukhishwa, ukuze uqale ngokusesha imibhalo pipe(2)
ibhalwe ngolimi lomhlangano futhi ibuyisela isichazi sefayela esisodwa kuphela, kodwa isivele ihlinzeka ngokusebenza okuyisisekelo okulindelekile:
Ucingo lwesistimu ipayipi idala indlela yokufaka/yokukhiphayo ebizwa ngokuthi ipayipi. Isichazi sefayela elibuyisiwe singasetshenziselwa ukufunda nokubhala imisebenzi. Uma okuthile kubhalwa epayipini, kufika kumabhayithi angu-504 edatha afakwa kubhafa, ngemva kwalokho inqubo yokubhala iyamiswa. Lapho kufundwa epayipini, idatha egcinwe ku-buffer iyasuswa.
Ngonyaka olandelayo i-kernel yayibhalwe kabusha ngo-C, futhi pipe(fildes)
»:
Ucingo lwesistimu ipayipi idala indlela yokufaka/yokukhiphayo ebizwa ngokuthi ipayipi. Izichazi zefayela ezibuyisiwe zingasetshenziswa emisebenzini yokufunda nokubhala. Uma okuthile kubhalwe epayipini, isibambo esibuyiswe ngo-r1 (resp. fildes[1]) siyasetshenziswa, sigcinwe kumabhayithi angu-4096 wedatha, ngemva kwalokho inqubo yokubhala iyamiswa. Uma ufunda epayipini, isibambo esibuyiselwe ku-r0 (resp. fildes[0]) sithatha idatha.
Kucatshangwa ukuthi uma ipayipi selichaziwe, izinqubo ezimbili (noma ngaphezulu) zokuxhumana (ezidalwe izingcingo ezilandelanayo ifom) izodlulisa idatha kusuka epayipini isebenzisa amakholi funda и bhala.
Igobolondo line-syntax yokuchaza uhlu lomugqa lwezinqubo ezixhunywe ngepayipi.
Izingcingo ezizofundwa epayipini elingenalutho (elingenayo idatha efakwe kubhafa) enomkhawulo owodwa kuphela (zonke izincazelo zefayela lokubhala zivaliwe) zibuyisela "ukuphela kwefayela". Izingcingo zokubhala esimweni esifanayo azinakwa.
Ekuqaleni
Uhlelo lwesithupha lwe-Unix (1975)
Ake siqale ukufunda ikhodi yomthombo ye-Unix
Iminyaka eminingi le ncwadi Lions bekuwukuphela kwedokhumenti ku-Unix kernel etholakala ngaphandle kweBell Labs. Nakuba ilayisense yohlelo lwesithupha yayivumela othisha ukuba basebenzise ikhodi yomthombo, ilayisense yohlelo lwesikhombisa yayingakufaki lokhu, ngakho le ncwadi yasakazwa njengamakhophi abhalwe ngomshini ngokungemthetho.
Namuhla ungathenga ukuphrintwa kabusha kwencwadi, ikhava ebonisa abafundi emshinini wokukopisha. Futhi sibonga uWarren Toomey (oqale iphrojekthi ye-TUHS) ungalanda
Eminyakeni engaphezu kwengu-15 edlule, ngathayipha ikhophi yekhodi yomthombo enikezwe kuyo Lions, ngoba angizange ngiyithande ikhwalithi yekhophi yami evela enambeni engaziwa yamanye amakhophi. I-TUHS ibingakatholakali futhi bengingenakho ukufinyelela emithonjeni emidala. Kodwa ngo-1988, ngathola itheyiphu endala enamathrekhi angu-9 equkethe isipele esivela kukhompyutha ye-PDP11. Kwakunzima ukusho ukuthi yayisebenza yini, kodwa kwakukhona isihlahla /usr/src/ esingaguquki lapho amafayela amaningi abhalwe ngonyaka we-1979, okwakubukeka sengathi kwakudala. Kwakuwuhlelo lwesikhombisa noma i-PWB ephuma kulo, njengoba ngangikholelwa.
Ngithathe okutholiwe njengesisekelo futhi ngahlela imithombo mathupha kuhlelo lwesithupha. Enye ikhodi yahlala ifana, kodwa enye kwadingeka ihlelwe kancane, iguqule ithokheni yesimanje ethi += iye kweyisidala =+. Ezinye izinto zamane zasuswa, futhi ezinye kwadingeka zibhalwe kabusha ngokuphelele, kodwa hhayi kakhulu.
Futhi namuhla singakwazi ukufunda ku-inthanethi ku-TUHS ikhodi yomthombo yohlelo lwesithupha kusuka
Ngendlela, ekuboneni kuqala, isici esiyinhloko sekhodi ye-C ngaphambi kwesikhathi sika-Kernighan no-Ritchie ubufushane. Akuvamile ukuthi ngikwazi ukufaka izingcezu zekhodi ngaphandle kokuhlela okubanzi ukuze zilingane nendawo yokubonisa ewumngcingo kusayithi lami.
Ekuqaleni
/*
* 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
Usayizi webhafa awukashintshi kusukela kuhlelo lwesine. Kodwa lapha siyabona, ngaphandle kwanoma yimiphi imibhalo yomphakathi, ukuthi amapayipi ake asebenzisa amafayela njengendawo yokugcina ikhophi!
Ngokuqondene namafayela e-LARG, ahambisana nawo
Nali ikholi yesistimu yangempela 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;
}
Amazwana achaza ngokucacile ukuthi kwenzekani lapha. Kodwa ukuqonda ikhodi akulula kangako, ngokwengxenye ngenxa yendlela "R0
и R1
amapharamitha wekholi yesistimu kanye namanani okubuyisela adluliswa.
Ake sizame nge
pipe()
kumele idlule R0
и R1
buyisela izinombolo ezichaza ifayela ukuze ufunde futhi ubhale. falloc()
ibuyisela isikhombisi esakhiweni sefayela, kodwa futhi "ibuyisela" nge u.u_ar0[R0]
kanye nesichazi sefayela. Okusho ukuthi, ikhodi igcina ngaphakathi r
isichazi sefayela sokufunda futhi sinikeze isichazi sefayela ukuze kubhalwe kuso ngqo u.u_ar0[R0]
ngemva kocingo lwesibili falloc()
.
Maka umkhosi FPIPE
, esiyibeka lapho sidala ipayipi, ilawula ukuziphatha komsebenzi
/*
* 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);
}
/* … */
}
Bese umsebenzi readp()
в pipe.c
ifunda idatha evela epayipini. Kodwa kungcono ukulandelela ukuqaliswa kusukela ekuqaleni writep()
. Nakulokhu, ikhodi isibe yinkimbinkimbi kakhulu ngenxa yezivumelwano zokuphasisana, kodwa eminye imininingwane ingashiywa.
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;
}
Sifuna ukubhala amabhayithi kokokufaka kwepayipi u.u_count
. Okokuqala sidinga ukukhiya i-inode (bona ngezansi plock
/prele
).
Bese sibheka ikhawunta yereferensi ye-inode. Uma nje zombili iziphetho zepayipi zihlala zivulekile, ikhawunta kufanele ilingane no-2. Sibamba isixhumanisi esisodwa (kusuka rp->f_inode
), ngakho-ke uma ikhawunta ingaphansi kuka-2, kufanele kusho ukuthi inqubo yokufunda ivale isiphetho sayo sepayipi. Ngamanye amazwi, sizama ukubhalela ipayipi elivaliwe, futhi leli iphutha. Ikhodi yephutha okokuqala ngqa EPIPE
kanye nesiginali SIGPIPE
yavela kuhlelo lwesithupha lwe-Unix.
Kodwa noma ngabe i-conveyor ivuliwe, ingase igcwale. Kulesi simo, sikhulula ukukhiya bese silala ngethemba lokuthi enye inqubo izofundwa epayipini futhi ikhulule isikhala esanele kuyo. Sesivukile, sibuyela ekuqaleni, siphinde sivale isikhiya bese siqala umjikelezo omusha wokuqopha.
Uma kunesikhala esanele samahhala epayipini, bese sibhala idatha kulo sisebenzisa i_size1
ku-inode (uma ipayipi lingenalutho lingalingana no-0) libonisa isiphetho sedatha eseliqukethwe kakade. Uma kunesikhala esanele sokurekhoda, singagcwalisa ipayipi ukusuka i_size1
ukuze PIPESIZ
. Bese sikhulula isikhiya bese sizama ukuvusa noma iyiphi inqubo elinde ukufundwa epayipini. Sibuyela ekuqaleni ukuze sibone ukuthi sikwazile yini ukubhala amabhayithi amaningi njengoba besidinga. Uma ihluleka, bese siqala umjikelezo omusha wokurekhoda.
Ngokuvamile ipharamitha i_mode
i-inode isetshenziselwa ukugcina izimvume r
, w
и x
. Kodwa endabeni yamapayipi, sibonisa ukuthi inqubo ethile ilinde ukubhala noma ukufundwa kusetshenziswa izingcezu IREAD
и IWRITE
ngokulandelana. Inqubo isetha ifulegi kanye nezingcingo sleep()
, futhi kulindeleke ukuthi kubangele enye inqubo esikhathini esizayo wakeup()
.
Umlingo wangempela uyenzeka sleep()
и wakeup()
. Zenziwa ku
/*
* 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) /* … */
Inqubo ebangela sleep()
esiteshini esithile, ingase ivuswe enye inqubo, eyobangela wakeup()
esiteshini esifanayo. writep()
и readp()
baqondise izenzo zabo ngokusebenzisa izingcingo ezinjalo ezibhanqiwe. Qaphela ukuthi pipe.c
njalo ubeka kuqala PPIPE
uma ebizwa sleep()
, kunjalo nje sleep()
ingase iphazanyiswe isignali.
Manje sinakho konke ukuqonda umsebenzi 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);
}
Ungase ukuthole kulula ukufunda lo msebenzi kusukela phansi kuya phezulu. Igatsha elithi "funda futhi ubuyisele" livame ukusetshenziswa uma kunedatha ethile epayipini. Kulokhu, sisebenzisa f_offset
ukufunda, bese ubuyekeza inani le-offset ehambisanayo.
Ekufundeni okulandelayo, ipayipi lizoba nalutho uma i-offset efundiwe isifinyelele i_size1
ku-inode. Sisetha kabusha indawo ku-0 futhi sizame ukuvusa noma iyiphi inqubo efuna ukubhalela ipayipi. Siyazi ukuthi uma i-conveyor igcwele, writep()
uzolala ip+1
. Futhi manje njengoba ipayipi lingenalutho, singalivusa ukuze siqale kabusha umjikelezo walo wokubhala.
Uma ungenalutho lokufunda, ke readp()
ingasetha ifulege IREAD
alale ip+2
. Siyazi ukuthi yini ezomvusa writep()
, uma ibhala idatha ethile epayipini.
Amazwana ku u
"Singabaphatha njengemisebenzi evamile ye-I/O ethatha ifayela, isikhundla, isigcinalwazi enkumbulweni, futhi sibale inani lamabhayithi okufunda noma ukubhala.
/*
* 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;
/* … */
Ngokuqondene nokuvinjwa “okungaguquguquki” ke readp()
и writep()
vimba i-inode baze baqede umsebenzi wabo noma bathole umphumela (okungukuthi, shayela wakeup
). plock()
и prele()
sebenza kalula: usebenzisa isethi ehlukile yezingcingo sleep
и wakeup
sivumele ukuthi sivuse noma iyiphi inqubo edinga ukukhiya esisanda kuwukhulula:
/*
* 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);
}
}
Ekuqaleni ngangingaqondi ukuthi kungani readp()
ayibangeli prele(ip)
ngaphambi kocingo wakeup(ip+1)
. Into yokuqala writep()
kubangela emjikelezweni wayo, lokhu plock(ip)
, okuholela ku-deadlock uma readp()
angikakayisusi ibhulokhi yami, ngakho-ke ngandlela thize ikhodi kufanele isebenze kahle. Uma ubheka wakeup()
, bese kuba sobala ukuthi ibeka kuphela inqubo yokulala njengoba ilungele ukukhishwa, ukuze esikhathini esizayo sched()
ngempela uyethula. Ngakho readp()
izimbangela wakeup()
, akhiphe ingidi, amise IREAD
kanye nezingcingo sleep(ip+2)
- konke lokhu ngaphambili writep()
iqala kabusha umjikelezo.
Lokhu kuqedela incazelo yamaconveyor kuhlelo lwesithupha. Ikhodi elula, imiphumela efinyelela kude.
I-Xv6, i-kernel elula efana ne-Unix
Ukwakha i-kernel
Ikhodi iqukethe ukuqaliswa okucacile nokucabangelayo 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()
ibeka isimo sokunye ukuqaliswa, okuhlanganisa imisebenzi piperead()
, pipewrite()
и pipeclose()
. Ucingo lwesistimu lwangempela sys_pipe
i-wrapper eyenziwe ngaphakathi
Linux 0.01
Ikhodi yomthombo ye-Linux 0.01 ingatholakala. Kuyoba okufundisayo ukufunda ukuqaliswa amapayipi e yakhe fs
/pipe.c
. Lokhu kusebenzisa i-inode ukumela ipayipi, kodwa ipayipi ngokwalo libhalwe ngesimanje C. Uma uye wasebenzisa ikhodi yesi-6, ngeke ube nenkinga lapha. Yile ndlela umsebenzi obukeka ngayo 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;
}
Ngaphandle kokubheka izincazelo zesakhiwo, ungathola ukuthi isibalo sereferensi ye-inode sisetshenziswa kanjani ukuze uhlole ukuthi umsebenzi wokubhala uyaphumela yini. SIGPIPE
. Ngaphezu kokusebenza kwe-byte-by-byte, lo msebenzi kulula ukuwuqhathanisa nemibono echazwe ngenhla. Ngisho logic sleep_on
/wake_up
akubukeki njengomfokazi.
Izihluthulelo ze-Linux zesimanje, i-FreeBSD, i-NetBSD, i-OpenBSD
Ngokushesha ngagijima phakathi kwezimbewu zesimanje. Akekho kubo osenokuqaliswa kwediski (akumangazi). I-Linux inokuqaliswa kwayo. Nakuba izikhwebu ezintathu zesimanje ze-BSD ziqukethe ukusetshenziswa okusekelwe kukhodi eyabhalwa u-John Dyson, ngokuhamba kweminyaka ziye zahluke kakhulu kwenye.
Uzofunda fs
/pipe.c
(ku-Linux) noma sys
/kern
/sys_pipe.c
(ku-*BSD), kudinga ukuzinikela kwangempela. Ikhodi yanamuhla imayelana nokusebenza nokusekelwa kwezici ezifana ne-vector kanye ne-asynchronous I/O. Futhi imininingwane yokwabiwa kwememori, izingidi nokucushwa kwe-kernel konke kuyahluka kakhulu. Lokhu akukhona okudingwa amakolishi ngezifundo zezinhlelo zokusebenza ezethulo.
Noma kunjalo, bengifuna ukumba amaphethini amadala (njengokukhiqiza SIGPIPE
futhi ubuye EPIPE
lapho ubhalela ipayipi elivaliwe) kuzo zonke lezi zinhlamvu zesimanje ezahlukene. Cishe ngeke ngibone ikhompuyutha ye-PDP-11 empilweni yangempela, kodwa kusekuningi okufanele ngikufunde kukhodi eyabhalwa eminyakeni eminingi ngaphambi kokuba ngizalwe.
I-athikili eyabhalwa ngu-Divi Kapoor ngo-2011:
Source: www.habr.com