Ahoana ny fametrahana fantsona ao amin'ny Unix

Ahoana ny fametrahana fantsona ao amin'ny Unix
Ity lahatsoratra ity dia mamaritra ny fampiharana ny fantsona ao amin'ny kernel Unix. Somary diso fanantenana aho fa nisy lahatsoratra vao haingana mitondra ny lohateny hoe "Ahoana no fiasan'ny fantsona ao amin'ny Unix?Β» nipoitra tsy momba ny rafitra anatiny. Nanjary te hahafanta-javatra aho ary nikaroka loharano tranainy mba hahitana ny valiny.

Inona no resahina?

Pipelines dia "angamba ny famoronana manan-danja indrindra ao amin'ny Unix" - endri-javatra mamaritra ny filozofia fototry ny Unix amin'ny fametrahana programa kely, sy ny teny filamatra mahazatra:

$ echo hello | wc -c
6

Io fampiasa io dia miankina amin'ny antson'ny rafitra nomen'ny kernel pipe, izay voalaza ao amin'ny pejin'ny antontan-taratasy fantsona (7) ΠΈ fantsona (2):

Ny fantsona dia manome fantsona tokana ho an'ny fifandraisana eo amin'ny dingana. Ny fantsona dia manana fidirana (manoratana farany) ary mivoaka (vakiana farany). Ny angona voasoratra amin'ny fidirana amin'ny fantsona dia azo vakiana amin'ny famoahana.

Ny fantsona dia noforonina amin'ny fiantsoana pipe(2), izay mamerina mpamaritra rakitra roa: ny iray dia manondro ny fampidirana ny fantsona, ny faharoa amin'ny famoahana.

Ny vokatra trace avy amin'ny baiko etsy ambony dia mampiseho ny famoronana fantsona sy ny fikorianan'ny angona avy amin'ny dingana iray mankany amin'ny iray hafa:

$ 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

Miantso ny fizotry ny ray aman-dreny pipe()mba hahazoana famariparitana rakitra mifatotra. Ny fizotry ny ankizy iray dia manoratra amin'ny mpamoritra iray ary ny dingana iray hafa mamaky angona mitovy amin'ny mpamoritra iray hafa. Ny akorandriaka "manova anarana" famaritana 2 sy 3 miaraka amin'ny dup4 hifanaraka amin'ny stdin sy stdout.

Raha tsy misy pipelines, ny akorandriaka dia tsy maintsy manoratra ny vokatra avy amin'ny dingana iray mankany amin'ny rakitra iray ary mitondra izany mankany amin'ny dingana hafa mba hamakiana ny angona avy amin'ny rakitra. Vokatr'izany dia handany loharano bebe kokoa sy habaka kapila izahay. Na izany aza, ny fantsona dia tsara kokoa noho ny fisorohana ny rakitra vonjimaika:

Raha misy dingana manandrana mamaky amin'ny fantsona tsy misy na inona na inona, dia read(2) hosakanana mandra-pivoaka ny angona. Raha misy dingana manandrana manoratra amin'ny fantsona feno, dia write(2) dia hosakanana mandra-pamakiana ny angona ampy avy amin'ny fantsona hamitana ny fanoratana.

Tahaka ny fepetra takian'ny POSIX, fananana manan-danja ity: manoratra amin'ny fantsona hatramin'ny PIPE_BUF bytes (farafaharatsiny 512) dia tsy maintsy atomika mba hahafahan'ireo dingana mifandray amin'ny alΓ lan'ny fantsona amin'ny fomba tsy ahafahan'ny rakitra mahazatra (izay tsy manome antoka toy izany).

Miaraka amin'ny rakitra mahazatra, ny dingana iray dia afaka manoratra ny vokatra rehetra ao aminy ary mampita izany amin'ny dingana hafa. Na ny dingana dia afaka miasa amin'ny fomba mitovy mafy, mampiasa mekanika famantarana ivelany (toy ny semaphore) hifampilazana momba ny fahavitan'ny fanoratana na famakiana. Manavotra antsika amin'izany fahasahiranana rehetra izany ny mpitatitra.

Inona no tadiavintsika?

