Pehea e hoʻokō ʻia ai nā pipelines ma Unix

Pehea e hoʻokō ʻia ai nā pipelines ma Unix
Hōʻike kēia ʻatikala i ka hoʻokō ʻana i nā pipeline ma ka kernel Unix. Ua hauʻoli wau i kahi ʻatikala hou i kapa ʻia ʻo "Pehea e hana ai nā pipeline ma Unix?"ua huli mai ole e pili ana i ka hale o loko. Ua lilo au i mea hoihoi a ʻeli au i nā kumu kahiko e ʻike ai i ka pane.

He aha kā mākou e kamaʻilio nei?

ʻO Pipelines, "ʻo ia paha ka mea nui loa ma Unix," he ʻano wehewehe o ka manaʻo kumu Unix o ka hoʻopili ʻana i nā polokalamu liʻiliʻi, a me kahi hōʻailona maʻamau ma ka laina kauoha:

$ echo hello | wc -c
6

Aia kēia hana i ke kelepona ʻōnaehana i hāʻawi ʻia i ka kernel pipe, i wehewehe ʻia ma nā ʻaoʻao palapala paipu(7) и paipu(2):

Hāʻawi nā Pipeline i kahi ala unidirectional no ke kamaʻilio interprocess. Loaʻa i ka pipeline kahi hoʻokomo (kākau hope) a me kahi puka (heluhelu hope). Hiki ke heluhelu ʻia nā ʻikepili i kākau ʻia i ka hoʻokomo o ka pipeline ma ka puka.

Hana ʻia ka pipeline me ke kelepona pipe(2), ka mea e hoʻihoʻi i ʻelua faila wehewehe: ʻo kekahi e pili ana i ka hoʻokomo o ka pipeline, ʻo ka lua i ka puka.

Hōʻike ka trace output mai ke kauoha i luna aʻe i ka hana ʻana o ka pipeline a me ke kahe o ka ʻikepili ma o ia mea mai kekahi kaʻina i kekahi:

$ 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

Kahea ka hana makua pipe()e kiʻi i nā mea wehewehe faila i kau ʻia. Hoʻokahi kaʻina hana keiki e kākau i ka lima hoʻokahi, a ʻo kekahi kaʻina e heluhelu i ka ʻikepili like mai kahi lima ʻē aʻe. Hoʻohana ka shell i ka dup2 e "hōʻano hou" i nā mea wehewehe 3 a me 4 e hoʻokūkū i stdin a me stdout.

Me ka ʻole o nā paipu, pono ka pūpū e kākau i ka hopena o kekahi kaʻina hana i kahi faila a hāʻawi i kekahi kaʻina hana e heluhelu ai i ka ʻikepili mai ka faila. ʻO ka hopena, e hoʻopau mākou i nā kumuwaiwai hou aʻe a me nā wahi disk. Eia nō naʻe, maikaʻi nā pipeline ʻaʻole wale no ka mea e ʻae iā ʻoe e pale i ka hoʻohana ʻana i nā faila manawa:

Inā e hoʻāʻo ana kahi kaʻina e heluhelu mai kahi pipeline ʻole a laila read(2) e ālai a hiki i ka loaʻa ʻana o ka ʻikepili. Inā ho'āʻo kahi hana e kākau i kahi paipu piha, a laila write(2) e ālai ʻia a lawa ka ʻikepili mai ka pipeline e hana i ke kākau.

E like me ke koi POSIX, he waiwai nui kēia: kākau i ka pipeline a hiki i PIPE_BUF ʻO nā bytes (ma ka liʻiliʻi loa he 512) pono ke ʻano atomic i hiki i nā kaʻina hana ke kamaʻilio me kekahi i kekahi ma o ka pipeline ma ke ʻano i hiki ʻole ai i nā faila maʻamau (ʻaʻole hāʻawi i kēlā mau hōʻoia).

I ka hoʻohana ʻana i kahi faila maʻamau, hiki i ke kaʻina hana ke kākau i nā mea i hoʻopuka ʻia iā ia a hāʻawi iā ia i kahi kaʻina hana ʻē aʻe. A i ʻole hiki ke hana i nā kaʻina hana ma kahi ʻano like loa, me ka hoʻohana ʻana i kahi mīkini hōʻailona waho (e like me ka semaphore) e hoʻomaopopo i kekahi i ka wā i pau ai kahi kākau a heluhelu paha. Hoʻopakele nā ​​Conveyors iā mākou mai kēia pilikia āpau.

