Sida dhuumaha looga fuliyo Unix

Sida dhuumaha looga fuliyo Unix
Maqaalkani waxa uu sharaxayaa hirgelinta dhuumaha gudaha Unix kernel. Waxaan xoogaa ka xumaaday maqaal dhawaan soo baxay oo ciwaankiisu ahaa "Sidee bay dhuumaha ugu shaqeeyaan Unix?" ayaa soo baxday ma ku saabsan qaab-dhismeedka gudaha. Waxaan noqday mid xiiseeya oo waxaan dhex qoday ilo hore si aan jawaabta u helo.

Maxaan ka hadlaynaa?

Dhuumaha, "malaha hal-abuurka ugu muhiimsan ee Unix," ayaa ah sifada qeexeysa falsafada Unix ee hoose ee isku xirka barnaamijyada yaryar, iyo sidoo kale calaamad caan ah oo ku taal khadka taliska:

$ echo hello | wc -c
6

Shaqadani waxay kuxirantahay wicitaanka nidaamka kernel-ku bixiyo pipe, kaas oo lagu sifeeyay boggaga waraaqaha tuubo (7) ΠΈ tuubo (2):

Tuubooyinku waxay bixiyaan kanaal aan jiho lahayn oo loogu talagalay isgaadhsiinta hab-socodka. Dhuunuhu waxa uu leeyahay gelinta (dhammaadka qor) iyo wax soo saar (dhammaadka akhrinta). Xogta lagu qoray gelinta dhuumaha waxaa laga akhriyi karaa soo-saarka.

Dhuumaha waxaa la sameeyaa iyadoo la isticmaalayo wicitaanka pipe(2), kaas oo soo celinaya laba tilmaame oo faylal ah: mid tixraacaya gelinta dhuumaha, kan labaadna soosaarka.

Wax soo saarka raadraaca ee amarka kore wuxuu muujinayaa abuurista dhuumaha iyo qulqulka xogta iyada oo loo marayo hal hab oo kale:

$ 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

Habka waalidku wuu wacaa pipe()si aad u hesho sharraxayaasha faylka la rakibay. Mid ka mid ah habraaca cunuga wuxuu wax ku qoraa hal gacan, mid kalena wuxuu akhriyaa xog isku mid ah gacan kale. qoloftu waxay isticmaashaa dup2 si ay u "bedesho" sharaxayaasha 3 iyo 4 si ay u dhigmaan stdin iyo stdout.

Tuubooyinka la'aanteed, qolofku waa inuu ku qoraa natiijada hal hab faylal una gudbiyaa hab kale si uu u akhriyo xogta faylka. Natiijo ahaan, waxaan luminay kheyraad badan iyo meel disk ah. Si kastaba ha ahaatee, dhuumaha ma wanaagsana kaliya sababtoo ah waxay kuu ogolaanayaan inaad ka fogaato isticmaalka faylasha ku meel gaarka ah:

Haddii nidaamku isku dayayo in laga akhriyo dhuumaha maran markaa read(2) xannibi doona ilaa xogta laga helayo. Haddii nidaamku isku dayo inuu u qoro dhuumo buuxa, markaa write(2) xannibi doona ilaa xog ku filan laga akhriyo dhuumaha si loo sameeyo qoraalka.

Sida shardiga POSIX, kani waa hanti muhiim ah: wax u qorida dhuumaha ilaa PIPE_BUF bytes (ugu yaraan 512) waa in ay noqdaan atomic si hab-socodka ay ugu wada xiriiraan midba midka kale iyada oo loo marayo dhuumaha si aan faylasha caadiga ah (kuwaas oo aan bixineynin dammaanadahaas) aysan awoodin.

Marka la isticmaalayo faylka caadiga ah, nidaamku wuxuu u qori karaa dhammaan wax soo saarkiisa wuxuuna u gudbin karaa hab kale. Ama habraacyadu waxay ku shaqayn karaan qaab isbarbar socda, iyadoo la adeegsanayo habka calaamadaynta dibadda (sida semaphore) si ay midba midka kale ugu wargaliyo marka qoraal ama akhris la dhammeeyo. Gaadiidleyda ayaa naga badbaadiya dhibkan oo dhan.