Hazavaiko amin'ny rantsantanako mba hahamora kokoa ny sary an-tsainao ny fomba fiasan'ny conveyor. Mila mametraka buffer sy fanjakana sasany ao anaty fitadidiana ianao. Mila fiasa ianao hanampiana sy hanesorana ny angona amin'ny buffer. Mila fitaovana sasany ianao hiantso ireo asa mandritra ny famakiana sy fanoratana amin'ny mpamoritra rakitra. Ary ilaina ny hidin-trano mba hampiharana ny fihetsika manokana voalaza etsy ambony.

Vonona izahay hanadihady ny kaody loharanon'ny kernel eo ambanin'ny jiro mamirapiratra mba hanamafisana na hanaporofoana ny modely ara-tsainay. Fa miomana mandrakariva amin'ny tsy ampoizina.

Aiza no tadiavintsika?

Tsy fantatro hoe aiza no misy ny dika mitovy amin'ilay boky malaza.Boky lionaΒ« miaraka amin'ny kaody loharano Unix 6, fa misaotra an'i Ny Unix Heritage Society azo karohina amin'ny aterineto kaody loharano na dia dikan-teny tranainy kokoa amin'ny Unix aza.

Toy ny mitsidika tranombakoka ny mandehandeha amin'ny arsiva TUHS. Afaka mijery ny tantarantsika isika ary manaja ny ezaka an-taonany hamerenana tsikelikely ireo fitaovana rehetra ireo avy amin'ny kasety sy ny printy taloha. Ary fantatro tsara ireo sombiny mbola tsy hita.

Rehefa afa-po ny fahalianantsika momba ny tantaran'ny fantsona taloha, dia afaka mijery ireo cores maoderina isika ho fampitahana.

Raha eny, pipe dia ny laharana antso an-tariby 42 eo amin'ny latabatra sysent[]. Kisendrasendra?

Kernel Unix nentim-paharazana (1970–1974)

Tsy nahita soritra aho pipe(2) na in PDP-7 Unix (Janoary 1970), na in Unix andiany voalohany (Novambra 1971), na amin'ny kaody loharano tsy feno fanontana faharoa (Jona 1972).

Manambara izany ny TUHS Unix andiany fahatelo (Febroary 1973) no dikan-teny voalohany misy fantsona:

Ny andiany fahatelo amin'ny Unix dia ny dikan-teny farany misy kernel voasoratra amin'ny assembler, fa koa ny dikan-teny voalohany misy pipelines. Nandritra ny taona 1973, nisy ny asa hanatsarana ny andiany fahatelo, naverina nosoratana tamin'ny C ny kernel, ka teraka ny andiany fahefatra amin'ny Unix.

Ny mpamaky iray dia nahita scan ny antontan-taratasy iray izay nanoloran'i Doug McIlroy ny hevitra hoe "fampifandraisana fandaharana toy ny hose zaridaina."

Ahoana ny fametrahana fantsona ao amin'ny Unix
Ao amin'ny bokin'i Brian KernighanUnix: Tantara sy Memoir”, ny tantaran'ny fisehoan'ny conveyors koa dia manonona ity antontan-taratasy ity: "... nihantona teo amin'ny rindrina tao amin'ny biraoko tao amin'ny Bell Labs nandritra ny 30 taona izy io." Eto resadresaka nifanaovana tamin'i McIlroyary tantara iray hafa avy amin'ny Ny asan'i McIlroy, nosoratana tamin'ny 2014:

Rehefa niseho ny Unix, ny fitiavako ny coroutine dia nahatonga ahy hanontany ny mpanoratra OS, Ken Thompson, mba hamela ny angon-drakitra voasoratra amin'ny dingana sasany handeha tsy amin'ny fitaovana ihany, fa koa amin'ny fivoahana mankany amin'ny dingana hafa. Nanapa-kevitra i Ken fa azo atao izany. Na izany aza, amin'ny maha minimalist azy, tiany hanana anjara toerana lehibe ny endri-javatra rehetra. Tena tombony lehibe tokoa ve ny fanoratana mivantana eo anelanelan'ny dingana raha oharina amin'ny fanoratana amin'ny rakitra mpanelanelana? Ary rehefa nanao tolo-kevitra manokana miaraka amin'ny anarana mahasarika "pipeline" sy ny famaritana ny syntax ny fifaneraserana amin'ny dingana aho, dia nihiaka ihany i Ken tamin'ny farany: "Izaho no hanao izany!".