He aha kā mākou e ʻimi nei?

E wehewehe au iā ia ma nā ʻōlelo maʻalahi i maʻalahi iā ʻoe ke noʻonoʻo pehea e hana ai kahi conveyor. Pono ʻoe e hoʻokaʻawale i kahi buffer a me kekahi mokuʻāina i ka hoʻomanaʻo. Pono ʻoe i nā hana e hoʻohui a wehe i ka ʻikepili mai ka buffer. Pono ʻoe i kahi ala e kāhea ai i nā hana i ka wā heluhelu a kākau i nā hana ma nā faila wehewehe. A pono ʻoe i nā laka e hoʻokō i ke ʻano kūikawā i wehewehe ʻia ma luna.

I kēia manawa ua mākaukau mākou e nīnau i ke kumu kumu kernel ma lalo o ke kukui kukui e hōʻoia a hōʻole i kā mākou kumu hoʻohālike noʻonoʻo. Akā e mākaukau mau no ka mea i manaʻo ʻole ʻia.

Ma hea mākou e ʻimi nei?

ʻAʻole maopopo iaʻu i hea kaʻu kope o ka puke kaulana "puke liona"me Unix 6 source code, akā mahalo iā ʻO ka Unix Heritage Society hiki iā ʻoe ke ʻimi ma ka pūnaewele ma hoʻopā'ālua ʻoiai nā mana kahiko o Unix.

ʻO ka hele ʻana i loko o ka waihona TUHS e like me ke kipa ʻana i kahi hale hōʻikeʻike. Hiki iā mākou ke nānā i kā mākou moʻolelo like, a mahalo wau i nā makahiki he nui o ka hoʻoikaika ʻana e hoʻihoʻi i kēia mau mea āpau mai nā lipine kahiko a me nā paʻi. A ʻike maopopo wau i kēlā mau ʻāpana e nalowale nei.

Ma muli o ko mākou makemake e pili ana i ka mōʻaukala kahiko o nā conveyors, hiki iā mākou ke nānā i nā kernels hou no ka hoʻohālikelike.

Ma ke ala, pipe ʻo ia ka helu kelepona ʻōnaehana 42 ma ka pākaukau sysent[]. ʻAkahi?

Kuʻuna Unix kernels (1970–1974)

ʻAʻole i loaʻa iaʻu kahi meheu pipe(2) ʻaʻole i loko PDP-7 Unix (Ianuali 1970), aole hoi ma paʻi mua o Unix (Novema 1971), ʻaʻole hoʻi i ka helu kumu ʻole paʻi ʻelua (Iune 1972).

Wahi a TUHS paʻi ʻekolu o Unix (Feberuari 1973) i lilo i ka mana mua me nā conveyors:

ʻO Unix 1973rd Edition ka mana hope loa me kahi kernel i kākau ʻia ma ka ʻōlelo hui, akā ʻo ka mana mua pū me nā pipelines. I ka makahiki XNUMX, ua hoʻokō ʻia ka hana e hoʻomaikaʻi i ke kolu o ka paʻi, ua kākau hou ʻia ka kernel ma C, a no laila ua ʻike ʻia ka paʻi ʻehā o Unix.

Ua loaʻa i kahi mea heluhelu kahi scan o kahi palapala i manaʻo ai ʻo Doug McIlroy i ka manaʻo o "hoʻohui ʻana i nā polokalamu e like me ka hose māla."

Pehea e hoʻokō ʻia ai nā pipelines ma Unix
Ma ka puke a Brian KernighanUnix: He Moʻolelo a me ka Memoir", ma ka moʻolelo o ka puka ʻana o nā conveyors, ua ʻōlelo ʻia kēia palapala: "... ua kau ʻia ma ka paia ma koʻu keʻena ma Bell Labs no 30 mau makahiki." Eia ninaninau me McIlroy, a me kekahi moʻolelo mai ʻO ka hana a McIlroy, i kākau ʻia ma 2014:

I ka puka ʻana mai o Unix, ʻo koʻu hoihoi i nā coroutine ua alakaʻi iaʻu e nīnau i ka mea kākau o OS, ʻo Ken Thompson, e ʻae i ka ʻikepili i kākau ʻia i kahi kaʻina e hele ʻaʻole wale i ka hāmeʻa, akā e hoʻopuka pū i kahi kaʻina hana ʻē aʻe. Ua hoʻoholo ʻo Ken e hiki. Eia nō naʻe, ma ke ʻano he minimalist, makemake ʻo ia i kēlā me kēia hana ʻōnaehana e hana i kahi kuleana koʻikoʻi. ʻO ke kākau pololei ʻana ma waena o nā kaʻina hana he pono nui ma mua o ke kākau ʻana i kahi faila waena? ʻO ia wale nō kaʻu i hana ai i kahi manaʻo kikoʻī me ka inoa hopu "pipeline" a me ka wehewehe ʻana i ka syntax no ka launa pū ʻana ma waena o nā kaʻina hana i ʻōlelo hope ai ʻo Ken: "E hana wau!"

A hana. I kekahi ahiahi pōʻino, ua hoʻololi ʻo Ken i ka kernel a me ka shell, hoʻoponopono i nā papahana maʻamau e hoʻohālikelike i ke ʻano o kā lākou ʻae ʻana i ke komo ʻana (hiki ke hele mai mai kahi pipeline), a hoʻololi pū i nā inoa faila. I ka lā aʻe, ua hoʻomaka e hoʻohana nui ʻia nā pipeline i nā noi. I ka pau ʻana o ka pule, ua hoʻohana nā mea kākau ʻōlelo iā lākou e hoʻouna i nā palapala mai nā mea hana huaʻōlelo i ka mea paʻi. Ma hope iki, ua hoʻololi ʻo Ken i ka API kumu a me ka syntax no ka hoʻopili ʻana i ka hoʻohana ʻana i nā pipeline me nā hui hoʻomaʻemaʻe, i hoʻohana ʻia mai ia manawa.

ʻO ka mea pōʻino, ua nalowale ke kumu kumu no ka paʻi ʻekolu o Unix kernel. A ʻoiai ua loaʻa iā mākou ke kumu kumu kernel i kākau ʻia ma C paʻi ʻehā, i hoʻokuʻu ʻia ma Nowemapa 1973, akā ua puka mai i kekahi mau mahina ma mua o ka hoʻokuʻu ʻia ʻana a ʻaʻole i loaʻa nā hoʻokō pipeline. He mea hilahila ke nalowale ke kumu kumu no kēia hana Unix kaao, a mau loa paha.

Loaʻa iā mākou nā palapala kikokikona no pipe(2) mai nā hoʻokuʻu ʻelua, no laila hiki iā ʻoe ke hoʻomaka ma ka ʻimi ʻana i ka palapala paʻi ʻekolu (no kekahi mau huaʻōlelo, i kaha ʻia "manual", he string o nā huaʻōlelo ^H, a ukali ʻia e kahi kaha lalo!). ʻO kēia proto-pipe(2) ua kākau ʻia ma ka ʻōlelo hui a hoʻihoʻi i hoʻokahi wale nō faila wehewehe, akā ua hāʻawi mua i ka hana kumu i manaʻo ʻia:

Kāhea pūnaewele paipu hoʻokumu i kahi mīkini hoʻokomo / puka i kapa ʻia he pipeline. Hiki ke hoʻohana ʻia ka mea wehewehe waihona i hoʻihoʻi ʻia no nā hana heluhelu a kākau. Ke kākau ʻia kekahi mea i ka pipeline, a hiki i 504 bytes o ka ʻikepili i hoʻopaʻa ʻia, a laila hoʻokuʻu ʻia ke kaʻina hana kākau. I ka heluhelu ʻana mai ka pipeline, lawe ʻia ka ʻikepili buffered.

I ka makahiki aʻe, ua kākau hou ʻia ka kernel ma C, a paipu(2) ma ka puka eha loaʻa i kona ʻano hou me ka prototype "pipe(fildes)»:

Kāhea pūnaewele paipu hoʻokumu i kahi mīkini hoʻokomo / puka i kapa ʻia he pipeline. Hiki ke hoʻohana ʻia nā mea wehewehe faila i ka heluhelu a kākau ʻana. Ke kākau ʻia kekahi mea i ka pipeline, hoʻohana ʻia ka pahu i hoʻihoʻi ʻia ma r1 (resp. fildes [1]), i hoʻopaʻa ʻia i 4096 bytes o ka ʻikepili, a laila hoʻokuʻu ʻia ke kaʻina hana kākau. I ka heluhelu ʻana mai ka pipeline, ua hoʻihoʻi ka lima i r0 (resp. fildes[0]) e lawe i ka ʻikepili.

Ua manaʻo ʻia i ka manawa e wehewehe ʻia ai kahi pipeline, ʻelua (a ʻoi aku paha) kaʻina hana kamaʻilio (i hana ʻia e nā kelepona ma hope i ke'ō) e hoʻoili i ka ʻikepili mai ka pipeline me ka hoʻohana ʻana i nā kelepona heluhelu и kakau.

Loaʻa i ka pūpū kahi syntax no ka wehewehe ʻana i kahi laina laina o nā kaʻina i hoʻopili ʻia e kahi pipeline.

Kāhea e heluhelu mai kahi paipu ʻole (ʻaʻohe ʻikepili i hoʻopaʻa ʻia) hoʻokahi wale nō hopena (ua pani ʻia nā mea wehewehe faila kākau) e hoʻihoʻi i ka "hopena o ka faila". ʻAʻole mālama ʻia nā kelepona e kākau ma kahi kūlana like.

mua loa mālama ʻia ka hoʻokō pipeline pili i ka paʻi ʻelima o Unix (Iune 1974), akā ua aneane like ia me ka mea i puka mai ma ka hoʻokuʻu aʻe. Ua hoʻohui ʻia nā manaʻo, no laila hiki iā ʻoe ke hoʻokuʻu i ka paʻi ʻelima.

Puka ʻeono o Unix (1975)

E hoʻomaka kākou e heluhelu i ka code source Unix paʻi ʻeono (Mei 1975). Mahalo nui iā Lions ʻoi aku ka maʻalahi o ka loaʻa ʻana ma mua o nā kumu o nā mana mua:

No nā makahiki he nui ka puke Lions ʻo ia wale nō ka palapala ma ka Unix kernel i loaʻa ma waho o Bell Labs. ʻOiai ua ʻae ka laikini paʻi ʻeono i nā kumu e hoʻohana i kāna code kumu, ua kāpae ka laikini paʻi ʻehiku i kēia hiki, no laila ua puʻunaue ʻia ka puke ma ke ʻano o nā kope kope kope ʻole.

I kēia lā hiki iā ʻoe ke kūʻai i kahi paʻi hou o ka puke, ʻo ka uhi e hōʻike ana i nā haumāna ma kahi mīkini kope. A mahalo iā Warren Toomey (nāna i hoʻomaka i ka papahana TUHS) hiki iā ʻoe ke hoʻoiho PDF file me ka code kumu no ka paʻi ʻeono. Makemake wau e hāʻawi iā ʻoe i ka manaʻo o ka nui o ka hoʻoikaika ʻana i ka hana ʻana i ka faila:

ʻOi aku ma mua o 15 mau makahiki i hala, ua paʻi au i kahi kope o ka code kumu i hāʻawi ʻia Lions, no ka mea ʻaʻole wau i makemake i ka maikaʻi o kaʻu kope mai kahi helu ʻike ʻole o nā kope ʻē aʻe. ʻAʻole i loaʻa ʻo TUHS a ʻaʻole hiki iaʻu ke komo i nā kumu kahiko. Akā i ka makahiki 1988, ua loaʻa iaʻu kahi lipine 9-track kahiko i loaʻa kahi waihona mai kahi kamepiula PDP11. He mea paʻakikī ke haʻi inā e hana ana, akā aia kahi lāʻau /usr/src/ i hoʻopaʻa ʻia i ka hapa nui o nā faila me ka makahiki 1979, ʻoiai he mea kahiko. ʻO ia ka hiku o ka paʻi ʻana a i ʻole kāna huaʻōlelo PWB, e like me kaʻu i manaʻoʻiʻo ai.

Lawe au i ka ʻike ma ke ʻano he kumu a hoʻoponopono lima i nā kumu i ka paʻi ʻeono. Ua mau kekahi o nā code, akā pono e hoʻoponopono iki ʻia kekahi, e hoʻololi i ka hōʻailona += hou i ka =+ kahiko. Ua holoi wale ʻia kekahi mau mea, a pono e kākau hou ʻia kekahi, ʻaʻole naʻe i ka nui.

A i kēia lā hiki iā mākou ke heluhelu ma ka pūnaewele ma TUHS ke kumu kumu o ka paʻi ʻeono mai waihona, nona ka lima o Dennis Ritchie.

Ma ke ala, i ka nānā mua ʻana, ʻo ka hiʻohiʻona nui o ka C-code ma mua o ka manawa o Kernighan lāua ʻo Ritchie pōkole. ʻAʻole hiki iaʻu ke hoʻokomo i nā ʻāpana code me ka ʻole o ka hoʻoponopono nui ʻana e kūpono i kahi wahi hōʻike haiki ma kaʻu pūnaewele.

I ka hoʻomaka /usr/sys/ken/pipe.c aia kahi ʻōlelo wehewehe (a ʻae, aia kekahi /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

ʻAʻole i loli ka nui buffer mai ka paʻi ʻehā. Eia naʻe ke ʻike nei mākou, me ka ʻole o nā palapala lehulehu, ua hoʻohana nā pipeline i nā faila i mālama ʻia!

No nā faila LARG, pili lākou hae inode LARG, i hoʻohana ʻia e ka "algorithm addressing nui" e hana nā poloka ʻole e kākoʻo i nā ʻōnaehana faila nui. No ka mea, ʻoi aku ka maikaʻi o ka hoʻohana ʻole ʻana iā Ken, e hauʻoli wau e lawe i kāna ʻōlelo.

Eia ke kelepona ʻōnaehana maoli 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;
}

Hōʻike maopopo ka manaʻo i nā mea e hana nei. Akā ʻaʻole maʻalahi ka hoʻomaopopo ʻana i ke code, ma muli o ke ala "struct mea hoʻohana u»a me na kakau inoa R0 и R1 Ua hala nā ʻāpana kelepona a me nā waiwai hoʻihoʻi.

E hoao kakou me ialloc() kau ma ka diski inode, a me ke kokua falloc() - e kau i ʻelua ma ka hoʻomanaʻo faila. Inā holo maikaʻi nā mea a pau, e hoʻonoho mākou i nā hae e ʻike i kēia mau faila ma ke ʻano he ʻelua mau kihi o ka pipeline, kuhikuhi iā lākou i ka inode hoʻokahi (nona ka helu kuhikuhi e hoʻonohonoho ʻia i 2), a e kaha i ka inode i hoʻololi ʻia a hoʻohana ʻia. E hoʻolohe i nā noi i iput() i nā ala hewa e hōʻemi i ka helu kuhikuhi ma ka inode hou.

pipe() pono ma R0 и R1 e hoʻihoʻi i nā helu wehewehe waihona no ka heluhelu a me ke kākau ʻana. falloc() hoʻihoʻi i kahi kuhikuhi i ka hoʻolālā faila, akā "hoʻi" ma o u.u_ar0[R0] a me kahi faila wehewehe. ʻO ia hoʻi, mālama ke code i loko r waihona wehewehe no ka heluhelu ʻana a hāʻawi i kahi wehewehe faila no ke kākau pololei ʻana mai u.u_ar0[R0] mahope o ka lua o ke kahea ana falloc().

Ho'āka FPIPE, ka mea a mākou i hoʻonohonoho ai i ka hana ʻana i ka pipeline, kaohi i ka ʻano o ka hana rdwr() i ka sys2.cke kāhea ʻana i nā hana maʻamau 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);
    }
        /* … */
}

