Bii o ti ṣe imuse awọn opo gigun ti epo ni Unix

Bii o ti ṣe imuse awọn opo gigun ti epo ni Unix
Nkan yii ṣe apejuwe imuse ti awọn opo gigun ti epo ni ekuro Unix. Inu mi bajẹ diẹ pe nkan aipẹ kan ti akole rẹ jẹ "Bawo ni pipelines ṣiṣẹ ni Unix?» yipada kii ṣe nipa ti abẹnu be. Mo ni iyanilenu ati ki o walẹ sinu awọn orisun atijọ lati wa idahun.

Kini a n sọrọ nipa?

Awọn paipu jẹ “o ṣee ṣe kiikan pataki julọ ni Unix” - ẹya asọye ti imọ-jinlẹ ti Unix ti fifi awọn eto kekere papọ, ati ọrọ-ọrọ laini aṣẹ ti o faramọ:

$ echo hello | wc -c
6

Išẹ yii da lori ipe eto ti a pese ekuro pipe, eyi ti o jẹ apejuwe lori awọn oju-iwe iwe paipu (7) и paipu (2):

Pipelines pese ikanni kan-ọna fun ibaraẹnisọrọ laarin-ilana. Opo gigun ti epo naa ni titẹ sii (ipari kikọ) ati iṣẹjade (opin kika). Awọn data ti a kọ si titẹ sii ti opo gigun ti epo ni a le ka ni abajade.

Opo gigun ti epo ti ṣẹda nipasẹ pipe pipe(2), eyi ti o da awọn apejuwe faili meji pada: ọkan tọka si titẹ sii ti opo gigun ti epo, keji si abajade.

Ijade itọpa lati aṣẹ ti o wa loke fihan ẹda ti opo gigun ti epo ati sisan data nipasẹ rẹ lati ilana kan si ekeji:

$ 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

Ilana obi awọn ipe pipe()lati gba so faili apejuwe. Ilana ọmọ kan kọwe si onitumọ kan ati ilana miiran ka data kanna lati ọdọ olutọwe miiran. Awọn ikarahun "tunrukọ" awọn apejuwe 2 ati 3 pẹlu dup4 lati baramu stdin ati stdout.

Laisi awọn opo gigun ti epo, ikarahun naa yoo ni lati kọ abajade ti ilana kan si faili kan ki o pai si ilana miiran lati ka data lati faili naa. Bi abajade, a yoo padanu awọn orisun diẹ sii ati aaye disk. Sibẹsibẹ, awọn opo gigun ti epo dara fun diẹ sii ju yiyọkuro awọn faili igba diẹ lọ:

Ti ilana kan ba gbiyanju lati ka lati opo gigun ti epo ti o ṣofo, lẹhinna read(2) yoo dina titi data yoo wa. Ti ilana kan ba gbiyanju lati kọ si opo gigun ti epo, lẹhinna write(2) yoo dina titi di igba ti a ti ka data ti o to lati opo gigun ti epo lati pari kikọ.

Gẹgẹbi ibeere POSIX, eyi jẹ ohun-ini pataki: kikọ si opo gigun ti epo to PIPE_BUF awọn baiti (o kere ju 512) gbọdọ jẹ atomiki ki awọn ilana le ṣe ibasọrọ pẹlu ara wọn nipasẹ opo gigun ti epo ni ọna ti awọn faili deede (eyiti ko pese iru awọn iṣeduro bẹ) ko le.

Pẹlu faili deede, ilana kan le kọ gbogbo iṣẹjade rẹ si rẹ ki o gbe lọ si ilana miiran. Tabi awọn ilana le ṣiṣẹ ni ipo afiwera lile, ni lilo ẹrọ ifihan itagbangba (bii semaphore) lati sọ fun ara wọn nipa ipari kikọ tabi kika. Awọn olutọpa gba wa lọwọ gbogbo wahala yii.

Kini a nwa?