Ary nanao. Indray takariva nahatsiravina, nanova ny kernel sy ny akorany i Ken, nanamboatra programa manara-penitra maromaro mba hanara-penitra ny fomba fanekeny ny fidirana (izay mety ho avy amin'ny fantsona), ary nanova ny anaran-drakitra. Ny ampitson'iny, dia tena be mpampiasa amin'ny fampiharana ny pipelines. Tamin'ny faran'ny herinandro dia nampiasa azy ireo ny sekretera mba handefasana antontan-taratasy avy amin'ny mpanodina teny mankany amin'ny mpanonta. Somary taty aoriana, nosoloin'i Ken ny API sy syntax tany am-boalohany amin'ny famenoana ny fampiasana fantsona miaraka amin'ny fivoriambe madio kokoa izay nampiasaina hatramin'izay.

Indrisy anefa fa very ny code source ho an'ny kernel Unix andiany fahatelo. Ary na dia manana ny code source kernel voasoratra ao amin'ny C andiany fahefatra, izay navoaka tamin'ny Novambra 1973, saingy nivoaka volana vitsivitsy talohan'ny famoahana ofisialy ary tsy misy ny fampiharana ny fantsona. Mampalahelo fa very ny kaody loharanon'ity endri-javatra Unix malaza ity, mety ho mandrakizay.

Manana lahatsoratra momba ny antontan-taratasy izahay pipe(2) avy amin'ny famoahana roa, mba hahafahanao manomboka amin'ny fikarohana ny antontan-taratasy andiany fahatelo (ho an'ny teny sasany, nasiana tsipiho "an-tanana", tady ^H ara-bakiteny arahin'ny tsipiho!). Ity proto-pipe(2) dia voasoratra ao amin'ny assembler ary tsy mamerina afa-tsy iray ny famaritana ny rakitra, fa efa manome ny asa fototra andrasana:

System antso sodina mamorona mekanika I/O antsoina hoe pipeline. Ny mpamaritra rakitra naverina dia azo ampiasaina amin'ny asa famakiana sy fanoratana. Rehefa misy zavatra voasoratra ao amin'ny fantsona, dia mitahiry angon-drakitra hatramin'ny 504 bytes izany, ary avy eo dia miato ny fizotran'ny fanoratana. Rehefa mamaky avy amin'ny fantsona dia alaina ny angon-drakitra buffered.

Tamin'ny taona nanaraka, ny kernel dia naverina nosoratana tamin'ny C, ary fantsona (2) andiany fahefatra nahazo ny endriny maoderina miaraka amin'ny prototype "pipe(fildes)"

System antso sodina mamorona mekanika I/O antsoina hoe pipeline. Ireo mpamoritra rakitra naverina dia azo ampiasaina amin'ny asa famakiana sy fanoratana. Rehefa misy zavatra voasoratra ao amin'ny pipeline, dia ampiasaina ny descriptor miverina amin'ny r1 (resp. fildes [1]), voatahiry hatramin'ny 4096 bytes ny angona, ary avy eo dia miato ny fizotran'ny fanoratana. Rehefa mamaky avy amin'ny fantsona dia miverina amin'ny r0 (resp. fildes[0]) ny descriptor maka ny angona.

Heverina fa rehefa voafaritra ny fantsona iray, dia misy dingana roa (na mihoatra) mifandray (natao tamin'ny fiantsoana manaraka. sotro rovitra) dia handefa angona avy amin'ny fantsona mampiasa antso vakio ny ΠΈ manoratra.

Ny akorandriaka dia manana syntax hamaritana ny fizotry ny dingana mifandray amin'ny alalan'ny fantsona.

Antso hamaky avy amin'ny fantsona tsy misy na inona na inona (tsy misy angon-drakitra voatahiry) izay manana fiafarana tokana (mihidy avokoa ny famaritana rakitra rehetra) dia mamerina ny "faran'ny rakitra". Ny fanoratana antso amin'ny toe-javatra mitovy amin'izany dia tsy raharahaina.

voalohany fampiharana fantsona voatahiry mihatra amin'ny andiany fahadimy amin'ny Unix (Jona 1974), nefa saika mitovy amin’ilay niseho tamin’ny famoahana manaraka. Fanehoan-kevitra ihany no nampiana, ka azo tsidihana ny andiany fahadimy.

Unix Sixth Edition (1975)

Manomboka mamaky ny kaody loharano Unix andiany fahenina (Mey 1975). Misaotra indrindra Lions mora kokoa ny mahita azy noho ny loharanon'ny dikan-teny teo aloha:

Nandritra ny taona maro ny boky Lions no hany antontan-taratasy momba ny kernel Unix hita ivelan'ny Bell Labs. Na dia namela ny mpampianatra hampiasa ny kaody loharanony aza ny fahazoan-dΓ lana fanontana fahenina, ny fahazoan-dΓ lana fanontana fahafito dia tsy nampiditra izany fahafahana izany, ka nozaraina tamin'ny kopia tsy ara-dalΓ na ilay boky.

Androany dia afaka mividy dika mitovy amin'ny boky ianao, izay mampiseho ireo mpianatra ao amin'ny copier ny fonony. Ary misaotra an'i Warren Toomey (izay nanomboka ny tetikasa TUHS), azonao atao ny misintona Loharano PDF andiany fahaenina. Te-hanome anao hevitra aho hoe ohatrinona ny ezaka natao tamin'ny famoronana ilay rakitra:

Maherin'ny 15 taona lasa izay, nitendry dika mitovy amin'ny kaody loharano nomena aho Lionssatria tsy tiako ny kalitaon'ny dikako avy amin'ny isa tsy fantatra hafa. Tsy mbola nisy ny TUHS, ary tsy nahazo ny loharano taloha aho. Saingy tamin'ny 1988 dia nahita horonam-peo tranainy misy lΓ lam-pandehanana 9 aho izay nanana backup avy amin'ny solosaina PDP11. Sarotra ny nahafantatra raha niasa izy io, saingy nisy hazo / usr / src / tsy misy dikany izay nanamarika ny ankamaroan'ny rakitra tamin'ny 1979, izay toa tranainy aza. Fanontana fahafito io, na derivative PWB, hoy aho.

Noraisiko ho fototry ny fikarohana ary nanova ny loharano ho amin'ny toetry ny andiany fahenina aho. Ny ampahany amin'ny kaody dia tsy miova, ny ampahany dia tsy maintsy ovaina kely, nanova ny marika maoderina += ho amin'ny =+ efa lany andro. Nisy nofafana tsotra izao, ary nisy zavatra tsy maintsy naverina nosoratana tanteraka, fa tsy be loatra.

Ary ankehitriny dia afaka mamaky an-tserasera ao amin'ny TUHS ny kaody loharanon'ny andiany fahenina amin'ny arsiva, izay nananan'i Dennis Ritchie tanana.

Raha ny marina, raha vao jerena, ny tena mampiavaka ny C-code talohan'ny vanim-potoanan'i Kernighan sy Ritchie dia ny azy. fohy. Matetika aho no afaka mampiditra sombin-kaody tsy misy fanitsiana be dia be mba hifanaraka amin'ny faritra fampisehoana somary tery amin'ny tranokalako.

Tany am-piandohana /usr/sys/ken/pipe.c misy fanehoan-kevitra manazava (ary eny, misy bebe kokoa /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

Tsy niova ny haben'ny buffer hatramin'ny andiany fahefatra. Saingy eto isika dia mahita, tsy misy antontan-taratasy ho an'ny daholobe, fa ny pipelines indray mandeha dia nampiasa rakitra ho fitahirizana miverina!

Raha ny rakitra LARG dia mifanaraka amin'ny inode-flag LARG, izay ampiasain'ny "algorithm adiresy lehibe" handaminana sakana ankolaka hanohanana rafitra fichier lehibe kokoa. Satria nilaza i Ken fa tsara kokoa ny tsy mampiasa azy ireo, dia faly aho mandray ny teniny.

Ity ny tena antson'ny rafitra 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;
}

Ny fanehoan-kevitra dia mamaritra mazava tsara ny zava-mitranga eto. Saingy tsy mora ny mahatakatra ny kaody, amin'ny ampahany noho ny fomba "mpampiasa struct u»ary rejisitra R0 и R1 ny paramètre antso an-tariby sy ny sanda miverina dia mandalo.

Andeha isika hanandrana ialloc() toerana eo amin'ny kapila inode (inode), ary miaraka amin'ny fanampiana falloc() - fivarotana roa rakitra. Raha mandeha tsara ny zava-drehetra, dia hametraka saina isika mba hamantarana ireo rakitra ireo ho toy ny tendrony roa amin'ny fantsona, hanondro azy ireo amin'ny inode iray ihany (izay isa reference dia lasa 2), ary mariho ny inode ho novaina sy ampiasaina. Tandremo ny fangatahana amin'ny iput() amin'ny lalana diso mba hampihenana ny isan'ny reference ao amin'ny inode vaovao.

pipe() amin'ny alalan'ny R0 ΠΈ R1 avereno ny laharan'ny famaritana rakitra ho an'ny famakiana sy fanoratana. falloc() mamerina tondro mankany amin'ny firafitry ny rakitra, fa koa "miverina" amin'ny alΓ lan'ny u.u_ar0[R0] ary mpamoritra rakitra. Izany hoe, voatahiry ao ny kaody r mpamoritra rakitra ho an'ny famakiana ary manendry mpamoritra ho an'ny fanoratana mivantana avy u.u_ar0[R0] aorian'ny fiantsoana faharoa falloc().

sainam-pirenena FPIPE, izay apetrakay rehefa mamorona ny fantsona, dia mifehy ny fihetsiky ny asa rdwr() amin'ny sys2.c, izay miantso ny mahazatra I/O manokana:

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

Avy eo ny asa readp() Π² pipe.c mamaky angona avy amin'ny fantsona. Saingy tsara kokoa ny manara-maso ny fampiharana manomboka amin'ny writep(). Indray mandeha, nanjary sarotra kokoa ny fehezan-dalΓ na noho ny toetry ny fifanolanana mandalo, saingy azo esorina ny antsipiriany sasany.

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

Te-hanoratra bytes amin'ny fampidirana pipeline izahay u.u_count. Voalohany dia mila manidy ny inode isika (jereo eto ambany plock/prele).

Avy eo dia manamarina ny isan'ny reference inode isika. Raha mbola misokatra ny tendrony roa amin'ny fantsona dia tokony ho 2 ny kaontera. Mifikitra amin'ny rohy iray isika (avy amin'ny rp->f_inode), koa raha latsaky ny 2 ny kaontera, dia tokony hidika izany fa nanakatona ny faran'ny fantsona ny fizotran'ny famakiana. Amin'ny teny hafa, miezaka manoratra amin'ny fantsona mihidy izahay, izay fahadisoana. Kaody fahadisoana voalohany EPIPE ary signal SIGPIPE niseho tamin'ny andiany fahenina amin'ny Unix.

Fa na dia misokatra aza ny conveyor dia mety ho feno. Amin'ity tranga ity, dia mamoaka ny hidin-trano izahay ary matory amin'ny fanantenana fa hisy dingana hafa hamaky ny fantsona ary hanafaka toerana ampy ao anatiny. Rehefa mifoha isika dia miverina amin'ny voalohany, ahantona indray ny hidin-trano ary manomboka tsingerina fanoratana vaovao.

Raha toa ka ampy ny toerana malalaka ao amin'ny fantsona, dia manoratra angon-drakitra amin'izany izahay writei (). fikirana i_size1 ny inode'a (miaraka amin'ny fantsona tsy misy na inona na inona dia mety mitovy amin'ny 0) manondro ny faran'ny angona efa misy azy. Raha ampy ny toerana hanoratana dia afaka mameno ny fantsona isika i_size1 Π΄ΠΎ PIPESIZ. Avy eo dia mamoaka ny hidin-trano izahay ary manandrana mamoha ny dingana rehetra miandry ny famakiana avy amin'ny fantsona. Miverina any amin'ny voalohany isika mba hijery raha nahavita nanoratra bytes betsaka araka izay ilainay. Raha tsy izany dia manomboka tsingerina fandraisam-peo vaovao isika.

Matetika parameter i_mode inode dia ampiasaina hitahiry fahazoan-dΓ lana r, w ΠΈ x. Fa amin'ny resaka pipelines, dia manambara izahay fa misy dingana miandry ny fanoratana na famakiana mampiasa bits IREAD ΠΈ IWRITE tsirairay avy. Ny dingana dia mametraka ny saina sy miantso sleep(), ary antenaina fa amin'ny ho avy dia hisy dingana hafa hiantso wakeup().

Ny tena majika dia mitranga ao sleep() ΠΈ wakeup(). Izy ireo dia ampiharina amin'ny slp.c, loharanon'ilay fanehoan-kevitra malaza hoe "Tsy andrasana ho azonao izany". Soa ihany fa tsy mila mahazo ny kaody isika, jereo fotsiny ny fanehoan-kevitra sasany:

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

Ny dingana izay miantso sleep() ho an'ny fantsona manokana, dia mety ho fohazina amin'ny dingana iray hafa, izay hiantso wakeup() ho an'ny fantsona iray ihany. writep() ΠΈ readp() mandrindra ny hetsika ataon'izy ireo amin'ny alalan'ny antso mitambatra toy izany. Mariho fa pipe.c atao laharam-pahamehana foana PPIPE rehefa antsoina sleep(), ka ny rehetra sleep() azo tapahina amin'ny alalan'ny famantarana.

Ankehitriny isika dia manana ny zava-drehetra mba hahatakatra ny asa 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);
}