A laila ka hana readp() в pipe.c heluhelu 'ikepili mai ka paipu. Akā ʻoi aku ka maikaʻi o ka ʻimi ʻana i ka hoʻokō e hoʻomaka ana writep(). Eia hou, ua lilo ke code i mea paʻakikī ma muli o nā kuʻina o ka hoʻopaʻapaʻa ʻana, akā hiki ke waiho ʻia kekahi mau kikoʻī.

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

Makemake mākou e kākau i nā bytes i ka hoʻokomo pipeline u.u_count. Pono mua mākou e laka i ka inode (e nānā i lalo plock/prele).

A laila, nānā mākou i ka helu kuhikuhi inode. I ka wā e wehe ʻia nā ʻaoʻao ʻelua o ka pipeline, pono e like ka counter me 2. Paʻa mākou i hoʻokahi loulou (mai rp->f_inode), no laila inā ʻoi aku ka liʻiliʻi o ka counter ma mua o 2, ʻo ia ke ʻano o ke kaʻina heluhelu ua pani ʻia kona hopena o ka pipeline. I nā huaʻōlelo ʻē aʻe, ke hoʻāʻo nei mākou e kākau i kahi pipeline i pani ʻia, a he hewa kēia. Kakahi helu kuhi hewa EPIPE a me ka hoailona SIGPIPE ua ʻike ʻia ma ka paʻi ʻeono o Unix.