Emi yoo ṣe alaye lori awọn ika ọwọ mi lati jẹ ki o rọrun fun ọ lati fojuinu bawo ni gbigbe le ṣiṣẹ. Iwọ yoo nilo lati pin ifipamọ ati ipo diẹ ninu iranti. Iwọ yoo nilo awọn iṣẹ lati ṣafikun ati yọkuro data lati ifipamọ. Iwọ yoo nilo ohun elo diẹ lati pe awọn iṣẹ lakoko kika ati kikọ awọn iṣẹ ṣiṣe lori awọn apejuwe faili. Ati pe a nilo awọn titiipa lati ṣe iṣe ihuwasi pataki ti a ṣalaye loke.

A ti ṣetan ni bayi lati ṣe ibeere koodu orisun ti ekuro labẹ ina atupa lati jẹrisi tabi tako awoṣe ọpọlọ aiduro wa. Ṣugbọn nigbagbogbo mura silẹ fun airotẹlẹ.

Nibo ni a nwa?

Emi ko mọ ibiti ẹda mi ti iwe olokiki wa.Iwe kiniun"pẹlu Unix 6 koodu orisun, ṣugbọn ọpẹ si Unix Heritage Society le wa lori ayelujara orisun koodu ani agbalagba awọn ẹya ti Unix.

Lilọ kiri nipasẹ awọn ile-ipamọ TUHS dabi ṣiṣabẹwo si musiọmu kan. A le wo itan-akọọlẹ ti a pin ati pe Mo ni ibowo fun awọn ọdun igbiyanju lati gba gbogbo ohun elo yii pada nipasẹ bit nipasẹ awọn kasẹti atijọ ati awọn atẹjade. Ati pe Mo mọye gaan ti awọn ajẹkù yẹn ti wọn ṣi nsọnu.

Nini itẹlọrun iwariiri wa nipa itan-akọọlẹ atijọ ti awọn opo gigun ti epo, a le wo awọn ohun kohun ode oni fun lafiwe.

Nipa ọna, pipe jẹ nọmba ipe eto 42 ninu tabili sysent[]. Lasan?

Awọn ekuro Unix ti aṣa (1970–1974)

Emi ko ri itọpa kankan pipe(2) bẹni ni PDP-7 Unix (January 1970), tabi ni akọkọ àtúnse Unix (Oṣu kọkanla ọdun 1971), tabi ni koodu orisun ti ko pe keji àtúnse (Osu Kefa 1972).

TUHS sọ pe kẹta àtúnse Unix (Kínní ọdún 1973) jẹ́ ẹ̀yà àkọ́kọ́ pẹ̀lú àwọn ọ̀nà pipe:

Ẹya kẹta ti Unix jẹ ẹya ti o kẹhin pẹlu ekuro ti a kọ sinu apejọ, ṣugbọn tun ẹya akọkọ pẹlu awọn paipu. Ni ọdun 1973, iṣẹ ti nlọ lọwọ lati mu ilọsiwaju ti ẹda kẹta dara, a tun kọ ekuro ni C, ati nitorinaa ẹda kẹrin ti Unix ni a bi.

Oluka kan rii ọlọjẹ ti iwe kan ninu eyiti Doug McIlroy dabaa imọran “awọn eto sisopọ bii okun ọgba.”

Bii o ti ṣe imuse awọn opo gigun ti epo ni Unix
Ninu iwe Brian KernighanUnix: Itan kan ati Akọsilẹ kan", awọn itan ti hihan conveyors tun nmẹnuba iwe yi: "... o so lori odi ni ọfiisi mi ni Bell Labs fun 30 ọdun." Nibi ifọrọwanilẹnuwo pẹlu McIlroyati itan miiran lati Iṣẹ McIlroy, ti a kọ ni ọdun 2014:

Nigbati Unix han, ifẹ mi fun awọn coroutines jẹ ki n beere lọwọ onkọwe OS, Ken Thompson, lati gba data ti a kọ si ilana kan lati lọ kii ṣe si ẹrọ nikan, ṣugbọn tun si ijade si ilana miiran. Ken ro pe o ṣee ṣe. Sibẹsibẹ, bi minimalist, o fẹ ki gbogbo ẹya eto lati ṣe ipa pataki. Njẹ kikọ taara laarin awọn ilana jẹ anfani nla lori kikọ si faili agbedemeji? Ati ki o nikan nigbati mo ti ṣe kan pato si imọran pẹlu awọn catchy orukọ "pipeline" ati awọn apejuwe ti awọn sintasi ti awọn ibaraenisepo ti awọn ilana, Ken nipari kigbe: "Emi yoo se o!".

O si ṣe. Ni irọlẹ ayanmọ kan, Ken yi ekuro ati ikarahun pada, ṣeto ọpọlọpọ awọn eto boṣewa lati ṣe iwọn bi wọn ṣe gba titẹ sii (eyiti o le wa lati opo gigun ti epo), ati yi awọn orukọ faili pada. Ni ọjọ keji, awọn opo gigun ti epo ni lilo pupọ ni awọn ohun elo. Ni opin ọsẹ, awọn akọwe lo wọn lati fi awọn iwe aṣẹ ranṣẹ lati awọn olutọpa ọrọ si itẹwe. Ni diẹ lẹhinna, Ken rọpo API atilẹba ati sintasi fun fifi ipari si lilo awọn opo gigun ti epo pẹlu awọn apejọ mimọ ti a ti lo lati igba naa.

Laanu, koodu orisun fun ekuro Unix kẹta ti sọnu. Ati pe botilẹjẹpe a ni koodu orisun kernel ti a kọ sinu C kẹrin àtúnse, eyiti a ti tu silẹ ni Oṣu kọkanla ọdun 1973, ṣugbọn o jade ni awọn oṣu diẹ ṣaaju itusilẹ osise ati pe ko ni imuse awọn opo gigun ti epo. O jẹ aanu pe koodu orisun fun ẹya Unix arosọ yii ti sọnu, boya lailai.

A ni ọrọ iwe fun pipe(2) lati awọn idasilẹ mejeeji, nitorinaa o le bẹrẹ nipasẹ wiwa iwe naa kẹta àtúnse (fun awọn ọrọ kan, ti a ṣe abẹlẹ “pẹlu ọwọ”, okun kan ti awọn ọrọ gangan ^H ti o tẹle pẹlu abẹlẹ!). Ilana yii-pipe(2) ti kọ sinu apejọ ati dapada apejuwe faili kan nikan, ṣugbọn tẹlẹ pese iṣẹ ṣiṣe mojuto ti a nireti:

Ipe eto pipe ṣẹda ẹrọ I/O ti a npe ni opo gigun ti epo. Apejuwe faili ti o pada le ṣee lo fun awọn iṣẹ kika ati kikọ. Nigbati ohun kan ba kọ si opo gigun ti epo, o fa soke si awọn baiti 504 ti data, lẹhinna ilana kikọ ti daduro. Nigbati o ba ka lati opo gigun ti epo, a mu data buffered.

Ni ọdun to nbọ, a ti tun kọ ekuro ni C, ati paipu (2) kẹrin àtúnse ti gba iwo ode oni pẹlu apẹrẹ”pipe(fildes)»:

Ipe eto pipe ṣẹda ẹrọ I/O ti a npe ni opo gigun ti epo. Awọn apejuwe faili ti o pada le ṣee lo ni awọn iṣẹ kika ati kikọ. Nigba ti a ba kọ nkan si opo gigun ti epo, aṣàpèjúwe naa pada ni r1 (resp. fildes [1]) ti lo, ti a fi silẹ si awọn baiti 4096 ti data, lẹhin eyi ti ilana kikọ ti daduro. Nigbati kika lati opo gigun ti epo, apejuwe pada si r0 (resp. fildes [0]) gba data naa.