Mety ho mora kokoa aminao ny mamaky ity asa ity manomboka any ambany ka hatrany ambony. Ny sampana "mamaky sy miverina" dia matetika ampiasaina rehefa misy angon-drakitra ao anaty fantsona. Amin'ity tranga ity, mampiasa izahay mamaky () vakio araka izay azo atao manomboka amin'ny ankehitriny f_offset vakio, ary havaozy avy eo ny sandan'ny offset mifanaraka amin'izany.

Amin'ny famakiana manaraka dia ho foana ny fantsona raha toa ka tonga ny offset vakina i_size1 amin'ny inode. Averinay amin'ny 0 ny toerana ary manandrana mamoha ny dingana rehetra te hanoratra amin'ny fantsona. Fantatsika fa rehefa feno ny conveyor, writep() matory amin'ny ip+1. Ary satria foana ny fantsona, dia afaka mamoha azy isika hanohy ny tsingerina fanoratana.

Raha tsy misy zavatra hovakiana dia readp() afaka mametraka saina IREAD ary renoky ny torimaso ip+2. Fantatsika izay hanaitra azy writep()rehefa manoratra angona sasany amin'ny fantsona.

Hevitra momba ny mamaky () ary manoratrai () hanampy anao hahatakatra fa tsy mandalo masontsivana amin'ny "uΒ» Azontsika atao toy ny fiasa I/O mahazatra izy ireo izay maka rakitra, toerana, buffer amin'ny fitadidiana, ary manisa ny isan'ny bytes hovakiana na soratana.

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