Akā inā hāmama ka conveyor, piha paha. I kēia hihia, hoʻokuʻu mākou i ka laka a hele i ka hiamoe me ka manaʻolana e heluhelu ʻia kahi kaʻina hana hou mai ka pipeline a hoʻokuʻu i kahi ākea i loko. Ma hope o ke ala ʻana, hoʻi mākou i ka hoʻomaka, kau hou i ka laka a hoʻomaka i kahi pōʻai hoʻopaʻa leo hou.

Inā lawa ka hakahaka o ka pipeline, a laila kākau mākou i ka ʻikepili iā ia me ka hoʻohana ʻana kākaui()... Parameter i_size1 ma ka inode (inā nele ka pipeline hiki ke like me 0) hōʻike i ka hopena o ka ʻikepili i loaʻa iā ia. Inā lawa ka leo hoʻopaʻa, hiki iā mākou ke hoʻopiha i ka pipeline mai i_size1 i luna PIPESIZ. A laila hoʻokuʻu mākou i ka laka a ho'āʻo e ala i kekahi kaʻina hana e kali nei e heluhelu mai ka pipeline. Hoʻi mākou i ka hoʻomaka e ʻike inā hiki iā mākou ke kākau i nā bytes e like me kā mākou makemake. Inā hāʻule, a laila hoʻomaka mākou i kahi pōʻai hoʻopaʻa leo hou.

ʻO ka mea maʻamau ka palena i_mode hoʻohana ʻia ka inode e mālama i nā ʻae r, w и x. Akā i ka hihia o nā pipeline, hōʻailona mākou e kali ana kekahi kaʻina hana no kahi kākau a heluhelu paha me ka hoʻohana ʻana i nā bits IREAD и IWRITE pakahi. Hoʻonohonoho ka hana i ka hae a me nā kelepona sleep(), a ua manaʻo ʻia e hana ʻia kekahi hana ʻē aʻe i ka wā e hiki mai ana wakeup().

Hiki ke kilokilo maoli i loko sleep() и wakeup(). Hoʻokō ʻia lākou ma slp.c, ke kumu o ka mea kaulana "ʻAʻole i manaʻo ʻia ʻoe e hoʻomaopopo i kēia" ʻōlelo. ʻO ka mea pōmaikaʻi, ʻaʻole pono mākou e hoʻomaopopo i ke code, e nānā wale i kekahi mau ʻōlelo:

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

ʻO ke kaʻina hana sleep() no kekahi alahele, hiki ke hoala ia mai e kekahi kaʻina hana, e kumu wakeup() no ke ala like. writep() и readp() hoʻonohonoho i kā lākou mau hana ma o ia mau kelepona paʻa. e hoʻomaopopo i kēlā pipe.c hāʻawi mua i nā manawa a pau PPIPE ke kaheaia sleep(), pela iho la sleep() hiki ke hookiia e ka hoailona.

I kēia manawa ua loaʻa iā mākou nā mea āpau e hoʻomaopopo i ka hana 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);
}

Hiki iā ʻoe ke maʻalahi ka heluhelu ʻana i kēia hana mai lalo a luna. Hoʻohana mau ʻia ka lālā "heluhelu a hoʻihoʻi" inā loaʻa kekahi ʻikepili i ka pipeline. I kēia hihia, hoʻohana mākou heluhelu () heluhelu mākou e like me ka nui o ka ʻikepili e hoʻomaka ana mai ka mea i kēia manawa f_offset heluhelu, a laila hoʻololi i ka waiwai o ka offset pili.