Maxaan raadineynaa?

Waxaan ku sharixi doonaa erayo fudud si ay kuugu sahlanaato inaad qiyaasto sida uu u shaqayn karo gaadiid qaade. Waxaad u baahan doontaa inaad qoondayso kaydka iyo xaalad xusuusta ah. Waxaad u baahan doontaa hawlo si aad ugu darto ugana saarto xogta kaydiyaha Waxaad u baahan doontaa habab aad ku wacdo hawlaha inta lagu jiro akhrinta iyo qorista hawlgallada sharraxayaasha faylka. Waxaadna u baahan doontaa quful si aad u fuliso hab-dhaqanka gaarka ah ee kor lagu sheegay.

Hadda waxaan diyaar u nahay inaan su'aalo weydiinno koodhka isha kernel-ka hoostiisa si aan u xaqiijinno ama u beeninno qaabkayaga maskaxeed ee aan caddayn. Laakin mar walba u diyaar garow wax aan la fileyn.

Halkee ayaan raadineynaa?

Ma garanayo halka uu ku yaal nuqulka buugga caanka ah "Buuga libaaxyada"oo leh Unix 6 code code, laakiin mahadsanid Ururka Unix Heritage Society waxaad ka raadin kartaa online at isha code xitaa noocyadii hore ee Unix.

Ku dhex wareegidda kaydka TUHS waxay la mid tahay booqashada matxafka. Waxaan eegi karnaa taariikhdayada aan wadaagno, waxaanan ixtiraam u hayaa sannadaha badan ee dadaalka loogu jiro soo kabashada dhammaan walxahan xoogaa cajalado iyo daabacaado duug ah. Waxaan si weyn ula socdaa jajabyadaas weli maqan.

Markaan ku qanacnay xiisaha aan u qabno taariikhda qadiimiga ah ee alaab-qaadayaasha, waxaan eegi karnaa kernels casriga ah marka la barbardhigo.

By habka, pipe waa nidaamka call number 42 ee shaxda sysent[]. Shil?

Kernels-dhaqameedka Unix (1970-1974)

Wax raad ah maan helin pipe(2) midna ma gelin PDP-7 Unix (Janaayo 1970), mana aha daabacaadda koowaad ee Unix (Noofambar 1971), mana ku jirin koodka isha ee aan dhamaystirnayn daabacaadda labaad (June 1972).

TUHS ayaa sheegaysa in daabacaadda saddexaad ee Unix (Febraayo 1973) wuxuu noqday nuqulkii ugu horreeyay ee gaadiidleyda:

Daabacaadda 1973aad ee Unix ayaa ahaa nuqulkii ugu dambeeyay ee kernel ku qoran luqadda kulanka, laakiin sidoo kale nuqulkii ugu horreeyay oo leh dhuumo. Intii lagu jiray XNUMX, waxaa la sameeyay shaqada si loo hagaajiyo daabacaadda saddexaad, kernel ayaa dib loogu qoray C, sidaas darteed daabacaadda afraad ee Unix ayaa soo baxday.

Mid ka mid ah akhristayaasha ayaa helay sawir dukumeenti ah kaas oo Doug McIlroy uu soo jeediyay fikradda "isku xirka barnaamijyada sida tuubada beerta."

Sida dhuumaha looga fuliyo Unix
Buugga Brian KernighanUnix: Taariikh iyo Xusuus", taariikhda soo ifbaxa maraakiibta, dukumeentigan ayaa sidoo kale lagu sheegay: "... waxay ku dhegtay gidaarka xafiiskayga Bell Labs muddo 30 sano ah." Halkan wareysiga McIlroy, iyo sheeko kale oo ka timid Shaqada McIlroy, oo la qoray 2014:

Markii Unix soo baxday, xiisaha aan u qabo coroutines ayaa ii horseeday inaan weydiiyo qoraaga OS-ga, Ken Thompson, inuu oggolaado xogta loo qoray habka inay u baxdo oo keliya ma aha qalabka, laakiin sidoo kale inaan u soo saaro hab kale. Ken wuxuu go'aansaday inay suurtagal tahay. Si kastaba ha ahaatee, sida ugu yar, wuxuu rabay in nidaam kastaa uu shaqeeyo door muhiim ah. Qoritaanka tooska ah ee hababka u dhexeeya run ahaantii faa'iido weyn ma ka leedahay qorista faylka dhexe? Waxay ahayd markii aan sameeyay soo jeedin gaar ah oo leh magaca soo jiidashada leh ee "tuubada" iyo sharaxaadda ereyga isdhexgalka ee u dhexeeya hababka ayuu Ken ugu dambeyntii ku dhawaaqay: "Waan samayn doonaa!"

Oo sameeyey. Habeen fiid ah, Ken waxa uu beddelay kernel-ka iyo qolofka, waxa uu hagaajiyay dhawr barnaamij oo caadi ah si loo jaangooyo sida ay u aqbaleen gelinta (taas oo ka iman karta dhuumaha), waxa kale oo uu beddelay magacyo faylal ah. Maalintii xigtay, dhuumaha ayaa bilaabay in si weyn loogu isticmaalo codsiyada. Dhammaadkii usbuuca, xoghayayaashu waxay adeegsanayeen si ay dukumentiyada uga soo diraan qalabka wax lagu daabaco. Wax yar ka dib, Ken wuxuu bedelay API-gii asalka ahaa iyo syntax si loogu duubo isticmaalka dhuumaha oo leh heshiisyo nadiif ah, kuwaas oo la isticmaalay tan iyo markaas.

Nasiib darro, koodhka isha ee daabacaadda saddexaad ee Unix kernel ayaa lumay. In kasta oo aan hayno koodhka isha kernel ee ku qoran C daabacaada afraad, oo la sii daayay Noofambar 1973, laakiin waxay soo baxday dhawr bilood ka hor inta aan si rasmi ah loo sii dayn oo kuma jiraan fulinta dhuumaha. Waa ceeb in koodhka isha shaqadan Unix ee halyeyga ahi lumo, laga yaabee weligeed.

Waxaan u haynaa dukumeenti qoraal ah pipe(2) laga bilaabo labada siideyn, si aad ku bilaabi karto raadinta dukumentiyada daabacaadda saddexaad (ereyo gaar ah, oo hoosta laga xarriiqay "gacan", xarig xaraf ah ^H, oo ay ku xigto hoosta!). Proto-pipe(2) wuxuu ku qoran yahay luqadda kulanka wuxuuna soo celinayaa kaliya hal sharaxe oo fayl, laakiin wuxuu horey u bixiyaa shaqeynta aasaasiga ah ee la filayo:

Wacitaanka nidaamka biibiile abuuraa habka wax-gelinta/soo-saarka loo yaqaan pipeline. Sharaxa faylka la soo celiyay waxaa loo isticmaali karaa hawlgallada akhrinta iyo qorista. Marka wax lagu qoro dhuumaha, ilaa 504 bytes oo xog ah ayaa la xiraa, ka dib habka qorista waa la hakiyaa. Markaad wax ka akhrinayso dhuumaha, xogta la xidhay waa la qaadayaa.

Sannadkii xigay kernel-ka ayaa dib loogu qoray C, iyo beebka (2) ee daabacaadda afraad waxay heshay muuqaalkeeda casriga ah ee tusaalaha ah "pipe(fildes)Β»:

Wacitaanka nidaamka biibiile abuuraa habka wax-gelinta/soo-saarka loo yaqaan pipeline. Sharaxayaasha faylka la soo celiyay waxaa loo isticmaali karaa akhrinta iyo qorista. Marka wax lagu qoro dhuunta, gacanta lagu soo celiyo r1 (resp. fildes[1]) ayaa la isticmaalaa, oo lagu kaydiyaa 4096 bytes oo xog ah, ka dib habka qorista waa la hakiyaa. Markaad wax ka akhrinayso dhuumaha, gacantu waxay ku soo noqotay r0 (resp. fildes[0]) waxay qaadataa xogta.