Raha ny fanakanana "conservative" indray, dia readp() ΠΈ writep() manidy inodes mandra-pahavitan'izy ireo na mahazo valiny (izany hoe antso wakeup). plock() ΠΈ prele() miasa tsotra: mampiasa andian-antso hafa sleep ΠΈ wakeup avelao izahay hamoha izay dingana mila ny hidin-trano vao navoakanay:

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

Tsy azoko ny antony readp() tsy miteraka prele(ip) alohan'ny fiantsoana wakeup(ip+1). Ny zavatra voalohany writep() miantso ao amin'ny tadivavarana, ity plock(ip), izay miteraka fahatapahana raha readp() mbola tsy nanala ny sakanany, noho izany dia tsy maintsy miasa tsara ny kaody. Raha mijery ianao wakeup(), dia lasa mazava fa manamarika ny dingana fatoriana ho vonona ho amin'ny famonoana, ka amin'ny ho avy sched() tena namoaka azy. Noho izany readp() antony wakeup(), mamoha, mametraka IREAD ary miantso sleep(ip+2)- izany rehetra izany teo aloha writep() mamerina ny tsingerina.

Izany dia mameno ny famaritana ny fantsona amin'ny andiany fahenina. Kaody tsotra, misy fiantraikany lavitra.

Unix Edition fahafito (Janoary 1979) dia famoahana lehibe vaovao (efa-taona taty aoriana) izay nampiditra fampiharana vaovao sy endri-javatra kernel. Izy io koa dia nandalo fiovana lehibe mifandraika amin'ny fampiasana karazana fanariana, sendikΓ  ary tondro fanondro amin'ny rafitra. na izany aza code pipelines saika tsy niova. Afaka mandingana ity andiany ity isika.

