Ki jan tiyo yo aplike nan Unix

Ki jan tiyo yo aplike nan Unix
Atik sa a dekri aplikasyon tiyo nan nwayo Unix la. Mwen te yon ti jan wont ke yon dènye atik ki gen tit "Ki jan tiyo yo travay nan Unix?» te tounen soti pa gen okenn sou estrikti entèn la. Mwen te vin kirye ak fouye nan ansyen sous yo jwenn repons lan.

De kisa nap pale?

Pipelines yo se "pwobableman envansyon ki pi enpòtan nan Unix" - yon karakteristik defini nan filozofi ki kache nan Unix nan mete ansanm ti pwogram yo, ak eslogan liy kòmand yo abitye:

$ echo hello | wc -c
6

Fonksyonalite sa a depann de apèl sistèm kenel bay la pipe, ki dekri nan paj dokiman yo tiyo (7) и tiyo (2):

Pipelines bay yon kanal yon sèl pou kominikasyon ant pwosesis. Tiyo a gen yon opinyon (ekri fen) ak yon pwodiksyon (li fen). Done ekri nan opinyon tiyo a ka li nan pwodiksyon an.

Se tiyo a kreye lè w rele pipe(2), ki retounen de deskriptè dosye: youn refere a opinyon tiyo a, dezyèm lan nan pwodiksyon an.

Pwodiksyon tras ki soti nan kòmandman ki anwo a montre kreyasyon yon tiyo ak koule nan done atravè li soti nan yon pwosesis nan yon lòt:

$ 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

Pwosesis paran an rele pipe()pou jwenn deskriptè dosye ki tache. Yon pwosesis timoun ekri nan yon deskriptè epi yon lòt pwosesis li menm done ki soti nan yon lòt deskriptè. Koki a "chanje non" deskriptè 2 ak 3 ak dup4 pou matche stdin ak stdout.

San tiyo, koki a ta dwe ekri pwodiksyon yon pwosesis nan yon dosye epi tiyo li nan yon lòt pwosesis pou li done ki soti nan dosye a. Kòm yon rezilta, nou ta gaspiye plis resous ak espas disk. Sepandan, tiyo yo bon pou plis pase jis evite dosye tanporè:

Si yon pwosesis eseye li nan yon tiyo vid, lè sa a read(2) pral bloke jiskaske done yo disponib. Si yon pwosesis eseye ekri nan yon tiyo plen, lè sa a write(2) pral bloke jiskaske ase done yo te li nan tiyo a ranpli ekri a.

Menm jan ak egzijans POSIX, sa a se yon pwopriyete enpòtan: ekri nan tiyo a jiska PIPE_BUF bytes (omwen 512) dwe atomik pou pwosesis yo ka kominike youn ak lòt atravè tiyo a nan yon fason ke dosye nòmal (ki pa bay garanti sa yo) pa kapab.

Avèk yon dosye regilye, yon pwosesis ka ekri tout pwodiksyon li yo nan li epi pase li nan yon lòt pwosesis. Oswa pwosesis yo ka opere nan yon mòd paralèl difisil, lè l sèvi avèk yon mekanis siyal ekstèn (tankou yon semafò) enfòme youn ak lòt sou fini an nan yon ekri oswa li. Transporteurs sove nou anba tout traka sa yo.

Kisa nap chache?

Mwen pral eksplike sou dwèt mwen pou fè li pi fasil pou ou imajine ki jan yon CONVEYOR ka travay. Ou pral bezwen asiyen yon tanpon ak kèk eta nan memwa. W ap bezwen fonksyon pou ajoute epi retire done nan tanpon an. Ou pral bezwen kèk etablisman pou rele fonksyon pandan operasyon lekti ak ekri sou deskriptè dosye yo. Ak kadna yo bezwen aplike konpòtman espesyal ki dekri pi wo a.

Kounye a nou pare pou n entèwoje kòd sous nwayo a anba limyè klere pou konfime oswa demanti modèl mantal vag nou an. Men, toujou pare pou inatandi.

Kote nap chache?

Mwen pa konnen ki kote kopi mwen an nan liv la pi popilè manti.Liv lyon« ak kòd sous Unix 6, men gras a Sosyete Eritaj Unix ka fouye sou entènèt kòd sous menm ansyen vèsyon Unix.