Waxaa loo malaynayaa in marka dhuumaha la qeexo, laba (ama ka badan) hababka isgaadhsiinta (oo ay abuuraan wicitaano xiga fargeeto ah) waxay ku wareejin doontaa xogta dhuumaha adoo isticmaalaya wicitaano akhri ΠΈ ku qor.

Qolfoofku wuxuu leeyahay hab-raac lagu qeexo habraacyo toosan oo isku xidhan oo dhuumo ah.

Wicitaannada lagu akhriyo dhuunta maran (oo aan ku jirin xog la daboolay) oo leh hal dhammaad (dhammaan sharraxayaasha faylka qoraalka waa la xiray) soo celinta "dhamaadka faylka". Wicitaannada lagu qorayo xaalad la mid ah waa la iska indhatiraa.

Ugu horrayn hirgelinta dhuumaha la ilaaliyo ku saabsan ilaa daabacaadda shanaad ee Unix (June 1974), laakiin waxay ku dhowdahay inay la mid tahay tii ka soo muuqday siidaynta soo socota. Faallooyinka ayaa hadda lagu daray, si aad uga boodi karto daabacaadda shanaad.

Daabacaaddii lixaad ee Unix (1975)

Aan bilowno akhrinta koodka isha Unix daabacaadda lixaad (May 1975). Aad iyo aad ayaa mahad leh Lions aad bay uga sahlan tahay in la helo marka loo eego ilaha qoraaladii hore:

Sannado badan buuggu Lions wuxuu ahaa dukumeentiga kaliya ee ku jira kernel-ka Unix ee laga heli karo meel ka baxsan Bell Labs. In kasta oo shatiga daabacaadda lixaad uu u oggolaaday macallimiinta inay adeegsadaan koodka isha, shatiga daabacaadda toddobaad ayaa meesha ka saaray suurtagalnimadan, sidaas darteed buugga waxaa loo qaybiyay qaab nuqullo qoraal ah oo sharci-darro ah.

Maanta waxaad iibsan kartaa daabacaadda dib u daabacaadda buugga, kaas oo daboolkiisu uu muujinayo ardayda mashiinka nuqulka ah. Waad ku mahadsan tahay Warren Toomey (oo bilaabay mashruuca TUHS) waad soo dejisan kartaa Faylka PDF oo leh koodka isha daabacaadda lixaad. Waxaan rabaa in aan ku siiyo fikrad ah inta ay le'eg tahay dadaalka abuurista faylka:

In ka badan 15 sano ka hor, waxaan qoray nuqul ka mid ah koodka isha ee lagu bixiyay Lions, sababtoo ah maan jeclayn tayada koobigayga oo aan ka helay tiro aan la garanayn oo koobiyo kale ah. TUHS ma jirin wali manaan helin ilahii hore. Laakiin sannadkii 1988kii, waxaan helay cajalad 9-track ah oo hore oo ay ku jirtay kaydka kombayutarka PDP11. Way adkeyd in la sheego in ay shaqaynayso iyo in kale, laakiin waxa jiray geed/usr/src/ geed aan fiicneyn oo inta badan faylalka lagu calaamadiyay sanadka 1979, kaas oo xitaa u muuqday mid qadiimi ah. Waxay ahayd daabacaaddii toddobaad ama PWB-ga laga soo xigtay, sida aan rumaystay.

Helitaanka waxa aan u qaatay gundhig oo waxa aan gacanta ku tafatiray ilihii ilaa daabacaddii lixaad. Qaar ka mid ah koodku sidiisii ​​ayay ahaan jireen, laakiin qaar waa in wax yar la tafatiray, taas oo beddeleysa calaamadda casriga ah ee += mid duugowday =+. Waxyaabaha qaarkood si fudud ayaa loo tirtiray, qaarna waxay ahayd in si buuxda dib loo qoro, laakiin aan aad u badnayn.

Maantana waxaan ka akhrisan karnaa internetka TUHS koodhka isha ee daabacaadda lixaad ee ka yimid kaydka, kaas oo Dennis Ritchie uu gacan ku lahaa.