A ro pe ni kete ti a ti ṣalaye opo gigun ti epo, awọn ilana ibaraenisepo meji (tabi diẹ sii) (ti a ṣẹda nipasẹ awọn ẹbẹ ti o tẹle orita) yoo kọja data lati opo gigun ti epo nipa lilo awọn ipe ka и kọ.

Ikarahun naa ni sintasi kan fun asọye ọna ila ti awọn ilana ti a ti sopọ nipasẹ opo gigun ti epo kan.

Awọn ipe lati ka lati opo gigun ti epo ti o ṣofo (ti ko ni data ti a fi silẹ) ti o ni opin kan nikan (gbogbo awọn apejuwe faili kikọ ni pipade) pada “ipari faili”. Kọ awọn ipe ni iru ipo ti wa ni bikita.

Ni iṣaaju imuse opo gigun ti epo tọkasi si karun àtúnse ti Unix (June 1974), ṣugbọn o fẹrẹ jẹ aami kanna ti o han ninu itusilẹ ti nbọ. Awọn asọye nikan ni a ṣafikun, nitorinaa ẹda karun le fo.

Ẹ̀dà Unix kẹfà (1975)

Bibẹrẹ lati ka koodu orisun Unix kẹfa àtúnse (Oṣu karun ọdun 1975). Ibebe ọpẹ si kiniun o rọrun pupọ lati wa ju awọn orisun ti awọn ẹya iṣaaju lọ:

Fun opolopo odun iwe kiniun jẹ iwe-ipamọ nikan lori ekuro Unix ti o wa ni ita ti Bell Labs. Bó tilẹ̀ jẹ́ pé ìwé àṣẹ ẹ̀dà kẹfà gba àwọn olùkọ́ láyè láti lo kóòdù orísun rẹ̀, ìwé àṣẹ àtúnṣe keje kò yọ̀ọ̀da yìí, nítorí náà, wọ́n pín ìwé náà sínú àwọn ẹ̀dà ẹ̀dà tí kò bófin mu.

Loni o le ra ẹda atuntẹ ti iwe naa, ideri eyiti o ṣe afihan awọn ọmọ ile-iwe ni oludaakọ. Ati ọpẹ si Warren Toomey (ẹniti o bẹrẹ iṣẹ TUHS), o le ṣe igbasilẹ Orisun Ẹda kẹfa PDF. Mo fẹ lati fun ọ ni imọran bi igbiyanju pupọ ṣe lọ si ṣiṣẹda faili naa:

Ni ọdun 15 sẹhin, Mo ti tẹ ẹda koodu orisun ti a pese sinu kiniunnitori Emi ko fẹran didara ẹda mi lati nọmba aimọ ti awọn ẹda miiran. TUHS ko si tẹlẹ, ati pe Emi ko ni iwọle si awọn orisun atijọ. Ṣugbọn ni ọdun 1988 Mo rii teepu atijọ kan pẹlu awọn orin 9 ti o ni afẹyinti lati kọnputa PDP11 kan. O nira lati mọ boya o ṣiṣẹ, ṣugbọn igi / usr / src kan wa ninu eyiti ọpọlọpọ awọn faili ti samisi ni ọdun 1979, eyiti paapaa lẹhinna dabi atijọ. O jẹ ẹda keje, tabi itọsẹ PWB, Mo ro.

Mo mu wiwa naa gẹgẹbi ipilẹ ati ọwọ satunkọ awọn orisun si ipo ti ẹda kẹfa. Apakan koodu naa wa bakan naa, apakan ni lati ṣatunkọ diẹ, yiyipada ami-ami ode oni += si ti atijo =+. Nkankan ti paarẹ nirọrun, ati pe ohun kan ni lati tun kọ patapata, ṣugbọn kii ṣe pupọ.

Ati loni a le ka lori ayelujara ni TUHS koodu orisun ti ẹda kẹfa ti pamosi, eyi ti Dennis Ritchie ní a ọwọ.