Ma nā heluhelu aʻe, e nele ka pipeline inā ua hiki i ka offset heluhelu i_size1 ma ka inode. Hoʻihoʻi mākou i ke kūlana i ka 0 a hoʻāʻo e ala i kahi kaʻina hana e makemake e kākau i ka pipeline. Ua ʻike mākou i ka piha ʻana o ka conveyor, writep() e hiamoe ana ma ip+1. A i kēia manawa ua nele ka pipeline, hiki iā mākou ke hoʻāla iā ia e hoʻomau i kāna pōʻai kākau.

Inā ʻaʻohe āu mea e heluhelu ai, a laila readp() hiki ke kau i ka hae IREAD a hiamoe ma ip+2. ʻIke mākou i ka mea e hoʻāla iā ia writep(), ke kākau ʻo ia i kekahi mau ʻikepili i ka pipeline.

Manaʻo ma heluhelu() a kākaui() e kōkua iā ʻoe e hoʻomaopopo ma mua o ka hele ʻana i nā ʻāpana ma o "u"Hiki iā mākou ke mālama iā lākou e like me nā hana I/O maʻamau e lawe i kahi faila, kahi kūlana, kahi pale i ka hoʻomanaʻo, a helu i ka helu o nā bytes e heluhelu a kākau paha.

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

No ka "conservative" blocking, a laila readp() и writep() e ālai i ka inode a hoʻopau i kā lākou hana a loaʻa paha kahi hopena (ʻo ia hoʻi, kāhea wakeup). plock() и prele() hana maʻalahi: me ka hoʻohana ʻana i nā kelepona ʻokoʻa sleep и wakeup e ʻae iā mākou e ala i kekahi kaʻina hana e pono ai ka laka a mākou i hoʻokuʻu ai:

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

I ka wā mua ʻaʻole hiki iaʻu ke hoʻomaopopo i ke kumu readp() ʻaʻole kumu prele(ip) mamua o ke kahea ana wakeup(ip+1). ʻO ka mea mua writep() kumu i loko o kona pōʻaiapuni, kēia plock(ip), ka mea e alakai i ka deadlock ina readp() ʻaʻole i wehe i kaʻu poloka i kēia manawa, no laila pono e hana pololei ke code. Inā ʻoe e nānā wakeup(), a laila e maopopo ai he mākaʻikaʻi wale nō ia i ke kaʻina hana hiamoe i mākaukau e hoʻokō, no laila i ka wā e hiki mai ana. sched() hoʻolana maoli. No laila readp() mau kumu wakeup(), wehe i ka laka, hoonoho IREAD a kelepona sleep(ip+2)- kēia mau mea ma mua writep() hoʻomaka hou i ka pōʻaiapuni.

Hoʻopau kēia i ka wehewehe ʻana o nā conveyors i ka paʻi ʻeono. Code maʻalahi, hopena lōʻihi.

Helu ʻehiku o Unix (Ianuali 1979) he hoʻokuʻu nui hou (ʻehā makahiki ma hope) i hoʻolauna i nā noi hou a me nā hiʻohiʻona kernel. Ua hoʻololi nui ʻia hoʻi e pili ana i ka hoʻohana ʻana i ke ʻano hoʻoheheʻe ʻana, nā uniona a me nā kuhikuhi kikoʻī i nā hale. Eia naʻe code lawe lawe ʻaʻole i loli. Hiki iā mākou ke hoʻokuʻu i kēia paʻi.

Xv6, he kernel like me Unix maʻalahi

No ka hana ʻana i ka kernel Xv6 i hoʻoikaika ʻia e ka paʻi ʻeono o Unix, akā ua kākau ʻia i ka C hou e holo ma nā kaʻina hana x86. He maʻalahi ka heluhelu a hoʻomaopopo ʻia ke code. Eia kekahi, ʻaʻole like me nā kumu Unix me TUHS, hiki iā ʻoe ke hōʻuluʻulu, hoʻololi, a holo ma kahi mea ʻē aʻe ma kahi PDP 11/70. No laila, hoʻohana nui ʻia kēia kernel i nā kulanui ma ke ʻano he mea hoʻonaʻauao ma nā ʻōnaehana hana. Nā kumu aia ma Github.

