Indlela amapayipi asetshenziswa ngayo ku-Unix

Indlela amapayipi asetshenziswa ngayo ku-Unix
Lesi sihloko sichaza ukusetshenziswa kwamapayipi ku-Unix kernel. Ngidumele ngandlela thize ngokuthi isihloko sakamuva esinesihloko esithi "Asebenza kanjani amapayipi e-Unix?"Umphumela hhayi mayelana nesakhiwo sangaphakathi. Ngaba nelukuluku lokwazi futhi ngamba emithonjeni emidala ukuze ngithole impendulo.

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 ipayipi(7) и ipayipi(2):

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, ke write(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 “Incwadi yamabhubesi"ngekhodi yomthombo ye-Unix 6, kodwa ngiyabonga I-Unix Heritage Society ungasesha ku-inthanethi ku- ikhodi yomthombo nezinguqulo ezindala ze-Unix.

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-PDP-7 Unix (Januwari 1970), noma ngo uhlelo lokuqala lwe-Unix (November 1971), noma kukhodi yomthombo engaphelele uhlelo lwesibili (June 1972).

I-TUHS isho lokho uhlelo lwesithathu lwe-Unix (NgoFebhuwari 1973) yaba inguqulo yokuqala enama-conveyors:

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.”

Indlela amapayipi asetshenziswa ngayo ku-Unix
Encwadini kaBrian KernighanUnix: Umlando kanye Nesikhumbuzo", emlandweni wokuvela kwabathumeli bempahla, lo mbhalo uyashiwo futhi: "... ulenga odongeni ehhovisi lami eBell Labs iminyaka engu-30." Lapha ingxoxo noMcIlroy, nenye indaba evela Umsebenzi kaMcIlroy, owabhalwa ngo-2014:

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 uhlelo lwesine, ekhishwe ngoNovemba 1973, kodwa yaphuma ezinyangeni ezimbalwa ngaphambi kokukhululwa okusemthethweni futhi ayiqukethe ukuqaliswa kwepayipi. Kuyihlazo ukuthi ikhodi yomthombo yalo msebenzi we-Unix oyinganekwane ilahleke, mhlawumbe unomphela.

Sinemibhalo yemibhalo pipe(2) kukho kokubili ukukhishwa, ukuze uqale ngokusesha imibhalo uhlelo lwesithathu (emagameni athile, adwetshelwe “ngesandla”, iyunithi yezinhlamvu yamagama ^H, elandelwa i-underscore!). Lesi sibonelo-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 ipayipi(2) kuhlelo lwesine ithole ukubukeka kwayo kwesimanje nge-prototype "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 ukusetshenziswa kwamapayipi alondoloziwe lihlobene kuya kuhlelo lwesihlanu lwe-Unix (June 1974), kodwa icishe ifane naleyo eyavela ekukhululweni okulandelayo. Amazwana asanda kwengezwa, ngakho-ke ungakwazi ukweqa uhlelo lwesihlanu.

Uhlelo lwesithupha lwe-Unix (1975)

Ake siqale ukufunda ikhodi yomthombo ye-Unix uhlelo lwesithupha (May 1975). Sibonga kakhulu Lions kulula kakhulu ukuyithola kunemithombo yezinguqulo zangaphambili:

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 Ifayela le-PDF elinekhodi yomthombo yohlelo lwesithupha. Ngifuna ukukunikeza umbono wokuthi ungakanani umzamo owenziwe ekudaleni ifayela:

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 ingobo yomlando, lapho uDennis Ritchie abe nesandla khona.

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 /usr/sys/ken/pipe.c kukhona ukuphawula okuchazayo (futhi yebo, kukhona okunye /usr/sys/dmr):

/*
 * 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 ifulegi le-inode LARG, esetshenziswa "i-algorithm yokukhuluma enkulu" ukuze icutshungulwe amabhlogo angaqondile ukusekela izinhlelo ezinkulu zamafayela. Njengoba uKen ethe kungcono ukungawasebenzisi, ngizokwamukela ngenjabulo izwi lakhe ngakho.

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 "hlela umsebenzisi u» kanye namarejista R0 и R1 amapharamitha wekholi yesistimu kanye namanani okubuyisela adluliswa.

Ake sizame nge ialloc() faka idiski inode (isibambo senkomba), nangosizo falloc() - beka ezimbili enkumbulweni ifayela. Uma konke kuhamba kahle, sizosetha amafulegi ukuze sihlonze lawa mafayela njengeziphetho ezimbili zepayipi, siwakhomba ku-inode efanayo (isibalo sayo sereferensi sizosethwa sibe ngu-2), bese simaka i-inode njengeshintshiwe futhi isetshenziswa. Naka izicelo ngifakile() ezindleleni zephutha zokunciphisa isibalo sereferensi ku-inode entsha.

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 rdwr() ku-sys2.cukubiza izinqubo ezithile ze-I/O:

/*
 * 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 bhala(). Ipharamitha 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 slp.c, umthombo wamazwana adumile athi “Akulindelekile ukuthi uqonde lokhu”. Ngenhlanhla, akudingeki siqonde ikhodi, vele ubheke amazwana athile:

/*
 * 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 funda() sifunda idatha eningi njengoba itholakala kusukela kule yamanje 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 readi() and writei() izokusiza ukuthi uqonde ukuthi esikhundleni sokudlulisa amapharamitha nge "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.

Uhlelo lwesikhombisa lwe-Unix (Januwari 1979) kwaba ukukhululwa okusha okukhulu (eminyakeni emine kamuva) okwethula izinhlelo zokusebenza eziningi ezintsha nezici ze-kernel. Iphinde yaba nezinguquko ezibalulekile maqondana nokusetshenziswa kohlobo lokulingisa, izinyunyana nezikhombi ezithayiphiwe ezakhiweni. Nokho ikhodi yokudlulisa cishe ezingashintshile. Singeqa lolu hlobo.

I-Xv6, i-kernel elula efana ne-Unix

Ukwakha i-kernel Xv6 ithonywe uhlelo lwesithupha lwe-Unix, kodwa ibhalwe ngesimanje C ukuze isebenze kumaphrosesa we-x86. Ikhodi ifundeka kalula futhi iyaqondakala. Futhi, ngokungafani nemithombo ye-Unix ene-TUHS, ungayihlanganisa, uyilungise, futhi uyiqhube kokunye ngaphandle kwe-PDP 11/70. Ngakho-ke, le kernel isetshenziswa kabanzi emanyuvesi njengezinto zokufundisa ezinhlelweni zokusebenza. Imithombo ziku-Github.

Ikhodi iqukethe ukuqaliswa okucacile nokucabangelayo ipayipi.c, isekelwa isigcinalwazi kumemori esikhundleni se-inode kudiski. Lapha nginikeza kuphela incazelo "yepayipi lesakhiwo" kanye nomsebenzi 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 sysfile.c. Ngincoma ukufunda ikhodi yakhe yonke. Ubunkimbinkimbi busezingeni lekhodi yomthombo yenguqulo yesithupha, kodwa kulula kakhulu futhi kujabulise kakhulu ukuyifunda.

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:I-Linux Kernel Implementation of Pipes and FIFOs" inikeza ukubuka konke kokuthi amapayipi (asasebenza) asebenza kanjani ku-Linux. A ukuzinikela kwakamuva ku-Linux ikhombisa imodeli yephayiphi yokusebenzisana, amakhono ayo angaphezu kwawamafayela esikhashana; futhi ikhombisa ukuthi amapayipi asuke kude kangakanani kusukela "ekukhiyweni okudala kakhulu" kwenguqulo yesithupha ye-Unix kernel.

Source: www.habr.com

Engeza amazwana