Nipa ọna, ni iwo akọkọ, ẹya akọkọ ti koodu C ṣaaju akoko Kernighan ati Ritchie jẹ tirẹ. kukuru. Kii ṣe igbagbogbo pe Mo ni anfani lati fi awọn snippets ti koodu sii laisi ṣiṣatunṣe lọpọlọpọ lati baamu agbegbe ifihan ti o dín jo lori aaye mi.

Ni ibẹrẹ /usr/sys/ken/pipe.c asọye asọye wa (ati bẹẹni, diẹ sii wa /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

Iwọn ifipamọ ko yipada lati ẹda kẹrin. Ṣugbọn nibi a rii, laisi eyikeyi iwe ti gbogbo eniyan, awọn opo gigun ti epo ni ẹẹkan lo awọn faili bi ibi ipamọ ipadabọ!

Bi fun awọn faili LARG, wọn ṣe deede si inode-flag LARG, eyiti o jẹ lilo nipasẹ “algoridimu adirẹsi nla” lati ṣe ilana aiṣe-taara ohun amorindun lati ṣe atilẹyin awọn ọna ṣiṣe faili nla. Niwọn bi Ken ti sọ pe o dara ki a ma lo wọn, lẹhinna Emi yoo fi ayọ gba ọrọ rẹ fun.

Eyi ni ipe eto gidi 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;
}

Ọrọìwòye ṣe apejuwe ohun ti n ṣẹlẹ ni kedere. Ṣugbọn kii ṣe rọrun lati ni oye koodu naa, ni apakan nitori bii “olumulo igbekale u»ati awọn iforukọsilẹ R0 и R1 Awọn paramita ipe eto ati awọn iye ipadabọ ti kọja.

Jẹ ká gbiyanju pẹlu ialloc() gbe lori disk inode (inode), ati pẹlu iranlọwọ falloc() - itaja meji faili. Ti ohun gbogbo ba lọ daradara, a yoo ṣeto awọn asia lati ṣe idanimọ awọn faili wọnyi bi awọn opin meji ti opo gigun ti epo, tọka wọn si inode kanna (eyiti kika itọkasi rẹ di 2), ati samisi inode bi ti yipada ati lilo. San ifojusi si awọn ibeere lati ipa () ni awọn ọna aṣiṣe lati dinku kika itọkasi ni inode tuntun.

pipe() nitori nipasẹ R0 и R1 pada faili apejuwe awọn nọmba fun kika ati kikọ. falloc() da a ijuboluwole si a file be, sugbon tun "pada" nipasẹ u.u_ar0[R0] ati apejuwe faili. Iyẹn ni, koodu ti wa ni ipamọ r Apejuwe faili fun kika ati ki o sọtọ a apejuwe fun kikọ taara lati u.u_ar0[R0] lẹhin ipe keji falloc().

Flag FPIPE, eyiti a ṣeto nigbati o ṣẹda opo gigun ti epo, n ṣakoso ihuwasi ti iṣẹ naa rdwr () ninu sys2.c, eyiti o pe awọn ilana I/O kan pato:

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

Lẹhinna iṣẹ naa readp() в pipe.c ka data lati opo gigun ti epo. Ṣugbọn o dara lati wa kakiri imuse ti o bẹrẹ lati writep(). Lẹẹkansi, koodu naa ti di idiju diẹ sii nitori iru ariyanjiyan ti o kọja apejọ, ṣugbọn diẹ ninu awọn alaye le yọkuro.

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

A fẹ kọ awọn baiti si igbewọle opo gigun ti epo u.u_count. Ni akọkọ a nilo lati tii inode (wo isalẹ plock/prele).

Lẹhinna a ṣayẹwo iye itọkasi inode. Niwọn igba ti awọn opin mejeeji ti opo gigun ti epo wa ni sisi, counter yẹ ki o jẹ 2. A dimu si ọna asopọ kan (lati rp->f_inode), nitorina ti counter ba kere ju 2, lẹhinna eyi yẹ ki o tumọ si pe ilana kika ti pa opin rẹ ti opo gigun ti epo. Ni awọn ọrọ miiran, a n gbiyanju lati kọ si opo gigun ti epo, eyiti o jẹ aṣiṣe. Koodu aṣiṣe akọkọ EPIPE ati ifihan agbara SIGPIPE han ni kẹfa àtúnse ti Unix.

Sugbon paapa ti o ba awọn conveyor wa ni sisi, o le jẹ ni kikun. Ni idi eyi, a tu titiipa silẹ ki o lọ sùn ni ireti pe ilana miiran yoo ka lati inu opo gigun ti epo ati ki o gba aaye ti o to ninu rẹ. Nigba ti a ba ji, a pada si ibẹrẹ, gbe titiipa soke lẹẹkansi ati bẹrẹ ọna kikọ tuntun kan.

Ti aaye ọfẹ ba wa ni opo gigun ti epo, lẹhinna a kọ data si rẹ nipa lilo kọ ()... Paramita i_size1 inode'a (pẹlu opo gigun ti o ṣofo le jẹ dogba si 0) tọka si opin data ti o wa ninu tẹlẹ. Ti aaye to ba wa lati kọ, a le kun opo gigun ti epo lati i_size1 si PIPESIZ. Lẹhinna a tu titiipa silẹ ki o gbiyanju lati ji eyikeyi ilana ti o nduro lati ka lati opo gigun ti epo. A pada si ibẹrẹ lati rii boya a ṣakoso lati kọ ọpọlọpọ awọn baiti bi a ṣe nilo. Ti kii ba ṣe bẹ, lẹhinna a bẹrẹ ọmọ igbasilẹ tuntun kan.

Nigbagbogbo paramita i_mode inode ti lo lati tọju awọn igbanilaaye r, w и x. Ṣugbọn ninu ọran ti awọn opo gigun ti epo, a ṣe ifihan pe diẹ ninu awọn ilana n duro de kikọ tabi kika nipa lilo awọn die-die IREAD и IWRITE lẹsẹsẹ. Ilana naa ṣeto asia ati awọn ipe sleep(), ati pe o nireti pe ni ọjọ iwaju diẹ ninu awọn ilana miiran yoo pe wakeup().

Idan gidi ṣẹlẹ ni sleep() и wakeup(). Wọn ti wa ni imuse ni slp.c, orisun ti olokiki "O ko nireti lati ni oye eyi" asọye. Ni Oriire, a ko ni lati loye koodu naa, kan wo diẹ ninu awọn asọye:

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

Ilana ti o pe sleep() fun kan pato ikanni, le nigbamii ti wa ni ji nipa miiran ilana, eyi ti yoo pe wakeup() fun kanna ikanni. writep() и readp() ipoidojuko awọn iṣe wọn nipasẹ iru awọn ipe ti a so pọ. ṣe akiyesi pe pipe.c nigbagbogbo ayo PPIPE nigbati a npe ni sleep(), nitorina gbogbo sleep() le ti wa ni Idilọwọ nipa a ifihan agbara.

Bayi a ni ohun gbogbo lati ni oye iṣẹ naa 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);
}

O le rii pe o rọrun lati ka iṣẹ yii lati isalẹ de oke. Ẹka “ka ati ipadabọ” ni a maa n lo nigbati data diẹ wa ninu opo gigun ti epo. Ni idi eyi, a lo ka() ka bi data pupọ ti o wa ti o bẹrẹ lati lọwọlọwọ f_offset ka, ati ki o mu awọn iye ti awọn ti o baamu aiṣedeede.

Lori awọn kika atẹle, opo gigun ti epo yoo ṣofo ti aiṣedeede kika ba ti de i_size1 ni inode. A tun ipo naa pada si 0 ati gbiyanju lati ji eyikeyi ilana ti o fẹ lati kọ si opo gigun ti epo. A mọ pe nigbati awọn conveyor ti kun, writep() sun oorun lori ip+1. Ati ni bayi pe opo gigun ti epo ti ṣofo, a le ji dide lati tun bẹrẹ iyipo kikọ rẹ.

Ti ko ba si nkankan lati ka, lẹhinna readp() le ṣeto asia IREAD si ti kuna sun oorun lori ip+2. A mọ ohun ti yoo ji i writep()nigbati o kọ diẹ ninu awọn data si opo gigun ti epo.

Comments lori ka () ati kọ () yoo ran ọ lọwọ lati loye pe dipo gbigbe awọn paramita nipasẹ”u»A le ṣe itọju wọn bii awọn iṣẹ I/O deede ti o mu faili kan, ipo kan, ifipamọ ni iranti, ati ka nọmba awọn baiti lati ka tabi kọ.

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

Bi fun "Konsafetifu" ìdènà, lẹhinna readp() и writep() tii inodes titi wọn o fi pari tabi gba abajade (ie ipe wakeup). plock() и prele() ṣiṣẹ nìkan: lilo kan ti o yatọ ṣeto ti awọn ipe sleep и wakeup gba wa laaye lati ji eyikeyi ilana ti o nilo titiipa ti a ṣẹṣẹ tu silẹ:

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

Ni akọkọ Emi ko le loye idi readp() ko fa prele(ip) ṣaaju ipe wakeup(ip+1). Ohun akọkọ writep() Awọn ipe ninu awọn oniwe-lupu, yi plock(ip), eyi ti àbábọrẹ ni a deadlock ti o ba ti readp() ko tii yọ bulọọki rẹ kuro sibẹsibẹ, nitorinaa koodu gbọdọ ṣiṣẹ bakan ni deede. Ti o ba wo wakeup(), o han gbangba pe o jẹ ami si ilana sisun nikan bi o ti ṣetan fun ipaniyan, ki ni ojo iwaju sched() gan se igbekale o. Nitorina readp() awọn okunfa wakeup(), ṣiṣi silẹ, ṣeto IREAD ati awọn ipe sleep(ip+2)- gbogbo eyi ṣaaju writep() tun bẹrẹ ọmọ.

Eyi pari apejuwe awọn pipeline ni ẹda kẹfa. Koodu ti o rọrun, awọn ilolu ti o jinna.

Ẹda Keje Unix (January 1979) jẹ itusilẹ pataki tuntun (ọdun mẹrin lẹhinna) ti o ṣafihan ọpọlọpọ awọn ohun elo tuntun ati awọn ẹya ekuro. O tun ti ṣe awọn ayipada pataki ni asopọ pẹlu lilo iru simẹnti, awọn ẹgbẹ ati awọn itọka titẹ si awọn ẹya. Sibẹsibẹ pipelines koodu Oba ko yi pada. A le foju yi àtúnse.

Xv6, ekuro ti o dabi Unix ti o rọrun

Lati ṣẹda arin Xv6 nfa nipasẹ awọn kẹfa àtúnse ti Unix, sugbon ti kọ ni igbalode C lati ṣiṣe lori x86 nse. Koodu naa rọrun lati ka ati oye. Paapaa, ko dabi awọn orisun Unix pẹlu TUHS, o le ṣajọ rẹ, yipada, ki o ṣiṣẹ lori nkan miiran yatọ si PDP 11/70. Nitorinaa, mojuto yii ni lilo pupọ ni awọn ile-ẹkọ giga bi ohun elo ikọni lori awọn ọna ṣiṣe. Awọn orisun wa lori Github.