Loaʻa i ke code kahi hoʻokō a maopopo a noʻonoʻo paipu.c, kākoʻo ʻia e kahi paʻa i ka hoʻomanaʻo ma kahi o kahi inode ma ka disk. Eia wau e hāʻawi wale i ka wehewehe ʻana o "pipeline structural" a me ka hana 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() hoʻonohonoho i ke kūlana o ke koena o ka hoʻokō, e komo pū ana nā hana piperead(), pipewrite() и pipeclose(). Kāhea ʻōnaehana maoli sys_pipe he wīwī i hoʻokomo ʻia i loko sysfile.c. Manaʻo wau e heluhelu i kāna code holoʻokoʻa. Aia ka paʻakikī ma ke kiʻekiʻe o ke code kumu o ka paʻi ʻeono, akā ʻoi aku ka maʻalahi a ʻoi aku ka leʻaleʻa o ka heluhelu.

Linux 0.01

Hiki ke loaʻa ke code kumu Linux 0.01. He mea aʻoaʻo e aʻo i ka hoʻokō ʻana i nā paipu i kāna fs/pipe.c. Hoʻohana kēia i ka inode e hōʻike i ka pipeline, akā ua kākau ʻia ka pipeline ponoʻī i ka C hou. ʻO kēia ke ʻano o ka hana 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;
}

Me ka nānā ʻole ʻana i ka wehewehe ʻana, hiki iā ʻoe ke noʻonoʻo pehea e hoʻohana ʻia ai ka helu kuhikuhi inode e nānā i ka hopena o kahi hana kākau. SIGPIPE. Ma waho aʻe o ka hana byte-by-byte, maʻalahi kēia hana e hoʻohālikelike me nā manaʻo i hōʻike ʻia ma luna. ʻOiai noʻonoʻo sleep_on/wake_up ʻaʻole ʻano malihini.

Nā kernel Linux hou, FreeBSD, NetBSD, OpenBSD

Holo wikiwiki au i kekahi mau kernel hou. ʻAʻohe o lākou i hoʻokō i ka disk (ʻaʻole kahaha). Loaʻa iā Linux kona hoʻokō ponoʻī. ʻOiai ʻo nā kernels BSD hou ʻekolu i loaʻa nā hoʻokō e pili ana i ke code i kākau ʻia e John Dyson, i nā makahiki he ʻokoʻa loa lākou mai kekahi i kekahi.

E heluhelu fs/pipe.c (ma Linux) a i ʻole sys/kern/sys_pipe.c (ma *BSD), pono ia i ka hoʻolaʻa maoli. ʻO ke code o kēia lā e pili ana i ka hana a me ke kākoʻo no nā hiʻohiʻona e like me vector a me asynchronous I/O. A ʻokoʻa loa nā kikoʻī o ka hoʻokaʻawale hoʻomanaʻo, nā laka a me ka hoʻonohonoho kernel. ʻAʻole kēia ka mea e pono ai nā koleke no kahi papa ʻōnaehana hoʻomaka.

Eia nō naʻe, makemake wau i ka ʻeli ʻana i kekahi mau hiʻohiʻona kahiko (e like me ka hana ʻana SIGPIPE a hoi mai EPIPE i ka wā e kākau ai i kahi paipu paʻa) i kēia mau ʻano ʻokoʻa o kēia manawa. ʻAʻole paha au e ʻike i kahi kamepiula PDP-11 i ke ola maoli, akā nui nā mea e aʻo ai mai nā code i kākau ʻia i nā makahiki ma mua o koʻu hānau ʻana.

He ʻatikala i kākau ʻia e Divi Kapoor ma 2011:Ka Linux Kernel Implementation of Pipes and FIFOs" hāʻawi i kahi ʻike o ka hana ʻana o nā pipelines (mau) ma Linux. A hana hou ma Linux e hōʻike ana i kahi hoʻohālike pipeline o ka launa pū ʻana, nona ka mana ma mua o nā faila manawa; a e hōʻike pū ana i ka lōʻihi o ka loaʻa ʻana o nā pipeline mai ka "loka conservative loa" o ka paʻi ʻeono o Unix kernel.

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka