Iphunyezwa njani imibhobho kwi-Unix

Iphunyezwa njani imibhobho kwi-Unix
Eli nqaku lichaza ukuphunyezwa kwemibhobho kwi-Unix kernel. Ndiphoxekile kukuba inqaku lamva nje elinesihloko esithi "Isebenza njani imibhobho kwi-Unix?"ijikisiwe hayi malunga nolwakhiwo lwangaphakathi. Ndaba nomdla ndaza ndamba kwimithombo emidala ukuze ndifumane impendulo.

Sithetha ngantoni?

Imibhobho, β€œmhlawumbi eyona nto iyilwayo ibalulekileyo kwi-Unix,” luphawu oluchazayo lwentanda-bulumko ye-Unix yokudibanisa iinkqubo ezincinci kunye, kunye nophawu oluqhelekileyo kumgca womyalelo:

$ echo hello | wc -c
6

Oku kusebenza kuxhomekeke kwindlela yokufowuna ebonelelwe ngekernel pipe, echazwe kumaphepha amaxwebhu umbhobho(7) ΠΈ umbhobho(2):

Imibhobho ibonelela ngomjelo ongaqhelekanga wonxibelelwano lwenkqubo. Umbhobho unegalelo (ukubhala ekupheleni) kunye nesiphumo (ukufunda ekupheleni). Idatha ebhaliweyo kwigalelo lombhobho inokufundwa kwisiphumo.

Umbhobho wenziwa ngokusebenzisa umnxeba pipe(2), ebuyisela iinkcazo ezimbini zefayile: enye ibhekisela kwigalelo lombhobho, okwesibini kwimveliso.

Isiphumo sokulandelela kulo myalelo ungasentla sibonisa ukwenziwa kombhobho kunye nokuhamba kwedatha kuyo ukusuka kwinkqubo enye ukuya 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

Inkqubo yomzali iminxeba pipe()ukufumana iinkcazelo zefayile ezinyusiweyo. Inkqubo enye yomntwana ibhalela kwisibambo esinye, kwaye enye inkqubo ifunda idatha efanayo ukusuka kwesinye isiphatho. Iqokobhe lisebenzisa i-dup2 "ukuthiya ngokutsha" izichazi 3 kunye no-4 ukutshatisa i-stdin kunye ne-stdout.

Ngaphandle kwemibhobho, iqokobhe kuya kufuneka ibhale imveliso yenkqubo enye kwifayile kwaye iyigqithisele kwenye inkqubo yokufunda idatha kwifayile. Ngenxa yoko, siya kuchitha izibonelelo ezininzi kunye nendawo yediski. Nangona kunjalo, imibhobho ilungile hayi kuphela ngenxa yokuba ikuvumela ukuba uthintele ukusetyenziswa kweefayile zethutyana:

Ukuba inkqubo izama ukufunda kumbhobho ongenanto ngoko read(2) iya kuvala de idatha ifumaneke. Ukuba inkqubo izama ukubhala kumbhobho opheleleyo, ngoko write(2) iya kuvala kude kube idatha eyaneleyo ifundiwe kumbhobho ukwenza ukubhala.

Njengemfuno yePOSIX, le yipropati ebalulekileyo: ukubhala kumbhobho ukuya kuthi ga PIPE_BUF iibytes (ubuncinci ziyi-512) kufuneka zibe yi-atomic ukwenzela ukuba iinkqubo zikwazi ukunxibelelana enye kwenye ngombhobho ngendlela yokuba iifayili eziqhelekileyo (ezinganikeli ziqinisekiso ezinjalo) zingenako.

Xa usebenzisa ifayile eqhelekileyo, inkqubo inokubhala yonke imveliso yayo kuyo kwaye iyigqithisele kwenye inkqubo. Okanye iinkqubo zingasebenza kwimodi ehambelana kakhulu, usebenzisa indlela yokubonisa yangaphandle (njenge-semaphore) ukwazisa omnye nomnye xa ukubhala okanye ukufunda kugqityiwe. Abathumeli basisindise kuyo yonke le ngxaki.