Pèdi nan achiv TUHS yo se tankou vizite yon mize. Nou ka gade istwa nou pataje epi mwen gen respè pou ane efò yo te fè pou rekipere tout materyèl sa a ti pa ti kras nan ansyen kasèt ak enprime. Apre sa, mwen byen konsyan de fragman sa yo ki toujou manke.

Èske w gen satisfè kiryozite nou sou istwa a ansyen nan tiyo, nou ka gade nan nwayo modèn pou konparezon.

By wout la, pipe se nimewo apèl sistèm 42 nan tablo a sysent[]. Konyensidans?

Nwayo tradisyonèl Unix (1970–1974)

Mwen pa jwenn okenn tras pipe(2) ni nan PDP-7 Unix (Janvye 1970), ni nan premye edisyon Unix (Novanm 1971), ni nan kòd sous enkonplè dezyèm edisyon (Jen 1972).

TUHS reklamasyon sa twazyèm edisyon Unix (Fevriye 1973) se te premye vèsyon an ak tiyo:

Twazyèm edisyon Unix te dènye vèsyon an ak yon nwayo ekri nan asanblaj, men tou, premye vèsyon an ak tiyo. Pandan lane 1973, travay te fèt pou amelyore twazyèm edisyon an, nwayo a te reekri an C, e konsa katriyèm edisyon Unix te fèt.

Yon lektè te jwenn yon eskanè nan yon dokiman kote Doug McIlroy te pwopoze lide pou "konekte pwogram tankou yon kawotchou jaden."

Ki jan tiyo yo aplike nan Unix
Nan liv Brian Kernighan aUnix: Yon istwa ak yon memwa", istwa a nan aparans nan transporteurs tou mansyone dokiman sa a: "... li te pandye sou miray la nan biwo mwen an nan Bell Labs pou 30 ane." Isit la entèvyou ak McIlroyak yon lòt istwa soti nan Travay McIlroy a, ekri nan 2014:

Lè Unix te parèt, pasyon mwen pou coroutines te fè m mande otè OS la, Ken Thompson, pou pèmèt done ekri nan kèk pwosesis ale non sèlman nan aparèy la, men tou nan sòti nan yon lòt pwosesis. Ken te panse li te posib. Sepandan, kòm yon minimalist, li te vle chak karakteristik sistèm yo jwe yon wòl enpòtan. Èske ekri dirèk ant pwosesis reyèlman yon gwo avantaj sou ekri nan yon dosye entèmedyè? Epi sèlman lè mwen te fè yon pwopozisyon espesifik ak non atiran "pipeline" ak yon deskripsyon sentaks nan entèraksyon an nan pwosesis, Ken finalman eksklame: "Mwen pral fè li!".

Epi li te fè. Yon aswè fatal, Ken te chanje nwayo a ak kokiy, li te ranje plizyè pwogram estanda pou estandadize fason yo aksepte opinyon (ki ta ka soti nan yon tiyo), epi li chanje non fichye yo. Nan denmen, tiyo yo te trè lajman itilize nan aplikasyon yo. Nan fen semèn nan, sekretè yo te itilize yo pou voye dokiman ki soti nan prosesè tèks nan enprimant lan. Yon ti jan pita, Ken te ranplase API orijinal la ak sentaks pou vlope itilizasyon tiyo ak konvansyon ki pi pwòp ki te itilize depi lè sa a.

Malerezman, kòd sous la pou twazyèm edisyon Kernel Unix la te pèdi. Ak byenke nou gen kòd sous nwayo a ekri nan C katriyèm edisyon, ki te lage nan Novanm 1973, men li te soti kèk mwa anvan lage ofisyèl la epi li pa genyen aplikasyon an nan tiyo. Li se yon pitye ke kòd sous la pou karakteristik lejand Unix sa a pèdi, petèt pou tout tan.

Nou gen tèks dokimantasyon pou pipe(2) soti nan tou de degaje yo, kidonk, ou ka kòmanse pa rechèch dokiman an twazyèm edisyon (pou sèten mo, souliye "manyèlman", yon seri ^H literal ki te swiv pa yon souliye!). Pwotokòl sa apipe(2) ekri nan asanblaj epi li retounen sèlman yon deskriptè dosye, men li deja bay fonksyonalite debaz yo espere:

Sistèm apèl tiyo kreye yon mekanis I/O ki rele yon tiyo. Yo ka itilize deskriptè fichye a retounen pou operasyon lekti ak ekri. Lè yon bagay ekri nan tiyo a, li tampon jiska 504 bytes nan done, apre sa pwosesis ekri a sispann. Lè w ap li nan tiyo a, yo pran done tanpon yo.

Nan ane annapre a, nwayo a te reekri nan C, ak tiyo(2) katriyèm edisyon akeri aparans modèn li ak pwototip la "pipe(fildes)'

Sistèm apèl tiyo kreye yon mekanis I/O ki rele yon tiyo. Deskriptè dosye yo retounen yo ka itilize nan operasyon lekti ak ekri. Lè yo ekri yon bagay nan tiyo a, deskriptè ki te retounen nan r1 (resp. fildes[1]) yo itilize, tanpon jiska 4096 octets done, apre sa pwosesis ekri a sispann. Lè li nan tiyo a, deskriptè a tounen nan r0 (resp. fildes[0]) pran done yo.

Li sipoze ke yon fwa yo te defini yon tiyo, de (oswa plis) pwosesis entèraksyon (kreye pa envokasyon ki vin apre yo). fouchèt) pral pase done ki soti nan tiyo a lè l sèvi avèk apèl yo li и ekri.

Koki a gen yon sentaks pou defini yon etalaj lineyè pwosesis ki konekte atravè yon tiyo.

Apèl pou li nan yon tiyo vid (ki pa gen done tanpon) ki gen yon sèl fen (tout deskriptè fichye ekri fèmen) retounen "fen fichye". Ekri apèl nan yon sitiyasyon ki sanble yo inyore.

Pi bonè aplikasyon tiyo konsève gen rapò nan senkyèm edisyon nan Unix (Jen 1974), men li prèske idantik ak sa ki te parèt nan pwochen lage a. Sèlman te ajoute kòmantè, kidonk senkyèm edisyon an ka sote.

Sizyèm Edisyon Unix (1975)

Kòmanse li kòd sous Unix sizyèm edisyon (Me 1975). An gwo gras a Lyon li pi fasil pou jwenn pase sous vèsyon pi bonè yo:

Pou anpil ane liv la Lyon se te sèl dokiman sou nwayo Unix ki disponib deyò Bell Labs. Malgre ke lisans sizyèm edisyon an te pèmèt pwofesè yo sèvi ak kòd sous li a, lisans setyèm edisyon an eskli posibilite sa a, kidonk liv la te distribye nan kopi ilegal tape.

Jodi a ou ka achte yon kopi reimprime nan liv la, kouvèti a ki dekri elèv yo nan fotokopi a. Ak gras a Warren Toomey (ki te kòmanse pwojè a TUHS), ou ka telechaje Sizyèm Edisyon Sous PDF. Mwen vle ba ou yon lide sou konbyen efò te fè nan kreye dosye a:

Plis pase 15 ane de sa, mwen tape yon kopi kòd sous yo bay nan Lyonpaske mwen pa t renmen kalite kopi mwen an soti nan yon kantite lòt kopi enkoni. TUHS pa t egziste ankò, e mwen pa t gen aksè a ansyen sous yo. Men an 1988 mwen te jwenn yon vye kasèt ak 9 tracks ki te gen yon backup nan yon òdinatè PDP11. Li te difisil pou konnen si li te travay, men te gen yon pyebwa entak /usr/src/ kote pifò nan fichye yo te make 1979, ki menm lè sa a te sanble ansyen. Se te setyèm edisyon an, oswa yon derive PWB, mwen te panse.

Mwen te pran jwenn la kòm yon baz ak manyèlman edited sous yo nan eta a nan sizyèm edisyon an. Yon pati nan kòd la rete menm jan an, yon pati te dwe yon ti kras modifye, chanje siy modèn la += nan demode =+ la. Yon bagay te tou senpleman efase, ak yon bagay te dwe konplètman reekri, men se pa twòp.

Ak jodi a nou ka li sou entènèt nan TUHS kòd sous la nan sizyèm edisyon an achiv, kote Dennis Ritchie te gen yon men.

