Kini nga artikulo naghulagway sa pagpatuman sa mga pipeline sa Unix kernel. Medyo nasagmuyo ako nga ang usa ka bag-o nga artikulo nga giulohan "
Unsa man ang atong gihisgutan?
Ang mga linya sa tubo mao ang "tingali ang labing hinungdanon nga imbensyon sa Unix" - usa ka piho nga bahin sa nagpahiping pilosopiya sa Unix sa paghiusa sa gagmay nga mga programa, ug ang pamilyar nga slogan sa command-line:
$ echo hello | wc -c
6
Kini nga pag-andar nagdepende sa tawag sa sistema nga gihatag sa kernel pipe
, nga gihulagway sa mga panid sa dokumentasyon
Ang mga pipeline naghatag ug one-way nga channel para sa inter-process nga komunikasyon. Ang pipeline adunay input (pagsulat sa katapusan) ug usa ka output (pagbasa sa katapusan). Ang datos nga gisulat sa input sa pipeline mabasa sa output.
Ang pipeline gihimo pinaagi sa pagtawag
pipe(2)
, nga nagbalik sa duha ka mga deskriptor sa file: ang usa nagtumong sa input sa pipeline, ang ikaduha sa output.
Ang pagsubay sa output gikan sa sugo sa ibabaw nagpakita sa paghimo sa usa ka pipeline ug ang dagan sa datos pinaagi niini gikan sa usa ka proseso ngadto sa lain:
$ 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
Ang proseso sa ginikanan nagtawag pipe()
aron makakuha og gilakip nga mga deskriptor sa file. Ang usa ka proseso sa bata nagsulat sa usa ka deskriptor ug ang lain nga proseso nagbasa sa parehas nga datos gikan sa lain nga deskriptor. Ang kabhang "nag-ngalan" sa mga deskriptor 2 ug 3 nga adunay dup4 aron ipares ang stdin ug stdout.
Kung walay mga pipeline, ang kabhang kinahanglan nga isulat ang output sa usa ka proseso ngadto sa usa ka file ug i-pipe kini ngadto sa laing proseso aron mabasa ang datos gikan sa file. Ingon usa ka sangputanan, mag-usik kami og daghang mga kapanguhaan ug espasyo sa disk. Bisan pa, ang mga pipeline labi pa sa paglikay sa temporaryo nga mga file:
Kung ang usa ka proseso mosulay sa pagbasa gikan sa usa ka walay sulod nga pipeline, nan
read(2)
mo-block hangtod nga magamit ang datos. Kung ang usa ka proseso mosulay sa pagsulat sa usa ka bug-os nga pipeline, nanwrite(2)
mag-block hangtod nga nabasa ang igo nga datos gikan sa pipeline aron makompleto ang pagsulat.
Sama sa kinahanglanon sa POSIX, kini usa ka hinungdanon nga kabtangan: pagsulat sa pipeline hangtod sa PIPE_BUF
bytes (labing menos 512) kinahanglang atomic aron ang mga proseso makakomunikar sa usag usa pinaagi sa pipeline sa paagi nga dili mahimo sa normal nga mga file (nga wala maghatag sa maong mga garantiya).
Uban sa usa ka regular nga file, ang usa ka proseso makasulat sa tanan nga mga output niini ug ipasa kini sa lain nga proseso. O ang mga proseso mahimong molihok sa usa ka hard parallel mode, gamit ang eksternal nga mekanismo sa pagsenyas (sama sa usa ka semaphore) aron sa pagpahibalo sa usag usa mahitungod sa pagkompleto sa usa ka pagsulat o pagbasa. Ang mga conveyor nagluwas kanamo gikan niining tanan nga kahasol.
Unsa ang atong gipangita?
Akong ipasabut sa akong mga tudlo aron mas sayon alang kanimo ang paghanduraw kung unsa ang mahimo sa usa ka conveyor. Kinahanglan nimo nga maggahin og buffer ug pipila ka estado sa memorya. Kinahanglan nimo ang mga function aron madugang ug makuha ang data gikan sa buffer. Kinahanglan nimo ang pipila ka pasilidad sa pagtawag sa mga function sa panahon sa pagbasa ug pagsulat nga mga operasyon sa mga deskriptor sa file. Ug gikinahanglan ang mga kandado aron mapatuman ang espesyal nga kinaiya nga gihulagway sa ibabaw.
Andam na kami karon sa pagsukitsukit sa source code sa kernel ubos sa hayag nga lamplight aron kumpirmahon o mapanghimakak ang among dili klaro nga mental model. Apan pag-andam kanunay sa wala damha.
Asa ta mangita?
Wala ko kahibalo kung asa nahimutang ang akong kopya sa sikat nga libro.
Ang pagsuroy-suroy sa mga archive sa TUHS sama sa pagbisita sa usa ka museyo. Mahimo natong tan-awon ang among gipaambit nga kasaysayan ug ako adunay pagtahod sa mga tuig nga paningkamot aron mabawi ang tanan niini nga materyal sa hinay-hinay gikan sa daan nga mga cassette ug mga printout. Ug nahibal-an gyud nako ang mga tipik nga wala pa.
Natagbaw ang among pagkamausisaon bahin sa karaan nga kasaysayan sa mga pipeline, mahimo naton tan-awon ang mga modernong cores alang sa pagtandi.
Hinuon, pipe
mao ang system call number 42 sa lamesa sysent[]
. Sulagma?
Tradisyonal nga Unix kernels (1970–1974)
Wala koy nakit-an nga bakas pipe(2)
ni sa
Giangkon kini sa TUHS
Ang ikatulo nga edisyon sa Unix mao ang katapusan nga bersyon nga adunay usa ka kernel nga gisulat sa assembler, apan usab ang una nga bersyon nga adunay mga pipeline. Sa panahon sa 1973, gisugdan ang pagtrabaho aron mapaayo ang ikatulo nga edisyon, ang kernel gisulat pag-usab sa C, ug sa ingon natawo ang ikaupat nga edisyon sa Unix.
Usa ka magbabasa nakit-an ang usa ka pag-scan sa usa ka dokumento diin gisugyot ni Doug McIlroy ang ideya sa "pagkonekta sa mga programa sama sa usa ka hose sa tanaman."
Sa libro ni Brian Kernighan
Sa dihang mitungha ang Unix, ang akong gugma sa mga coroutine nakapahimo kanako nga mangutana sa tagsulat sa OS, si Ken Thompson, nga tugotan ang mga datos nga gisulat sa pipila ka proseso nga moadto dili lamang sa device, kondili ngadto usab sa exit ngadto sa laing proseso. Naghunahuna si Ken nga posible. Bisan pa, ingon usa ka minimalist, gusto niya nga ang matag bahin sa sistema adunay hinungdanon nga papel. Ang direkta ba nga pagsulat tali sa mga proseso usa ka dako nga bentaha kaysa pagsulat sa usa ka intermediate file? Ug sa diha nga naghimo ako usa ka piho nga sugyot nga adunay madanihon nga ngalan nga "pipeline" ug usa ka paghulagway sa syntax sa interaksyon sa mga proseso, si Ken sa katapusan mipatugbaw: "Buhaton ko kini!".
Ug gibuhat. Usa ka makalilisang nga gabii, giusab ni Ken ang kernel ug shell, giayo ang daghang mga standard nga programa aron ma-standardize kung giunsa nila pagdawat ang input (nga mahimo’g gikan sa usa ka pipeline), ug giusab ang mga filename. Pagkasunod adlaw, ang mga pipeline kaylap nga gigamit sa mga aplikasyon. Sa kataposan sa semana, gigamit sila sa mga sekretaryo sa pagpadalag mga dokumento gikan sa mga tigproseso sa pulong ngadto sa tig-imprenta. Sa wala madugay, gipulihan ni Ken ang orihinal nga API ug syntax alang sa pagputos sa paggamit sa mga pipeline nga adunay mas limpyo nga mga kombensiyon nga gigamit sukad.
Ikasubo, ang source code alang sa ikatulo nga edisyon nga Unix kernel nawala. Ug bisan kung kami adunay kernel source code nga gisulat sa C
Naa miy documentation text para pipe(2)
gikan sa duha ka pagpagawas, aron makasugod ka pinaagi sa pagpangita sa dokumentasyon pipe(2)
gisulat sa assembler ug nagbalik lamang sa usa ka file descriptor, apan naghatag na sa gipaabot nga core functionality:
Sistema nga tawag tubo naghimo ug mekanismo sa I/O nga gitawag ug pipeline. Ang gibalik nga deskriptor sa file mahimong magamit alang sa pagbasa ug pagsulat nga mga operasyon. Kung adunay gisulat sa pipeline, kini nag-buffer hangtod sa 504 bytes nga datos, pagkahuman gisuspinde ang proseso sa pagsulat. Kung nagbasa gikan sa pipeline, gikuha ang buffered data.
Pagkasunod tuig, ang kernel nasulat na usab sa C, ug pipe(fildes)
»:
Sistema nga tawag tubo naghimo ug mekanismo sa I/O nga gitawag ug pipeline. Ang gibalik nga mga deskriptor sa file mahimong magamit sa pagbasa ug pagsulat nga mga operasyon. Kung adunay gisulat sa pipeline, gigamit ang descriptor nga gibalik sa r1 (resp. fildes [1]), gi-buffer hangtod sa 4096 bytes nga datos, pagkahuman gisuspinde ang proseso sa pagsulat. Kung nagbasa gikan sa pipeline, ang deskriptor mibalik sa r0 (resp. fildes [0]) nagkuha sa datos.
Gituohan nga sa higayon nga ang usa ka pipeline gihubit, duha (o daghan pa) nga mga proseso sa interaksyon (gibuhat pinaagi sa sunod nga mga pag-ampo. Tinidor) ipasa ang datos gikan sa pipeline gamit ang mga tawag basaha и isulat.
Ang kabhang adunay usa ka syntax alang sa pagtino sa usa ka linear array sa mga proseso nga konektado pinaagi sa usa ka pipeline.
Ang mga tawag sa pagbasa gikan sa usa ka walay sulod nga pipeline (walay buffered data) nga adunay usa lamang ka tumoy (tanan isulat ang mga deskriptor sa file nga sirado) ibalik ang "katapusan sa file". Ang pagsulat sa mga tawag sa susamang sitwasyon wala tagda.
pinakauna
Unix Ika-unom nga Edisyon (1975)
Pagsugod sa pagbasa sa Unix source code
Sulod sa daghang mga tuig ang libro Mga leon mao lamang ang dokumento sa Unix kernel nga anaa sa gawas sa Bell Labs. Bisan tuod ang lisensya sa ikaunom nga edisyon nagtugot sa mga magtutudlo sa paggamit sa source code niini, ang ikapitong edisyon nga lisensya wala maglakip niini nga posibilidad, mao nga ang libro giapod-apod sa ilegal nga mga kopya nga gi-type.
Karon mahimo ka makapalit usa ka kopya sa libro nga gipatik pag-usab, nga ang hapin niini naghulagway sa mga estudyante sa copier. Ug salamat sa Warren Toomey (nga nagsugod sa proyekto sa TUHS), mahimo nimong i-download
Kapin sa 15 ka tuig ang milabay, nag-type ko og kopya sa source code nga gihatag Mga leontungod kay dili ko ganahan sa kalidad sa akong kopya gikan sa wala mailhi nga gidaghanon sa ubang mga kopya. Wala pa ang TUHS, ug wala akoy access sa daan nga mga tinubdan. Apan niadtong 1988 nakakita kog daan nga teyp nga adunay 9 ka tracks nga dunay backup gikan sa PDP11 nga kompyuter. Lisud mahibal-an kung kini nagtrabaho, apan adunay usa ka buo nga /usr/src/ nga kahoy diin kadaghanan sa mga file gimarkahan nga 1979, nga bisan kaniadto tan-awon nga karaan. Ikapito kadto nga edisyon, o usa ka PWB derivative, sa akong hunahuna.
Gikuha nako ang pagpangita isip basehan ug gi-edit sa mano-mano ang mga tinubdan ngadto sa estado sa ikaunom nga edisyon. Ang bahin sa kodigo nagpabilin nga pareho, ang bahin kinahanglan nga usbon gamay, usbon ang modernong token += ngadto sa karaan nga =+. Adunay yano nga gitangtang, ug adunay kinahanglan nga hingpit nga isulat pag-usab, apan dili sobra.
Ug karon atong mabasa online sa TUHS ang source code sa ikaunom nga edisyon sa
Pinaagi sa dalan, sa unang pagtan-aw, ang nag-unang bahin sa C-code sa wala pa ang panahon sa Kernighan ug Ritchie mao ang kamubo. Dili kasagaran nga ako makahimo sa pagsal-ot sa mga snippet sa code nga walay halapad nga pag-edit aron mohaum sa medyo pig-ot nga display nga lugar sa akong site.
Sa sinugdanan
/*
* 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
Ang gidak-on sa buffer wala mausab sukad sa ikaupat nga edisyon. Apan dinhi atong makita, nga walay bisan unsa nga publikong dokumentasyon, nga ang mga pipeline kaniadto migamit sa mga file isip fallback storage!
Sama sa alang sa LARG nga mga file, sila katumbas sa
Ania ang tinuod nga tawag sa sistema 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;
}
Ang komento tin-aw nga naghulagway kung unsa ang nahitabo dinhi. Apan dili sayon sabton ang kodigo, bahin tungod sa kung giunsa "R0
и R1
gipasa ang mga parameter sa tawag sa sistema ug mga kantidad sa pagbalik.
Atong sulayan uban
pipe()
tungod pinaagi sa R0
и R1
ibalik ang mga numero sa deskriptor sa file alang sa pagbasa ug pagsulat. falloc()
nagbalik sa usa ka pointer sa usa ka istruktura sa file, apan usab "mibalik" pinaagi sa u.u_ar0[R0]
ug usa ka file descriptor. Kana mao, ang code gitipigan sa r
file descriptor para sa pagbasa ug assign sa usa ka descriptor alang sa pagsulat direkta gikan sa u.u_ar0[R0]
pagkahuman sa ikaduhang tawag falloc()
.
Flag FPIPE
, nga among gibutang sa paghimo sa pipeline, nagkontrol sa kinaiya sa function
/*
* 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);
}
/* … */
}
Unya ang function readp()
в pipe.c
nagbasa sa datos gikan sa pipeline. Apan mas maayo nga masubay ang pagpatuman sugod sa writep()
. Sa makausa pa, ang kodigo nahimong mas komplikado tungod sa kinaiya sa argumento nga nagpasa sa kombensiyon, apan ang pipila ka mga detalye mahimong matangtang.
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;
}
Gusto namon nga isulat ang mga byte sa input sa pipeline u.u_count
. Una kinahanglan natong i-lock ang inode (tan-awa sa ubos plock
/prele
).
Dayon among susihon ang ihap sa reference sa inode. Hangtud nga ang duha ka tumoy sa pipeline magpabilin nga bukas, ang counter kinahanglan nga 2. Nagkupot kami sa usa ka link (gikan sa rp->f_inode
), busa kung ang counter dili mubu sa 2, nan kini nagpasabut nga ang proseso sa pagbasa nagsira sa katapusan sa pipeline. Sa laing pagkasulti, naningkamot kami sa pagsulat sa usa ka sirado nga pipeline, nga usa ka sayup. Unang error code EPIPE
ug signal SIGPIPE
nagpakita sa ikaunom nga edisyon sa Unix.
Apan bisan kung bukas ang conveyor, mahimo kini puno. Sa kini nga kaso, gibuhian namo ang kandado ug matulog sa paglaum nga ang laing proseso magbasa gikan sa pipeline ug magpagawas og igo nga luna niini. Inigmata nato, mobalik kita sa sinugdanan, ibitay pag-usab ang kandado ug magsugod og bag-ong siklo sa pagsulat.
Kung adunay igo nga libre nga wanang sa pipeline, nan isulat namon ang datos niini gamit i_size1
ang inode'a (nga adunay walay sulod nga pipeline mahimong katumbas sa 0) nagpunting sa katapusan sa datos nga anaa na niini. Kung adunay igong luna nga isulat, mahimo natong pun-on ang pipeline gikan sa i_size1
sa PIPESIZ
. Dayon gibuhian namo ang kandado ug gisulayan nga pukawon ang bisan unsang proseso nga naghulat nga basahon gikan sa pipeline. Mobalik kami sa sinugdanan aron tan-awon kung nakahimo ba kami sa pagsulat sa daghang mga byte nga among gikinahanglan. Kung dili, nan magsugod kami usa ka bag-ong siklo sa pagrekord.
Kasagaran nga parameter i_mode
inode gigamit sa pagtipig sa mga permiso r
, w
и x
. Apan sa kaso sa mga pipeline, kami nagsenyas nga ang pipila ka proseso naghulat alang sa pagsulat o pagbasa gamit ang mga piraso IREAD
и IWRITE
matag usa. Ang proseso nagtakda sa bandila ug mga tawag sleep()
, ug gilauman nga sa umaabot adunay laing proseso nga motawag wakeup()
.
Ang tinuod nga salamangka mahitabo sa sleep()
и wakeup()
. Gipatuman sila sa
/*
* 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) /* … */
Ang proseso nga nagtawag sleep()
alang sa usa ka partikular nga channel, mahimong sa ulahi pukawon sa lain nga proseso, nga motawag wakeup()
para sa parehas nga channel. writep()
и readp()
pag-coordinate sa ilang mga aksyon pinaagi sa maong gipares nga mga tawag. timan-i nga pipe.c
unahon kanunay PPIPE
sa dihang gitawag sleep()
, so tanan sleep()
mahimong mabalda sa usa ka signal.
Karon naa na kami sa tanan aron masabtan ang function 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);
}
Mahimong mas sayon nimo nga basahon kini nga function gikan sa ubos ngadto sa ibabaw. Ang sanga nga "basaha ug ibalik" kasagarang gigamit kung adunay pipila ka datos sa pipeline. Sa kini nga kaso, gigamit namon f_offset
basaha, ug dayon i-update ang bili sa katugbang nga offset.
Sa sunod nga mga pagbasa, ang pipeline mahimong walay sulod kung ang read offset naabot na i_size1
sa inode. Gi-reset namon ang posisyon sa 0 ug gisulayan nga pukawon ang bisan unsang proseso nga gusto isulat sa pipeline. Nahibal-an namon nga kung puno na ang conveyor, writep()
matulog sa ip+1
. Ug karon nga walay sulod ang pipeline, mahimo natong pukawon kini aron ipadayon ang siklo sa pagsulat niini.
Kung walay mabasa, nan readp()
makabutang ug bandera IREAD
ug matulog sa ip+2
. Nahibal-an namon kung unsa ang makapukaw kaniya writep()
sa diha nga kini nagsulat sa pipila ka mga data ngadto sa pipeline.
Mga komento sa u
»Mahimo nato silang trataron sama sa regular nga I/O functions nga nagkuha ug file, posisyon, buffer sa memorya, ug ihap ang gidaghanon sa bytes nga basahon o isulat.
/*
* 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;
/* … */
Sama sa "konserbatibo" nga pag-block, unya readp()
и writep()
i-lock ang mga inode hangtod mahuman o makakuha usa ka resulta (ie tawag wakeup
). plock()
и prele()
yano nga pagtrabaho: gamit ang lainlaing hugpong sa mga tawag sleep
и wakeup
tugoti kami nga pukawon ang bisan unsang proseso nga nanginahanglan sa kandado nga among gipagawas:
/*
* 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);
}
}
Sa una wala ko kasabot ngano readp()
dili hinungdan prele(ip)
sa wala pa ang tawag wakeup(ip+1)
. Ang unang butang writep()
nagtawag sa iyang loop, kini plock(ip)
, nga moresulta sa deadlock kon readp()
wala pa matangtang ang block niini, mao nga ang code kinahanglan nga molihok sa husto. Kung tan-awon nimo wakeup()
, nahimong tin-aw nga kini nagtimaan lamang sa proseso sa pagkatulog ingon nga andam na alang sa pagpatay, aron sa umaabot sched()
gilusad gyud ni. Busa readp()
hinungdan wakeup()
, nag-abli, nagtakda IREAD
ug mga tawag sleep(ip+2)
- kining tanan kaniadto writep()
gi-restart ang cycle.
Nakompleto niini ang paghulagway sa mga pipeline sa ikaunom nga edisyon. Yano nga code, layo nga mga implikasyon.
Xv6, usa ka yano nga kernel nga sama sa Unix
Sa paghimo sa usa ka nucleus
Ang code naglangkob sa usa ka tin-aw ug mahunahunaon nga pagpatuman 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()
nagtakda sa kahimtang sa tanan nga nahabilin nga pagpatuman, nga naglakip sa mga gimbuhaton piperead()
, pipewrite()
и pipeclose()
. Ang aktwal nga tawag sa sistema sys_pipe
usa ka wrapper nga gipatuman sa
Linux 0.01
Makita nimo ang source code para sa Linux 0.01. Kini mahimong matulon-anon sa pagtuon sa pagpatuman sa mga pipelines sa iyang fs
/pipe.c
. Dinhi, usa ka inode ang gigamit sa pagrepresentar sa pipeline, apan ang pipeline mismo gisulat sa modernong C. Kung imong gi-hack ang imong agianan sa ikaunom nga edisyon nga code, wala ka'y problema dinhi. Kini ang hitsura sa function 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;
}
Bisan kung wala’y pagtan-aw sa mga kahulugan sa istruktura, mahimo nimong mahibal-an kung giunsa ang pag-ihap sa reference sa inode gigamit aron masusi kung ang usa ka operasyon sa pagsulat moresulta sa SIGPIPE
. Dugang pa sa byte-by-byte nga trabaho, kini nga function sayon nga itandi sa mga ideya sa ibabaw. Bisan lohika sleep_on
/wake_up
murag dili alien.
Modernong Linux Kernels, FreeBSD, NetBSD, OpenBSD
Dali nakong gisusi ang pipila ka modernong mga lugas. Walay usa kanila nga adunay usa ka disk-based nga pagpatuman (dili ikatingala). Ang Linux adunay kaugalingong pagpatuman. Ug bisan kung ang tulo ka modernong BSD kernels adunay mga implementasyon base sa code nga gisulat ni John Dyson, sa paglabay sa mga tuig sila nahimong lahi kaayo sa usag usa.
Sa pagbasa fs
/pipe.c
(sa Linux) o sys
/kern
/sys_pipe.c
(sa *BSD), nagkinahanglan kini og tinuod nga dedikasyon. Ang performance ug suporta alang sa mga feature sama sa vector ug asynchronous I/O importante sa code karon. Ug ang mga detalye sa alokasyon sa memorya, mga kandado, ug pag-configure sa kernel tanan magkalainlain kaayo. Dili kini ang gikinahanglan sa mga unibersidad alang sa pasiuna nga kurso sa mga operating system.
Sa bisan unsa nga kaso, kini makapaikag alang kanako sa pagkalot sa pipila ka daan nga mga sumbanan (pananglitan, pagmugna SIGPIPE
ug balik EPIPE
kung nagsulat sa usa ka sirado nga pipeline) sa tanan niini, lahi kaayo, modernong mga kernel. Tingali dili gyud ko makakita og PDP-11 nga kompyuter nga buhi, apan daghan pa ang makat-unan gikan sa code nga gisulat pipila ka tuig sa wala pa ako matawo.
Gisulat ni Divi Kapoor sa 2011, ang artikulo nga "
Source: www.habr.com