Sijonge ntoni?

Ndiza kuyicacisa ngamagama alula ukuze kube lula kuwe ukuba ucinge ukuba umqhubi wemoto unokusebenza njani. Kuya kufuneka unikeze isithinteli kunye nesimo esithile kwinkumbulo. Uya kufuna imisebenzi yokongeza kunye nokususa idatha kwi-buffer. Uya kufuna ezinye iindlela zokubiza imisebenzi ngexesha lokufunda nokubhala imisebenzi kwiinkcazo zefayile. Kwaye uya kufuna izitshixo ukuphumeza ukuziphatha okukhethekileyo okuchazwe ngasentla.

Ngoku sikulungele ukuhlolisisa ikhowudi yomthombo we-kernel phantsi kwesibane esikhanyayo ukuqinisekisa okanye ukuphikisa imodeli yethu yengqondo engacacanga. Kodwa hlala uzilungiselele izinto ongazilindelanga.

Sijonge phi?

Andazi ukuba iphi ikopi yam yencwadi edumileyo "Incwadi yeengonyama"nge Unix 6 ikhowudi yomthombo, kodwa enkosi I-Unix Heritage Society unokukhangela kwi-intanethi ikhowudi yonikezo iinguqulelo ezindala ze Unix.

Ukuzulazula kwindawo yogcino lwe-TUHS kufana nokutyelela imyuziyam. Singajonga kwimbali yethu ekwabelwana ngayo, kwaye ndinentlonipho yeminyaka emininzi yomzamo wokubuyisela yonke le nto kancinci kancinci kwiikhasethi ezindala kunye noshicilelo. Kwaye ndizazi kakuhle ezo ziqwenga zingekhoyo.

Emva kokuba sanelise umnqweno wethu wokwazi ngembali yamandulo yabahambisi, sinokujonga iinkozo zale mihla ukuze sithelekise.

Ngendlela, pipe yinkqubo yokufowuna inombolo 42 kwitheyibhile sysent[]. Ngebhaqo?

Iinkozo ze-Unix zesiNtu (1970-1974)

Khange ndifumane umkhondo pipe(2) okanye phakathi PDP-7 Unix (ngoJanuwari 1970), okanye ngo uhlelo lokuqala lwe Unix (Novemba 1971), okanye kwikhowudi yomthombo engaphelelanga uhlelo lwesibini (Juni 1972).

I-TUHS ithi uhlelo lwesithathu lwe Unix (ngoFebruwari 1973) yaba yinguqulelo yokuqala kunye nabahambisi:

I-Unix 1973rd Edition yayiyinguqulelo yokugqibela ene-kernel ebhalwe ngolwimi lwendibano, kodwa kunye nenguqulelo yokuqala enemibhobho. Ebudeni bowe-XNUMX, kwenziwa umsebenzi wokuphucula uhlelo lwesithathu, ikernel yaphinda yabhalwa ngoC, kwaza kwavela uhlelo lwesine lweUnix.

Omnye umfundi ufumene iskena soxwebhu apho uDoug McIlroy ecebise ngombono "wokudibanisa iinkqubo njengethumbu legadi."

Iphunyezwa njani imibhobho kwi-Unix
Kwincwadi kaBrian KernighanUnix: Imbali kunye neMemori", kwimbali yokuvela kwabahambisi, olu xwebhu lukhankanywe kwakhona: "... luxhonywe eludongeni kwiofisi yam eBell Labs iminyaka engama-30." Apha udliwano-ndlebe noMcIlroy, kunye nelinye ibali elivela Umsebenzi kaMcIlroy, obhalwe kwi-2014:

Xa i-Unix yaphuma, ukuthanda kwam ii-coroutines kwandikhokelela ekubeni ndibuze umbhali we-OS, u-Ken Thompson, ukuba avumele idatha ebhaliweyo kwinkqubo ukuba ihambe kungekhona nje kwisixhobo, kodwa kunye nokuphuma kwenye inkqubo. UKen wagqiba kwelokuba kunokwenzeka. Nangona kunjalo, njenge-minimalist, wayefuna ukuba wonke umsebenzi wenkqubo udlale indima ebalulekileyo. Ngaba ukubhala ngokuthe ngqo phakathi kweenkqubo ngokwenene kuyinzuzo enkulu ngaphezu kokubhalela ifayile ephakathi? Kwaba kuphela xa ndenza isindululo esikhethekileyo ngegama elinomtsalane elithi "umbhobho" kunye nenkcazo ye-syntax yokusebenzisana phakathi kweenkqubo apho uKen wadanduluka wathi: "Ndiya kuyenza!"

Kwaye wenza. Ngobunye ubusuku obumnandi, u-Ken watshintsha i-kernel kunye neqokobhe, walungisa iinkqubo ezininzi ezisemgangathweni ukuze balungelelanise indlela abalamkela ngayo igalelo (elinokuvela kumbhobho), kwaye watshintsha namagama eefayile. Ngosuku olulandelayo, imibhobho yaqala ukusetyenziswa kakhulu kwizicelo. Ekupheleni kweveki, oonobhala babewasebenzisela ukuthumela amaxwebhu asuka kwiprosesa yamagama ukuya kumshicileli. Kancinane kamva, uKen wathatha indawo ye-API yoqobo kunye ne-syntax yokusonga ukusetyenziswa kwemibhobho ngeendibano zococeko, eziye zasetyenziswa ukusukela ngoko.

Ngelishwa, ikhowudi yemvelaphi yohlelo lwesithathu Unix kernel ilahlekile. Kwaye nangona sinekhowudi yomthombo we-kernel ebhalwe kwi-C uhlelo lwesine, ekhutshwe ngoNovemba 1973, kodwa yaphuma kwiinyanga ezininzi ngaphambi kokukhululwa ngokusemthethweni kwaye ayiquki ukuphunyezwa kwemibhobho. Kulihlazo ukuba ikhowudi yomthombo walo msebenzi we-Unix ulahlekile, mhlawumbi ngonaphakade.

Sinamaxwebhu okubhaliweyo e pipe(2) kokubini ukhupho, ngoko ungaqala ngokuphendla uxwebhu uhlelo lwesithathu (kumagama athile, kukrwelelwe umgca β€œngesandla”, uluhlu lwamagama afanayo ^H, lulandelwa ngumgca ngaphantsi!). Le proto-pipe(2) ibhalwe ngolwimi lwendibano kwaye ibuyisela ingcaciso yefayile enye kuphela, kodwa sele ibonelela ngomsebenzi ongundoqo olindelekileyo:

Umnxeba wenkqubo umbhobho yenza igalelo/imveliso indlela ebizwa ngokuba ngumbhobho. Inkcazo yefayile ebuyisiweyo ingasetyenziselwa ukufunda nokubhala imisebenzi. Xa kukho into ebhaliweyo kumbhobho, ukuya kuthi ga kwi-504 bytes yedatha ikhuselwe, emva koko inkqubo yokubhala iyanqunyanyiswa. Xa kufundwa kumbhobho, idatha egciniweyo iyathathwa.

Kunyaka olandelayo ikernel yayibhalwe ngokutsha ngoC, kwaye umbhobho(2) kuhlelo lwesine ifumene imbonakalo yayo yangoku kunye neprototype "pipe(fildes)"

Umnxeba wenkqubo umbhobho yenza igalelo/imveliso indlela ebizwa ngokuba ngumbhobho. Izichazi zefayile ezibuyisiweyo zingasetyenziselwa ukufunda nokubhala imisebenzi. Xa kukho into ebhaliweyo kumbhobho, isiphatho esibuyiswe nge-r1 (resp. fildes[1]) siyasetyenziswa, sigcinwe kwi-4096 bytes yedatha, emva koko inkqubo yokubhala iyanqunyanyiswa. Xa ufunda kumbhobho, isibambo sibuyele kwi-r0 (resp. fildes [0]) sithatha idatha.