Xv6, kernel tsotra mitovy amin'ny Unix

Mba hamorona nucleus Xv6 voataonan'ny Unix andiany fahenina, saingy nosoratana tamin'ny C maoderina mba hihazakazaka amin'ny processeur x86. Mora vakina sy azo takarina ilay kaody. Ary koa, tsy toy ny loharano Unix miaraka amin'ny TUHS, azonao atao ny manangona azy, manova azy ary mampandeha azy amin'ny zavatra hafa ankoatry ny PDP 11/70. Noho izany, io fototra io dia ampiasaina betsaka any amin'ny oniversite ho fitaovana fampianarana amin'ny rafitra miasa. loharanom-baovao dia ao amin'ny Github.

Ny fehezan-dalΓ na dia misy fampiharana mazava sy feno fisainana fantsona.c, tohanan'ny buffer ao anaty fitadidiana fa tsy inode amin'ny kapila. Eto aho dia tsy manome afa-tsy ny famaritana ny "pipeline structural" sy ny fiasa 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() mametraka ny toetry ny sisa rehetra amin'ny fampiharana, izay ahitana ny asa piperead(), pipewrite() ΠΈ pipeclose(). Ny tena antso rafitra sys_pipe dia wrapper ampiharina ao sysfile.c. Manoro hevitra aho hamaky ny kaody rehetra. Ny fahasarotana dia eo amin'ny haavon'ny kaody loharanon'ny fanontana fahenina, saingy mora kokoa sy mahafinaritra kokoa ny mamaky azy.