Jid ahaan, jaleecada hore, muuqaalka ugu weyn ee C-code ka hor muddada Kernighan iyo Ritchie waa soo koobid. Inta badan ma aha in aan awoodo in aan geliyo qaybo kood ah iyada oo aan la samayn tafatir ballaaran si aan ugu habboonaado aag muuqaal cidhiidhi ah oo ku yaal boggayga.

Bilowgii /usr/sys/ken/pipe.c waxaa jira faallo sharraxaad ah (iyo haa, waxaa jira wax ka badan /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

Cabbirku isma beddelin ilaa daabacaaddii afraad. Laakiin halkan waxaan ku aragnaa, iyada oo aan la helin wax dukumeenti dadweyne ah, in dhuumahaas mar hore u isticmaali jireen galalka kaydinta kaydinta!

Xagga faylalka LARG, waxay u dhigmaan calanka inode LARG, kaas oo loo isticmaalo "algorithm wax ka qabashada weyn" si loo farsameeyo blocks aan toos ahayn si ay u taageeraan nidaamyada faylasha waaweyn. Tan iyo markii Ken uu sheegay in ay wanaagsan tahay in aan la isticmaalin, waxaan si farxad leh u qaadan doonaa eraygiisa.

Halkan waa wicitaanka nidaamka dhabta ah 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;
}

Faallada ayaa si cad u qeexaysa waxa halkan ka socda. Laakiin fahamka koodhka ma fududa, qayb ahaan sababtoo ah jidka "struct user uΒ» oo diiwaan geliya R0 ΠΈ R1 Xaddiga wicitaanka nidaamka iyo qiyamka soo celinta waa la dhaafay.

Aan isku dayno ialloc() saara saxanka inode (hand index), iyo iyadoo la kaashanayo falloc() - meel laba xusuusta fayl. Haddii wax walba si fiican u socdaan, waxaanu dejin doonaa calamo si aan u aqoonsanno faylalkan inay yihiin labada daraf ee dhuumaha, waxaanu ku tilmaannaa isla inode (kuwaas oo tixraaca tixraaceedu noqon doono 2), oo ku calaamadi inode sida wax laga beddelay oo la isticmaalay. U fiirso codsiyada waan dhigay() Wadooyinka khaladka ah si loo yareeyo tirada tixraaca ee inode cusub.

pipe() waa in loo maraa R0 ΠΈ R1 soo celi nambarada sharaxaadaha faylka si aad u akhrido oo u qorto. falloc() ku soo celiyaa tilmaame qaab dhismeedka faylka, laakiin sidoo kale "soo noqda" iyada oo loo marayo u.u_ar0[R0] iyo sharraxaha faylka. Taasi waa, koodku wuxuu kaydiyaa gudaha r Faylka sharaxaha si loo akhriyo oo u xilsaaro sharraxaaha faylka si toos ah wax looga qoro u.u_ar0[R0] ka dib markii labaad falloc().

Calanka FPIPE, kaas oo aan dejineyno marka la abuurayo dhuumaha, waxay xakameysaa habdhaqanka shaqada rdwr () ee sys2.cwacitaanka hababka gaarka ah ee 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);
    }
        /* … */
}

Markaa shaqada readp() Π² pipe.c akhriyo xogta dhuumaha. Laakiin way fiicantahay in la raadiyo hirgelinta laga bilaabo writep(). Mar labaad, koodhka ayaa noqday mid aad u adag sababtoo ah heshiisyada doodaha gudbinta, laakiin faahfaahinta qaar ayaa laga saari karaa.

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;
}

Waxaan rabnaa inaan ku qorno bytes gelinta dhuumaha u.u_count. Marka hore waxaan u baahanahay inaan xirno inode (eeg hoos plock/prele).