By wout la, nan premye gade, karakteristik prensipal la nan C-kòd la anvan peryòd Kernighan ak Ritchie se li yo. konsizyon. Li pa souvan ke mwen kapab mete snippets nan kòd san koreksyon vaste anfòm yon zòn ekspozisyon relativman etwat sou sit mwen an.

Nan kòmansman an /usr/sys/ken/pipe.c gen yon kòmantè eksplikasyon (e wi, gen plis /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

Gwosè tanpon an pa chanje depi katriyèm edisyon an. Men, isit la nou wè, san okenn dokiman piblik, ke tiyo yon fwa te itilize dosye kòm depo depo!

Kòm pou fichye LARG, yo koresponn ak inode-drapo LARG, ki itilize pa "gwo algorithm adrese" pou trete blòk endirèk pou sipòte pi gwo sistèm dosye. Depi ke Ken di li pi bon poum pa sèvi ak yo, mwen kontan pran pawòl li pou sa.

Isit la se apèl sistèm reyèl la 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;
}

Kòmantè a dekri byen klè sa k ap pase isit la. Men, li pa fasil pou konprann kòd la, an pati akòz ki jan "struct itilizatè u» ak anrejistre R0 и R1 paramèt apèl sistèm ak valè retounen yo pase.

Ann eseye ak ialloc() mete sou disk inode (inode), ak èd la falloc() - magazen de dosye. Si tout bagay ale byen, nou pral mete drapo pou idantifye fichye sa yo kòm de bout tiyo a, montre yo sou menm inode (ki gen konte referans vin 2), epi make inode la kòm modifye ak nan itilize. Peye atansyon sou demann yo mwen mete() nan chemen erè yo diminye konte referans nan nouvo inode la.

pipe() akòz R0 и R1 retounen nimewo deskriptè dosye pou lekti ak ekri. falloc() retounen yon konsèy nan yon estrikti dosye, men tou, "retounen" atravè u.u_ar0[R0] ak yon deskriptè dosye. Sa vle di, kòd la estoke nan r deskriptè dosye pou lekti epi bay yon deskriptè pou ekri dirèkteman nan u.u_ar0[R0] apre dezyèm apèl falloc().

Drapo FPIPE, ki nou mete lè kreye tiyo a, kontwole konpòtman an nan fonksyon an rdwr() nan sys2.c, ki rele espesifik I / O woutin:

/*
 * 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è sa a, fonksyon an readp() в pipe.c li done ki soti nan tiyo a. Men, li se pi bon trase aplikasyon an kòmanse nan writep(). Yon fwa ankò, kòd la te vin pi konplike akòz nati a nan konvansyon an pase agiman, men kèk detay ka omisyon.

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

Nou vle ekri octets nan opinyon tiyo a u.u_count. Premyèman, nou bezwen fèmen inode la (gade anba a plock/prele).

Lè sa a, nou tcheke konte referans inode. Osi lontan ke tou de bout tiyo a rete louvri, kontwa a ta dwe 2. Nou kenbe sou yon sèl lyen (ki soti nan rp->f_inode), Se konsa, si kontwa a se mwens pase 2, Lè sa a, sa ta dwe vle di ke pwosesis la lekti te fèmen fen tiyo li yo. Nan lòt mo, nou ap eseye ekri nan yon tiyo fèmen, ki se yon erè. Premye kòd erè EPIPE ak siyal SIGPIPE parèt nan sizyèm edisyon Unix.

Men, menm si CONVEYOR la ​​louvri, li ka plen. Nan ka sa a, nou lage seri a epi ale nan dòmi nan espwa ke yon lòt pwosesis pral li nan tiyo a ak libere ase espas nan li. Lè nou reveye, nou retounen nan kòmansman an, rakwoche seri a ankò epi kòmanse yon nouvo sik ekri.

Si gen ase espas gratis nan tiyo a, Lè sa a, nou ekri done sou li lè l sèvi avèk ekri(). Paramèt i_size1 inode'a a (ak yon tiyo vid ka egal a 0) pwen nan fen done yo ke li deja genyen. Si gen ase espas pou ekri, nou ka ranpli tiyo a soti i_size1 до PIPESIZ. Lè sa a, nou lage seri a epi eseye reveye nenpòt pwosesis ki ap tann li nan tiyo a. Nou tounen nan kòmansman an pou wè si nou te rive ekri otan octets ke nou bezwen. Si ou pa, Lè sa a, nou kòmanse yon nouvo sik anrejistreman.

Anjeneral paramèt i_mode inode yo itilize pou estoke otorizasyon yo r, w и x. Men, nan ka a nan tiyo, nou siyal ke kèk pwosesis ap tann pou yon ekri oswa li lè l sèvi avèk Bits IREAD и IWRITE respektivman. Pwosesis la mete drapo a ak apèl sleep(), epi li espere ke nan tan kap vini an kèk lòt pwosesis pral rele wakeup().

Vrè maji a rive nan sleep() и wakeup(). Yo aplike nan slp.c, sous la nan pi popilè "Ou pa atann yo konprann sa a" kòmantè. Erezman, nou pa bezwen konprann kòd la, jis gade kèk kòmantè:

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

Pwosesis la ki rele sleep() pou yon kanal patikilye, ka pita dwe reveye pa yon lòt pwosesis, ki pral rele wakeup() pou menm chanèl la. writep() и readp() kowòdone aksyon yo atravè apèl pè sa yo. sonje ke pipe.c toujou bay priyorite PPIPE lè yo rele sleep(), se konsa tout sleep() ka entèwonp pa yon siyal.

Koulye a, nou gen tout bagay yo konprann fonksyon an 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);
}

Ou ta ka jwenn li pi fasil pou li fonksyon sa a anba nan tèt. Se branch "li epi retounen" anjeneral yo itilize lè gen kèk done nan tiyo a. Nan ka sa a, nou itilize li () li done otan ki disponib apati de aktyèl la f_offset li, epi mete ajou valè konpanse ki koresponn lan.

Nan lekti ki vin apre yo, tiyo a pral vid si konpanse lekti a rive i_size1 nan inode la. Nou reset pozisyon an 0 epi eseye reveye nenpòt pwosesis ki vle ekri nan tiyo a. Nou konnen ke lè transporteur a plen, writep() tonbe nan dòmi sou ip+1. Epi kounye a ke tiyo a vid, nou ka reveye li pou rekòmanse sik ekri li yo.

Si pa gen anyen pou li, lè sa a readp() ka mete yon drapo IREAD epi tonbe nan dòmi sou ip+2. Nou konnen sa ki pral reveye l writep()lè li ekri kèk done nan tiyo a.

Kòmantè sou li () epi ekri() pral ede w konprann ke olye pou yo pase paramèt nan "u» nou ka trete yo tankou fonksyon I/O regilye ki pran yon dosye, yon pozisyon, yon tanpon nan memwa, epi konte kantite byte pou li oswa ekri.

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

Kòm pou "konsèvatif" bloke, lè sa a readp() и writep() fèmen inodes jiskaske yo fini oswa jwenn yon rezilta (sa vle di rele wakeup). plock() и prele() travay tou senpleman: lè l sèvi avèk yon seri diferan nan apèl sleep и wakeup pèmèt nou reveye nenpòt pwosesis ki bezwen kadna nou sot lage a:

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

Okòmansman mwen pa t 'kapab konprann poukisa readp() pa lakòz prele(ip) anvan apèl la wakeup(ip+1). Premye bagay writep() apèl nan bouk li yo, sa a plock(ip), ki rezilta nan yon enpas si readp() poko retire blòk li, kidonk kòd la dwe yon jan kanmenm travay kòrèkteman. Si ou gade wakeup(), li vin klè ke li sèlman make pwosesis la dòmi kòm pare pou ekzekisyon, se konsa ke nan tan kap vini an sched() vrèman te lanse li. Se konsa readp() lakòz wakeup(), déblotché, mete IREAD ak apèl sleep(ip+2)- tout bagay sa yo anvan writep() rekòmanse sik la.

Sa a konplete deskripsyon tiyo nan sizyèm edisyon an. Senp kòd, enplikasyon byen lwen.

Setyèm edisyon Unix (Janvye 1979) se te yon nouvo gwo lage (kat ane pita) ki te prezante anpil nouvo aplikasyon ak karakteristik nwayo. Li te tou sibi chanjman enpòtan an koneksyon avèk itilizasyon kalite Distribisyon, sendika ak endikasyon tape nan estrikti. Sepandan kòd tiyo pratikman pa t chanje. Nou ka sote edisyon sa a.

Xv6, yon nwayo senp tankou Unix

Pou kreye yon nwayo Xv6 enfliyanse pa sizyèm edisyon Unix, men ekri nan modèn C pou kouri sou processeurs x86. Kòd la fasil pou li ak konprann. Epitou, kontrèman ak sous Unix ak TUHS, ou ka konpile li, modifye li, epi kouri li sou yon lòt bagay pase PDP 11/70. Se poutèt sa, nwayo sa a lajman itilize nan inivèsite kòm yon materyèl ansèyman sou sistèm opere. Sous yo sou Github.

Kòd la gen yon aplikasyon klè ak reflechi tiyo.c, te sipòte pa yon tanpon nan memwa olye pou yo yon inode sou disk. Isit la mwen bay sèlman definisyon an nan "tiyo estriktirèl" ak fonksyon an 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() fikse eta a nan tout rès aplikasyon an, ki gen ladan fonksyon piperead(), pipewrite() и pipeclose(). Rele sistèm aktyèl la sys_pipe se yon wrapper aplike nan sysfile.c. Mwen rekòmande li tout kòd li a. Konpleksite a se nan nivo kòd sous la nan sizyèm edisyon an, men li se pi fasil ak pi bèl li.

Linux 0.01

Ou ka jwenn kòd sous la pou Linux 0.01. Li pral édikatif yo etidye aplikasyon an nan tuyaux nan l 'yo fs/pipe.c. Isit la, yo itilize yon inode pou reprezante tiyo a, men tiyo a li menm ekri nan C modèn. Si ou te rache wout ou nan kòd la sizyèm edisyon, ou pa pral gen okenn pwoblèm isit la. Sa a se sa fonksyon an sanble 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;
}

Menm san gade nan definisyon estrikti yo, ou ka konnen ki jan konte referans inode yo itilize pou tcheke si yon operasyon ekri rezilta nan. SIGPIPE. Anplis travay byte-by-byte, fonksyon sa a fasil pou konpare ak lide ki anwo yo. Menm lojik sleep_on/wake_up pa sanble etranje konsa.

Modèn Linux Kernels, FreeBSD, NetBSD, OpenBSD

Mwen byen vit ale sou kèk nwayo modèn. Okenn nan yo pa deja gen yon aplikasyon ki baze sou disk (pa etone). Linux gen pwòp aplikasyon li. Ak byenke twa nwayo BSD modèn yo gen enplemantasyon ki baze sou kòd ki te ekri pa John Dyson, pandan ane yo yo te vin twò diferan youn ak lòt.

Pou li fs/pipe.c (sou Linux) oswa sys/kern/sys_pipe.c (sou *BSD), li pran devouman reyèl. Pèfòmans ak sipò pou karakteristik tankou vektè ak I/O asynchrone yo enpòtan nan kòd jodi a. Ak detay yo sou alokasyon memwa, kadna, ak konfigirasyon nwayo tout varye anpil. Sa a se pa sa inivèsite yo bezwen pou yon kou entwodiksyon sou sistèm opere.

Nan nenpòt ka, li te enteresan pou m 'detire kèk modèl fin vye granmoun (pa egzanp, génération SIGPIPE epi retounen EPIPE lè ekri nan yon tiyo fèmen) nan tout sa yo, konsa diferan, nwayo modèn. Mwen pral pwobableman pa janm wè yon òdinatè PDP-11 ap viv, men gen toujou anpil bagay yo aprann nan kòd la ki te ekri kèk ane anvan mwen te fèt.

Ekri pa Divi Kapoor nan 2011, atik la "Aplikasyon Kernel Linux nan tiyo ak FIFOsse yon apèsi sou kouman Linux tuyaux (jiskaprezan) travay. A dènye komèt sou linux montre modèl entèraksyon tiyo a, ki gen kapasite depase sa yo ki nan dosye tanporè; epi tou montre ki jan lwen tiyo yo te ale nan "trè konsèvatif bloke" nan sizyèm edisyon Unix nwayo a.

Sous: www.habr.com

Add nouvo kòmantè