Linux 0.01

Azonao atao ny mahita ny kaody loharano ho an'ny Linux 0.01. Hanampy ny fianarana ny fampiharana ny fantsona ao aminy fs/pipe.c. Eto, misy inode ampiasaina hanehoana ny fantsona, fa ny fantsona mihitsy dia nosoratana tamin'ny C maoderina. Raha toa ianao ka nijirika ny lalanao tamin'ny alΓ lan'ny kaody andiany fahenina, dia tsy hanana olana ianao eto. Toy izao ny endri-javatra 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;
}

Na dia tsy mijery ny famaritana struct aza dia azonao fantarina ny fomba ampiasana ny fanisan'ny inode hanamarina raha misy asa fanoratana SIGPIPE. Ankoatra ny asa byte-by-byte, ity fiasa ity dia mora ampitahaina amin'ireo hevitra etsy ambony. Na ny lojika aza sleep_on/wake_up toa tsy dia vahiny loatra.

Kernel Linux maoderina, FreeBSD, NetBSD, OpenBSD

Nandeha haingana ireo voany maoderina sasany aho. Tsy misy amin'izy ireo efa manana fampiharana mifototra amin'ny disk (tsy mahagaga). Linux dia manana ny fampiharana azy manokana. Ary na dia misy fampiharana mifototra amin'ny kaody nosoratan'i John Dyson aza ireo kernel BSD maoderina telo, dia nanjary tsy nitovy loatra izy ireo nandritra ny taona maro.

Mamaky fs/pipe.c (amin'ny Linux) na sys/kern/sys_pipe.c (amin'ny *BSD), mila fanoloran-tena marina izany. Zava-dehibe amin'ny kaody ankehitriny ny fampisehoana sy fanohanana ireo endri-javatra toy ny vector sy asynchronous I/O. Ary ny antsipirian'ny fizarana fahatsiarovana, hidin-trano, ary ny fanamafisana kernel dia samy hafa be. Tsy izany no ilain'ny oniversite amin'ny fampianarana fampidirana momba ny rafitra fiasana.

Na izany na tsy izany, nahaliana ahy ny nanangona lamina tranainy vitsivitsy (ohatra, famoronana SIGPIPE ary miverina EPIPE rehefa manoratra amin'ny fantsona mihidy) amin'ireo voany maoderina rehetra ireo, tena samy hafa. Mety tsy hahita solosaina PDP-11 mivantana mihitsy aho, saingy mbola betsaka ny ianarana avy amin'ny fehezan-dalΓ na nosoratana taona vitsivitsy talohan'ny nahaterahako.

Nosoratan'i Divi Kapoor tamin'ny 2011, ilay lahatsoratra "Ny Linux Kernel Fampiharana ny fantsona sy ny FIFOdia topimaso ny fomba fiasan'ny fantsona Linux (hatramin'izao). ny vao haingana commit amin'ny linux mampiseho ny modelin'ny fifandraisana amin'ny fantsona, izay mihoatra noho ny an'ny rakitra vonjimaika ny fahaizany; ary mampiseho ihany koa ny halaviran'ny fantsona avy amin'ny "fanidy tena mpandala ny nentin-drazana" ao amin'ny kernel Unix andiany fahenina.

Source: www.habr.com

Add a comment