Kadibna waxaanu hubinaynaa miiska tixraaca inode. Ilaa iyo inta labada daraf ee dhuumuhu ay furan yihiin, miisanku waa inuu la siman yahay 2. Waxaan haynaa hal xiriiriye (laga bilaabo). rp->f_inode), marka haddii miiska uu ka yar yahay 2, waa in ay ka dhigan tahay in habka wax-akhrisku uu xiray dhamaadka dhuumaha. Si kale haddii loo dhigo, waxaan isku dayeynaa inaan u qorno dhuumaha xiran, tani waa qalad. Koodhka qaladka markii ugu horeysay EPIPE iyo calaamad SIGPIPE ka soo muuqday daabacaaddii lixaad ee Unix.

Laakin xataa hadii uu furmo qaadku, waxa laga yaabaa in ay buuxdo. Xaaladdan oo kale, waxaan sii deyneynaa qufulka oo aan seexanno rajada ah in hab kale uu ka akhriyo dhuumaha oo uu xoreeyo meel ku filan. Markaan soo kacnay, waxaan ku soo laabanaa bilawgii, dib u dhig qufulka oo aan bilownay wareeg cusub oo duubis ah.

Haddii ay jirto meel bannaan oo bilaash ah oo ku filan dhuumaha, ka dibna waxaan u qornaa xogta annaga oo isticmaalaya qori(). Halbeegga i_size1 at inode (haddii dhuumuhu madhan yihiin waxay la mid noqon kartaa 0) waxay muujinaysaa dhammaadka xogta ay hore ugu jirtay. Haddii ay jirto meel ku filan oo wax lagu duubo, waxaan ka buuxin karnaa dhuumaha i_size1 si ay u PIPESIZ. Kadibna waxaan sii deyneynaa qufulka oo aan isku daynaa inaan toosino nidaam kasta oo sugaya in laga akhriyo dhuunta. Waxaan dib ugu laabanaa bilawgii si aan u aragno inaan awoodnay inaan qorno inta ugu badan ee aan u baahanahay. Haddii aan lagu guulaysan, markaas waxaan bilaabeynaa wareeg cusub oo duubis ah.

Caadi ahaan halbeegga i_mode inode waxa loo isticmaalaa in lagu kaydiyo ogolaanshaha r, w ΠΈ x. Laakiin marka laga hadlayo dhuumaha, waxaanu tilmaamaynaa in nidaamka qaarkood uu sugayo qorista ama akhrinta iyadoo la isticmaalayo xoogaa yar IREAD ΠΈ IWRITE siday u kala horreeyaan. Nidaamku wuxuu dejiyaa calanka iyo wicitaanada sleep(), waxaana la filayaa in hannaan kale oo mustaqbalka ay keeni doonaan wakeup().

Sixirka dhabta ah ayaa ku dhaca sleep() ΠΈ wakeup(). Waxaa lagu hirgeliyaa gudaha Slp.c, Isha caanka ah "Lama filayo inaad tan fahanto" faallada. Nasiib wanaag, ma ahan inaan fahamno koodka, kaliya fiiri faallooyinka qaarkood:

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

Habka sababa sleep() Kanaal gaar ah, waxaa laga yaabaa in hadhow lagu toosiyo hab kale, taas oo keeni doonta wakeup() isla kanaalka. writep() ΠΈ readp() isku dubbarid ficilladooda iyada oo loo marayo wicitaannada lammaanaha ah. ogow taas pipe.c had iyo jeer waxay siisaa mudnaanta PPIPE marka loo yeero sleep(), waa sidaas sleep() waxaa hakad geli kara calaamad

Hadda waxaan haynaa wax walba si aan u fahanno shaqada 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);
}

Waxaa laga yaabaa inaad ku fududaato inaad akhrido shaqadan hoose ilaa sare. Qaybta "akhri oo soo celi" waxaa badanaa la isticmaalaa marka ay jiraan xog qaar ah oo ku jira dhuumaha. Xaaladdan oo kale, waxaan isticmaalnaa akhri() Waxaan akhrinay inta xog ee la hayo laga bilaabo tan hadda jirta f_offset akhrinta, ka dibna cusboonaysii qiimaha dhimista u dhiganta.