Awọn koodu ni kan ko o ati laniiyan imuse pipe.c, ṣe atilẹyin nipasẹ ifipamọ ni iranti dipo inode lori disk. Nibi Mo fun ni asọye nikan ti “paipu opo” ati iṣẹ naa 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() ṣeto ipo ti gbogbo awọn iyokù imuse, eyiti o pẹlu awọn iṣẹ piperead(), pipewrite() и pipeclose(). Awọn gangan eto ipe sys_pipe ti wa ni a wrapper muse ni sysfile.c. Mo ṣeduro kika gbogbo koodu rẹ. Idiju naa wa ni ipele ti koodu orisun ti ẹda kẹfa, ṣugbọn o rọrun pupọ ati diẹ sii dídùn lati ka.

Linux 0.01

O le wa koodu orisun fun Linux 0.01. Yoo jẹ itọnisọna lati ṣe iwadi imuse ti awọn opo gigun ti epo ni tirẹ fs/pipe.c. Nibi, a ti lo inode lati ṣe aṣoju opo gigun ti epo, ṣugbọn opo gigun ti ara rẹ ni a kọ ni igbalode C. Ti o ba ti gepa ọna rẹ nipasẹ koodu ẹda kẹfa, iwọ kii yoo ni wahala nibi. Eyi ni ohun ti iṣẹ naa dabi 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;
}

Paapaa laisi wiwo awọn asọye igbekale, o le ro ero bawo ni a ṣe lo kika itọkasi inode lati ṣayẹwo boya iṣẹ ṣiṣe kikọ ba ni abajade SIGPIPE. Ni afikun si iṣẹ baiti-nipasẹ-baiti, iṣẹ yii rọrun lati ṣe afiwe pẹlu awọn ero ti o wa loke. Ani ogbon sleep_on/wake_up ko dabi ajeji.

Awọn ekuro Linux ode oni, FreeBSD, NetBSD, OpenBSD

Mo yara lọ lori diẹ ninu awọn ekuro ode oni. Ko si ọkan ninu wọn ti ni imuse orisun disiki (kii ṣe iyalẹnu). Lainos ni imuse tirẹ. Ati pe botilẹjẹpe awọn ekuro BSD ode oni mẹta ni awọn imuse ti o da lori koodu ti a kọ nipasẹ John Dyson, ni awọn ọdun diẹ wọn ti yatọ pupọ si ara wọn.

Lati ka fs/pipe.c (lori Linux) tabi sys/kern/sys_pipe.c (lori * BSD), o gba iyasọtọ gidi. Iṣe ati atilẹyin fun awọn ẹya bii fekito ati asynchronous I/O ṣe pataki ni koodu loni. Ati awọn alaye ti ipin iranti, awọn titiipa, ati iṣeto ekuro gbogbo yatọ pupọ. Eyi kii ṣe ohun ti awọn ile-ẹkọ giga nilo fun ikẹkọ iṣafihan lori awọn ọna ṣiṣe.

Ni eyikeyi idiyele, o jẹ iyanilenu fun mi lati ṣawari awọn ilana atijọ diẹ (fun apẹẹrẹ, ti ipilẹṣẹ SIGPIPE ati pada EPIPE nigba kikọ si opo gigun ti epo) ni gbogbo iwọnyi, ti o yatọ, awọn kernels ode oni. Emi kii yoo rii kọnputa PDP-11 laaye laaye, ṣugbọn ọpọlọpọ tun wa lati kọ ẹkọ lati koodu ti a kọ ni ọdun diẹ ṣaaju ki a bi mi.

Ti a kọ nipasẹ Divi Kapoor ni ọdun 2011, nkan naa "Awọn imuse Ekuro Linux ti Awọn paipu ati awọn FIFOjẹ ẹya Akopọ ti bi Linux pipelines (ki jina) ṣiṣẹ. A laipe ṣẹ on Linux ṣe apejuwe apẹẹrẹ opo gigun ti ibaraenisepo, eyiti awọn agbara rẹ kọja ti awọn faili igba diẹ; ati pe o tun fihan bawo ni awọn opo gigun ti lọ lati “titiipa Konsafetifu pupọ” ni ẹda Unix ekuro kẹfa.

orisun: www.habr.com

Fi ọrọìwòye kun