Kucingelwa ukuba xa umbhobho uchaziwe, iinkqubo ezimbini (okanye ngaphezulu) zokunxibelelana (ezenziwe ngeminxeba elandelayo Ifom) iya kudlulisela idatha ukusuka kumbhobho usebenzisa iifowuni ukufunda ΠΈ bhala.

Iqokobhe linesivakalisi sokuchaza uluhlu olulandelelanayo lweenkqubo ezidityaniswe ngumbhobho.

Iifowuni zokufunda kumbhobho ongenanto (ongekho datha ye-buffered) enesiphelo esinye kuphela (zonke izichazi zefayile zokubhala zivaliwe) zibuyisela "end of file". Iifowuni zokubhala kwimeko efanayo azihoywa.

Kwangoko ukuphunyezwa kwemibhobho egciniweyo iyasebenza ukuya kuhlelo lwesihlanu lwe-Unix (Juni 1974), kodwa iphantse yafana naleyo yavela kwinqaku elilandelayo. Amagqabantshintshi asanda kongezwa, ngoko unokutsiba uhlelo lwesihlanu.

Uhlelo lwesithandathu lweUnix (1975)

Masiqale ukufunda ikhowudi yomthombo we-Unix uhlelo lwesithandathu (Meyi 1975). Kakhulu enkosi iingonyama kulula kakhulu ukuyifumana kunemithombo yeenguqulelo zangaphambili:

Kangangeminyaka emininzi le ncwadi iingonyama yayikuphela koxwebhu kwi Unix kernel ekhoyo ngaphandle kweBell Labs. Nangona ilayisenisi yohlelo lwesithandathu yayivumela ootitshala ukuba basebenzise ikhowudi yomthombo wayo, ilayisenisi yohlelo lwesixhenxe yayingabandakanyi oku, ngoko ke le ncwadi yasasazwa ngokohlobo lweekopi ezichwetheziweyo ezingekho mthethweni.

Namhlanje ungathenga ukuprintwa kwakhona kwencwadi, ikhava ebonisa abafundi kumatshini wokukopisha. Kwaye ndiyabulela kuWarren Toomey (oqale iprojekthi yeTUHS) unokukhuphela Ifayile yePDF enekhowudi yomthombo yohlelo lwesithandathu. Ndifuna ukukunika umbono wokuba ungakanani umzamo owenziweyo ekudaleni ifayile:

Ngaphezulu kweminyaka eyi-15 eyadlulayo, ndachwetheza ikopi yekhowudi yomthombo enikwe kuyo iingonyama, kuba andizange ndiwuthande umgangatho wekopi yam evela kwinani elingaziwayo lezinye iikopi. I-TUHS yayingekabikho kwaye andizange ndikwazi ukufikelela kwimithombo yakudala. Kodwa ngo-1988, ndafumana iteyiphu endala ye-9-track equlethe i-backup esuka kwikhompyuter ye-PDP11. Kwakunzima ukuxelela ukuba yayisebenza, kodwa kwakukho i-intact / usr / src / umthi apho uninzi lweefayile zibhalwe ngonyaka we-1979, nangona zikhangeleka zamandulo. Yayiluhlelo lwesixhenxe okanye iPWB ephuma kuyo, njengoko ndandikholelwa.

Ndithathe into efunyenweyo njengesiseko kwaye ndahlela ngesandla imithombo kuhlelo lwesithandathu. Enye ikhowudi yahlala ifana, kodwa enye kwafuneka ihlelwe kancinane, itshintshe ithokheni yangoku += ukuya kwephelelwe lixesha =+. Ezinye izinto zicinywe ngokulula, kwaye ezinye kwafuneka zibhalwe ngokutsha, kodwa hayi kakhulu.

Kwaye namhlanje sinokufunda kwi-intanethi kwi-TUHS ikhowudi yomthombo wohlelo lwesithandathu ukusuka yokugcina, apho uDennis Ritchie wayenesandla.

Ngendlela, ekuboneni kuqala, eyona nto iphambili yekhowudi yeC ngaphambi kwexesha leKernighan kunye neRitchie ubufutshane. Ayiqhelekanga ukuba ndikwazi ukufaka amaqhekeza ekhowudi ngaphandle kokuhlela okubanzi ukuze ilingane indawo yokubonisa emxinwa kakhulu kwindawo yam.

Ekuqaleni /usr/sys/ken/pipe.c kukho inkcazo yenkcazo (kwaye ewe, kukho ngaphezulu /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

Ubungakanani bebuffer abutshintshanga ukusukela kuhlelo lwesine. Kodwa apha siyabona, ngaphandle kwawo nawaphi na amaxwebhu oluntu, ukuba imibhobho yayikhe yasebenzisa iifayile njengogcino lokugcina!

Ngokuphathelele iifayile ze-LARG, ziyahambelana iflegi ye-inode LARG, esetyenziswa yi "algorithm enkulu yokulungisa" ukuqhubela phambili iibhloko ezingathanga ngqo ukuxhasa iinkqubo ezinkulu zefayile. Ekubeni uKen wathi kungcono ukungazisebenzisi, ndiza kuyamkela ngovuyo ilizwi lakhe.

Nantsi indlela yokwenyani yokufowuna 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;
}

Izimvo zichaza ngokucacileyo ukuba kuqhubeka ntoni apha. Kodwa ukuqonda ikhowudi akulula kangako, ngokuyinxenye ngenxa yendlela "cwangcisa umsebenzisi uΒ» kunye neerejista R0 ΠΈ R1 Iiparamitha zokufowuna kwenkqubo kunye namaxabiso okubuyisela agqithisiwe.

Masizame nge ialloc() faka kwidiski i-inode (isibambo sesalathisi), kwaye ngoncedo falloc () - beka ezimbini kwinkumbulo ifayile. Ukuba konke kuhambe kakuhle, siya kucwangcisa iiflegi ukuchonga ezi fayile njengeziphelo ezibini zombhobho, zikhombe kwi-inode efanayo (inani lereferensi eliza kumiselwa ku-2), kwaye umaka i-inode njengoko ilungisiwe kwaye isetyenziswa. Nika ingqalelo kwizicelo ndiyabeka() kwiindlela zemposiso ukunciphisa ubalo lwereferensi kwi-inode entsha.

pipe() kufuneka idlule R0 ΠΈ R1 buyisela amanani eenkcazo zeefayile zokufunda nokubhala. falloc() ibuyisela isalathisi kulwakhiwo lwefayile, kodwa kwakhona "ibuyisela" nge u.u_ar0[R0] kunye nenkcazelo yefayile. Oko kukuthi, ikhowudi igcina ngaphakathi r isichazi sefayile yokufunda kwaye yabela inkcazo yefayile yokubhala ngokuthe ngqo ukusuka u.u_ar0[R0] emva kwefowuni yesibini falloc().

Iflegi FPIPE, esibeka xa sidala umbhobho, silawula ukuziphatha komsebenzi rdwr() kwi sys2.cukufowunela iindlela 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);
    }
        /* … */
}

Emva koko umsebenzi readp() Π² pipe.c ifunda idatha kumbhobho. Kodwa kungcono ukulandelela ukuphunyezwa ukuqala ukusuka writep(). Kwakhona, ikhowudi iye yaba nzima ngakumbi ngenxa yeengqungquthela zokudlula iingxabano, kodwa ezinye iinkcukacha zinokushiywa.

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 ii-bytes kwigalelo lombhobho u.u_count. Okokuqala kufuneka sitshixe i-inode (jonga ngezantsi plock/prele).

Emva koko sijonga i-inode reference counter. Ngethuba nje zombini iziphelo zombhobho zihlala zivulekile, i-counter kufuneka ilingane no-2. Sibamba ikhonkco enye (ukusuka rp->f_inode), ngoko ke ukuba i-counter ingaphantsi kwe-2, kufuneka ithethe ukuba inkqubo yokufunda ivale isiphelo sayo sombhobho. Ngamanye amazwi, sizama ukubhalela kumbhobho ovaliweyo, kwaye oku kuyimpazamo. Ikhowudi yempazamo yexesha lokuqala EPIPE kunye nomqondiso SIGPIPE yavela kuhlelo lwesithandathu lwe-Unix.

Kodwa nokuba i-conveyor ivuliwe, inokuba igcwele. Kule meko, sikhulula isitshixo kwaye silale ngethemba lokuba enye inkqubo iya kufunda kwipayipi kwaye ikhulule indawo eyaneleyo kuyo. Emva kokuba sivukile, sibuyela ekuqaleni, sixhoma isitshixo kwakhona kwaye siqale umjikelo omtsha wokurekhoda.

Ukuba kukho indawo eyaneleyo yamahhala kwipayipi, ngoko sibhala idatha kuyo ngokusebenzisa bhala ()... Ipharamitha i_size1 inode (ukuba umbhobho awunanto, unokulingana no-0) ubonisa ukuphela kwedatha esele iqulethe. Ukuba kukho indawo yokurekhoda eyaneleyo, sinokugcwalisa umbhobho ukusuka i_size1 Π΄ΠΎ PIPESIZ. Emva koko sikhulula isitshixo kwaye sizame ukuvusa nayiphi na inkqubo elinde ukufunda kumbhobho. Sibuyela ekuqaleni ukuze sibone ukuba siye sakwazi ukubhala ii-bytes ezininzi njengoko sifuna. Ukuba ayiphumelelanga, ngoko siqala umjikelo omtsha wokurekhoda.

Ngokuqhelekileyo iparameter i_mode i-inode isetyenziselwa ukugcina iimvume r, w ΠΈ x. Kodwa kwimeko yemibhobho, sibonisa ukuba inkqubo ethile ilindele ukubhala okanye ukufunda usebenzisa amasuntswana IREAD ΠΈ IWRITE ngokulandelelanayo. Inkqubo ibeka iflegi kunye neefowuni sleep(), kwaye kulindeleke ukuba enye inkqubo kwixesha elizayo iya kubangela wakeup().

Umlingo wokwenyani uyenzeka sleep() ΠΈ wakeup(). Ziphunyezwa kwi slp.c, umthombo odumileyo othi "Awulindelekanga ukuba uqonde oku" ukuphawula. Ngethamsanqa, akufuneki siqonde ikhowudi, jonga nje amagqabantshintshi:

/*
 * 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) /* … */

Inkqubo ebangela sleep() kwijelo elithile, linokuthi kamva livuswe yenye inkqubo, eya kubangela wakeup() kwitshaneli enye. writep() ΠΈ readp() ukulungelelanisa izenzo zabo ngeefowuni ezidityanisiweyo. Qaphela oko pipe.c isoloko ibeka indawo yokuqala PPIPE xa ebizwa sleep(), yiloo nto ke sleep() inokuphazanyiswa luphawu.

Ngoku sinayo yonke into yokuqonda 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);
}

Ungakufumanisa kulula ukufunda lo msebenzi ukusuka ezantsi ukuya phezulu. Isebe "lokufunda nokubuyisela" lidla ngokusetyenziswa xa kukho idatha ethile kumbhobho. Kule meko, sisebenzisa funda () sifunda idatha eninzi njengoko ifumaneka ukuqala kule yangoku f_offset ukufunda, kwaye emva koko uhlaziye ixabiso le-offset ehambelanayo.

Kufundo olulandelayo, umbhobho uya kuba nanto ukuba i-read offset ifikile i_size1 kwi inode. Siseta kwakhona indawo ku-0 kwaye sizame ukuvusa nayiphi na inkqubo efuna ukubhala kumbhobho. Siyazi ukuba xa i-conveyor igcwele, writep() uya kulala ip+1. Kwaye ngoku umbhobho ungenanto, sinokuwuvusa ukuze siphinde siqalise umjikelo wawo wokubhala.

Ukuba awunanto yokufunda, ngoko readp() inokuseta iflegi IREAD ndize ndilale ip+2. Siyazi ukuba yintoni eya kumvusa writep(), xa ibhala idatha ethile kumbhobho.

Izimvo kwi readi() kunye nokubhala() izakunceda uqonde ukuba endaweni yokudlula iparameters nge "u"Sinokubaphatha njengemisebenzi eqhelekileyo ye-I / O ethatha ifayile, indawo, i-buffer kwimemori, kwaye ubale inani leebhayithi zokufunda okanye 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;
/* … */

Ngokubhekiselele kwi "conservative" blocking, ke readp() ΠΈ writep() vala i-inode de bagqibe umsebenzi wabo okanye bafumane isiphumo (oko kukuthi, ukufowuna wakeup). plock() ΠΈ prele() sebenza ngokulula: usebenzisa iseti eyahlukileyo yeefowuni sleep ΠΈ wakeup sivumele ukuba sivuse nayiphi na inkqubo efuna isitshixo esisandula ukuyikhulula:

/*
 * 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 ndandingasiqondi isizathu readp() ayibangeli prele(ip) phambi kwefowuni wakeup(ip+1). Into yokuqala kukuba writep() ibangela kumjikelo wayo, oku plock(ip), ekhokelela kwi-deadlock ukuba readp() andikayisusi ibhloko yam okwangoku, ngoko ke ikhowudi kufuneka isebenze ngokuchanekileyo. Ukuba ujonga wakeup(), ke kuyacaca ukuba iphawula kuphela inkqubo yokulala njengoko ilungele ukuphumeza, ukwenzela ukuba kwixesha elizayo sched() ngenene wayisungula. Ngoko readp() bangela wakeup(), isusa isitshixo, iseti IREAD kunye neefowuni sleep(ip+2)- konke oku ngaphambili writep() iqalisa kwakhona umjikelo.

Oku kugqiba inkcazo yabahambisi kuhlelo lwesithandathu. Ikhowudi elula, imiphumo efikelela kude.

Uhlelo lwesixhenxe lweUnix (NgoJanuwari 1979) yayiyinkupho entsha enkulu (iminyaka emine kamva) eyazisa izicelo ezininzi ezintsha kunye neempawu zekernel. Kukwakho notshintsho olubalulekileyo ngokunxibelelene nokusetyenziswa kohlobo lokuphoswa, iimanyano kunye nezikhombisi ezichwetheziweyo kwizakhiwo. Nangona kunjalo ikhowudi yokuhambisa ayitshintshanga. Singalutsiba olu hlelo.

Xv6, ikernel elula efana ne-Unix

Ukwenza i-kernel Xv6 iphenjelelwe luhlelo lwesithandathu lwe-Unix, kodwa ibhaliwe kwi-C yangoku ukuze iqhutywe kwiiprosesa ze-x86. Ikhowudi ifundeka lula kwaye iyaqondakala. Ngaphezu koko, ngokungafaniyo nemithombo ye-Unix ene-TUHS, ungayiqokelela, uyiguqule, kwaye uyiqhube kwenye into ngaphandle kwe-PDP 11/70. Ke ngoko, le kernel isetyenziswa kakhulu kwiiyunivesithi njengezinto zokufunda kwiinkqubo zokusebenza. Imithombo zikwiGithub.

Ikhowudi iqulethe ukuphunyezwa okucacileyo kunye nokucinga umbhobho.c, exhaswa sisikhuseli kwinkumbulo endaweni ye-inode kwidiski. Apha ndinikezela kuphela inkcazo "yemibhobho yesakhiwo" kunye 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 imo yophunyezo oluseleyo, olubandakanya imisebenzi piperead(), pipewrite() ΠΈ pipeclose(). Okwenyani umnxeba wenkqubo sys_pipe sisisongelo esimiliselwe ngaphakathi sysfile.c. Ndincoma ukufunda ikhowudi yakhe yonke. Ubunzima bukwinqanaba lekhowudi yomthombo wohlelo lwesithandathu, kodwa kulula kakhulu kwaye kumnandi ngakumbi ukufunda.

Linux 0.01

Linux 0.01 ikhowudi yemvelaphi inokufumaneka. Kuya kuba kufundisa ukufunda ukuphunyezwa kwemibhobho yakhe fs/pipe.c. Oku kusebenzisa i-inode ukumela umbhobho, kodwa umbhobho wona ngokwawo ubhalwe ngohlobo lwangoku C. Ukuba uye wasebenza ngendlela yakho ngekhowudi yohlelo lwesi-6, awuyi kuba nangxaki apha. Le yindlela umsebenzi okhangeleka 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 kokujonga iinkcazo zesakhiwo, ungafumanisa ukuba ireferensi yokubala ye-inode isetyenziswa njani ukujonga ukuba umsebenzi wokubhala uphumela SIGPIPE. Ukongeza ekusebenzeni i-byte-by-byte, lo msebenzi kulula ukuthelekisa kunye neengcamango ezichazwe ngasentla. Nkqu nengqondo sleep_on/wake_up ayibonakali ingaqhelekanga.

Iinkozo zeLinux zanamhlanje, iFreeBSD, iNetBSD, iOpenBSD

Ngokukhawuleza ndatyhutyha iinkozo zale mihla. Akukho namnye kubo unokuphunyezwa kwediski kwakhona (ayimangalisi). I-Linux inokuphunyezwa kwayo. Nangona iikernel ezintathu ze-BSD zanamhlanje ziqulethe ukuphunyezwa okusekwe kwikhowudi eyabhalwa nguJohn Dyson, ekuhambeni kweminyaka baye bahluke kakhulu omnye komnye.

Ukufunda fs/pipe.c (kwiLinux) okanye sys/kern/sys_pipe.c (kwi-BSD), kuthatha ukuzinikela ngokwenene. Ikhowudi yanamhlanje imalunga nokusebenza kunye nenkxaso yeempawu ezifana ne-vector kunye ne-asynchronous I/O. Kwaye iinkcukacha zokwabiwa kwememori, izitshixo kunye noqwalaselo lwe-kernel zonke ziyahluka kakhulu. Oku ayisiyiyo into efunwa ziikholeji kwikhosi yentshayelelo yeenkqubo zokusebenza.

Ngapha koko, bendinomdla wokwemba iipateni ezindala (ezifana nokuvelisa SIGPIPE kwaye ubuye EPIPE xa ubhalela kumbhobho ovaliweyo) kuzo zonke ezi nkozo zahlukeneyo zanamhlanje. Andisoze ndibone ikhompyuter ye-PDP-11 ebomini bokwenyani, kodwa kusekho okuninzi ekufuneka ndikufunde kwikhowudi eyabhalwa kwiminyaka ngaphambi kokuba ndizalwe.

Inqaku elibhalwe nguDivi Kapoor ngo-2011:Ukuphunyezwa kweLinux Kernel yeMibhobho kunye neeFIFOs" ibonelela ngesishwankathelo sendlela imibhobho (isa) isebenza ngayo kwiLinux. A Ukuzinikela okutsha kwiLinux ibonisa imodeli yombhobho wonxibelelwano, obuchule bayo bungaphezulu kwezo fayile zethutyana; kwaye ikwabonisa ukuba imibhobho ikude kangakanani na ukusuka "kutshixeko olungqongqo kakhulu" kuhlelo lwesithandathu lwe-Unix kernel.

umthombo: www.habr.com

Yongeza izimvo