Akhrinta soo socota, dhuumaha ayaa madhnaan doona haddii ka-dhaafka akhrigu uu gaaro i_size1 iyo inode. Waxaan dib u dhignay booska 0 waxaanan isku daynaa inaan toosinno hannaan kasta oo raba in loo qoro dhuumaha. Waxaynu ognahay in marka qaadku buuxsamo. writep() ku seexan doona ip+1. Oo hadda oo ay dhuumuhu maran yihiin, waxaan ku kicin karnaa si aan dib ugu bilowno wareegtada qoraalka.

Haddii aadan haysan wax aad akhrido, markaa readp() calan dhigi kara IREAD oo hurdo la seexdo ip+2. Waanu ognahay waxa isaga kicin doona writep(), marka ay u qorto xogta qaar ka mid ah dhuumaha.

Faallo ku saabsan readi() iyo writei() waxay kaa caawin doontaa inaad fahamto in halkii aad ka gudbin lahayd xuduudaha "u"Waxaan ula dhaqmi karnaa sida hawlaha caadiga ah ee I/O ee qaata fayl, boos, kayd xusuusta, oo tirinaya tirada bytes si loo akhriyo ama loo qoro.

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

Dhanka xannibaadda "muxaafidka", markaa readp() ΠΈ writep() xannibo inode-ka ilaa ay ka dhammeeyaan shaqadooda ama ay helaan natiijo (taasi waa, wac wakeup). plock() ΠΈ prele() si fudud u shaqee: adoo isticmaalaya wicitaano kala duwan sleep ΠΈ wakeup noo ogolow inaan toosinno hanaan kasta oo u baahan qufulka aan hadda siidaynay:

/*
 * 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);
    }
}

Markii hore ma fahmin sababta readp() ma keeno prele(ip) wicitaanka ka hor wakeup(ip+1). Waxa ugu horreeya waa writep() sababa in ay wareegga, this plock(ip), taasoo keenaysa xidhidh haddii readp() Wali ma saarin block-kayga, markaa si uun koodku waa inuu si sax ah u shaqeeyaa. Hadii aad eegto wakeup(), ka dibna waxay caddaynaysaa in ay calaamad u tahay oo kaliya habka hurdada oo diyaar u ah in la fuliyo, si mustaqbalka sched() runtii bilaabay. Markaa readp() sababta wakeup(), ka saartaa qufulka, dhigaysa IREAD iyo wac sleep(ip+2)- waxaas oo dhan ka hor writep() dib u bilaabaya wareegga

Tani waxay dhamaystiraysaa sharraxaadda gaadiidka qaada ee daabacaadda lixaad. Koodhka fudud, cawaaqibta fog.

Daabacaadda toddobaad ee Unix (Janaayo 1979) waxay ahayd siideyn weyn oo cusub (afar sano kadib) taasoo soo bandhigtay codsiyo badan oo cusub iyo astaamo kernel ah. Waxa kale oo ay samaysay isbeddello la taaban karo oo la xidhiidha isticmaalka nooca shubista, ururrada iyo tilmaamayaasha qaab-dhismeedka. Si kastaba ha ahaatee koodhka gudbinta ficil ahaan aan isbeddelin. Waan ka boodi karnaa daabacaadan.

Xv6, kernel fudud oo u eg Unix

Si loo abuuro kernel-ka Xv6 saameyn ku yeeshay daabacaadda lixaad ee Unix, laakiin waxay ku qoran tahay C casriga ah si ay ugu shaqeyso x86 processor. Codku waa sahlan tahay in la akhriyo lana fahmi karo. Waxaa dheer, si ka duwan ilaha Unix ee leh TUHS, waad soo ururin kartaa, wax ka beddeli kartaa, oo ku wadi kartaa wax aan ahayn PDP 11/70. Sidaa darteed, kernel-kan ayaa si weyn loogu isticmaalaa jaamacadaha sida qalab waxbarasho oo ku saabsan nidaamyada hawlgalka. Ilaha waxay ku yaalaan Github.

Xeerku waxa uu ka kooban yahay dhaqangelin cad oo fikir leh tuubo.c, oo ay taageerto kayd kayd ah oo xusuusta halkii laga isticmaali lahaa inode-ka saxanka. Halkan waxaan ku bixiyaa kaliya qeexida "tuubada qaab dhismeedka" iyo shaqada 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() dejinaya xaaladda inta ka hartay hirgelinta, oo ay ku jiraan hawlaha piperead(), pipewrite() ΠΈ pipeclose(). wac nidaamka dhabta ah sys_pipe waa duub lagu hirgeliyay sysfile.c. Waxaan ku talinayaa inuu akhriyo koodkiisa oo dhan. Kakanaanta ayaa ah heerka koodhka isha daabacaadda lixaad, laakiin aad bay u fududahay oo aad bay u raaxaysan tahay in la akhriyo.

Linux 0.01

Koodhka isha ee Linux 0.01 waa la heli karaa. Waxay noqon doontaa mid wax ku ool ah in la barto hirgelinta dhuumaha tuubooyinka fs/pipe.c. Tani waxay isticmaashaa inode si ay u matasho dhuumaha, laakiin dhuunta lafteeda waxay ku qoran tahay C casriga ah. Haddii aad ka soo shaqeysay habkaaga iyada oo loo marayo koodka daabacaadda XNUMXaad, dhib kuma yeelan doontid halkan. Tani waa sida shaqadu u egtahay 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;
}

Adigoon xitaa fiirin qeexitaannada qaab-dhismeedka, waxaad ogaan kartaa sida tirinta tixraaca inode-ka loo isticmaalo si loo hubiyo in hawlgal qoraal ahi uu ka dhashay SIGPIPE. Marka lagu daro shaqada byte-by-byte, shaqadani way fududahay in la barbardhigo fikradaha kor lagu sharaxay. Xataa macquul sleep_on/wake_up uma eka shisheeye.

Kernel-ka casriga ah ee Linux, FreeBSD, NetBSD, OpenBSD

Waxaan si degdeg ah u dhex maray qaar ka mid ah kernels casriga ah. Midkoodna ma haysto hirgelinta diskka (la yaab ma leh). Linux waxay leedahay hirgelinteeda. In kasta oo saddexda kernel ee casriga ah ee BSD ay ka kooban yihiin hirgelinta ku salaysan kood uu qoray John Dyson, sannadihii la soo dhaafay aad ayay uga duwan yihiin midba midka kale.

In la akhriyo fs/pipe.c (Linux) ama sys/kern/sys_pipe.c (on *BSD), waxay u baahan tahay dadaal dhab ah. Koodhka maanta waxa uu ku saabsan yahay waxqabadka iyo taageerada astaamaha sida vector iyo asynchronous I/O. Iyo faahfaahinta qoondaynta xusuusta, qufulka iyo qaabaynta kernel dhamaantood aad bay u kala duwan yihiin. Tani ma aha waxa kulliyaduhu u baahan yihiin koorsada hababka hawlgalka ee hordhaca ah.

Si kastaba ha noqotee, waxaan xiisaynayay inaan qodo qaabab hore (sida abuurista SIGPIPE oo soo noqda EPIPE markaad wax u qorayso dhuumo xiran) dhammaan kernels casri ah oo kala duwan. Malaha waligay ma arki doono kombuyuutar PDP-11 nolosha dhabta ah, laakiin wali waxaa jira waxyaabo badan oo laga baran karo koodka la qoray sanado kahor intaanan dhalan.

Maqaal uu qoray Divi Kapoor 2011:Hirgelinta Kernel Linux ee Tubooyinka iyo FIFOs"wuxuu bixiyaa dulmar ku saabsan sida dhuumaha (wali) ugu shaqeeyaan Linux. A dib u eegis lagu sameeyay Linux wuxuu muujiyaa qaabka dhuumaha isdhexgalka, kaas oo awoodiisa ay ka badan tahay kuwa faylasha ku meel gaarka ah; iyo sidoo kale waxay muujinaysaa fogaanta dhuumaha ay ka yimaadeen "qufulka aadka u dhawrsan" ee daabacaadda lixaad ee Unix kernel.

Source: www.habr.com

Add a comment