Unixలో పైప్‌లైన్‌లు ఎలా అమలు చేయబడతాయి

Unixలో పైప్‌లైన్‌లు ఎలా అమలు చేయబడతాయి
ఈ వ్యాసం Unix కెర్నల్‌లో పైప్‌లైన్‌ల అమలును వివరిస్తుంది. అనే శీర్షికతో ఇటీవలి కథనం రావడంతో నేను కొంత నిరాశకు గురయ్యాను.Unixలో పైప్‌లైన్‌లు ఎలా పని చేస్తాయి?"అని తేలింది కాదు అంతర్గత నిర్మాణం గురించి. నేను ఆసక్తిగా ఉన్నాను మరియు సమాధానాన్ని కనుగొనడానికి పాత మూలాలను తవ్వాను.

మనం దేని గురించి మాట్లాడుతున్నాం?

పైప్‌లైన్‌లు, “బహుశా యునిక్స్‌లో అత్యంత ముఖ్యమైన ఆవిష్కరణ,” చిన్న ప్రోగ్రామ్‌లను ఒకదానితో ఒకటి అనుసంధానించే అంతర్లీన యునిక్స్ తత్వశాస్త్రం యొక్క నిర్వచించే లక్షణం, అలాగే కమాండ్ లైన్‌లో సుపరిచితమైన చిహ్నం:

$ echo hello | wc -c
6

ఈ కార్యాచరణ కెర్నల్ అందించిన సిస్టమ్ కాల్‌పై ఆధారపడి ఉంటుంది pipe, ఇది డాక్యుమెంటేషన్ పేజీలలో వివరించబడింది పైపు (7) и పైపు (2):

ఇంటర్‌ప్రాసెస్ కమ్యూనికేషన్ కోసం పైప్‌లైన్‌లు ఏకదిశాత్మక ఛానెల్‌ని అందిస్తాయి. పైప్‌లైన్‌లో ఇన్‌పుట్ (రైట్ ఎండ్) మరియు అవుట్‌పుట్ (రీడ్ ఎండ్) ఉన్నాయి. పైప్‌లైన్ ఇన్‌పుట్‌కు వ్రాసిన డేటా అవుట్‌పుట్ వద్ద చదవబడుతుంది.

కాల్ ఉపయోగించి పైప్‌లైన్ సృష్టించబడుతుంది pipe(2), ఇది రెండు ఫైల్ డిస్క్రిప్టర్‌లను అందిస్తుంది: ఒకటి పైప్‌లైన్ ఇన్‌పుట్‌ను సూచిస్తుంది, రెండవది అవుట్‌పుట్‌ను సూచిస్తుంది.

పై ఆదేశం నుండి ట్రేస్ అవుట్‌పుట్ పైప్‌లైన్ యొక్క సృష్టిని మరియు దాని ద్వారా ఒక ప్రక్రియ నుండి మరొక ప్రక్రియకు డేటా ప్రవాహాన్ని చూపుతుంది:

$ 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

పేరెంట్ ప్రాసెస్ కాల్స్ pipe()మౌంట్ చేయబడిన ఫైల్ డిస్క్రిప్టర్లను పొందడానికి. ఒక చైల్డ్ ప్రాసెస్ ఒక హ్యాండిల్‌కి వ్రాస్తుంది మరియు మరొక ప్రాసెస్ అదే డేటాను మరొక హ్యాండిల్ నుండి రీడ్ చేస్తుంది. stdin మరియు stdoutని సరిపోల్చడానికి 2 మరియు 3 డిస్క్రిప్టర్‌లను "పేరు మార్చడానికి" షెల్ dup4ని ఉపయోగిస్తుంది.

పైపులు లేకుండా, షెల్ ఒక ప్రక్రియ యొక్క అవుట్‌పుట్‌ను ఫైల్‌కి వ్రాసి, ఫైల్ నుండి డేటాను చదవడానికి మరొక ప్రక్రియకు పంపాలి. ఫలితంగా, మేము మరింత వనరులను మరియు డిస్క్ స్థలాన్ని వృధా చేస్తాము. అయినప్పటికీ, పైప్‌లైన్‌లు మంచివి ఎందుకంటే అవి తాత్కాలిక ఫైల్‌ల వినియోగాన్ని నివారించడానికి మిమ్మల్ని అనుమతిస్తాయి:

ఒక ప్రక్రియ ఖాళీ పైప్‌లైన్ నుండి చదవడానికి ప్రయత్నిస్తుంటే read(2) డేటా అందుబాటులోకి వచ్చే వరకు బ్లాక్ చేస్తుంది. ఒక ప్రక్రియ పూర్తి పైప్‌లైన్‌కి వ్రాయడానికి ప్రయత్నిస్తే, అప్పుడు write(2) రైట్ చేయడానికి పైప్‌లైన్ నుండి తగినంత డేటా చదివే వరకు బ్లాక్ చేస్తుంది.

POSIX అవసరం వలె, ఇది ఒక ముఖ్యమైన ఆస్తి: వరకు పైప్‌లైన్‌కు వ్రాయడం PIPE_BUF బైట్‌లు (కనీసం 512) తప్పనిసరిగా పరమాణువుగా ఉండాలి, తద్వారా సాధారణ ఫైల్‌లు (అటువంటి హామీలను అందించనివి) చేయలేని విధంగా ప్రక్రియలు పైప్‌లైన్ ద్వారా ఒకదానితో ఒకటి సంభాషించగలవు.

సాధారణ ఫైల్‌ను ఉపయోగిస్తున్నప్పుడు, ఒక ప్రక్రియ దాని అవుట్‌పుట్ మొత్తాన్ని దానికి వ్రాసి దానిని మరొక ప్రక్రియకు పంపగలదు. లేదా ప్రక్రియలు అత్యంత సమాంతర మోడ్‌లో పనిచేయగలవు, బాహ్య సిగ్నలింగ్ మెకానిజం (సెమాఫోర్ వంటివి) ఉపయోగించి ఒక వ్రాత లేదా చదవడం పూర్తయినప్పుడు ఒకదానికొకటి తెలియజేయవచ్చు. కన్వేయర్లు ఈ అవాంతరాల నుండి మనలను కాపాడతాయి.

మనం దేని కోసం చూస్తున్నాం?

నేను దానిని సాధారణ పరంగా వివరిస్తాను, తద్వారా కన్వేయర్ ఎలా పని చేస్తుందో మీరు ఊహించడం సులభం. మీరు మెమరీలో బఫర్ మరియు కొంత స్థితిని కేటాయించాలి. బఫర్ నుండి డేటాను జోడించడానికి మరియు తీసివేయడానికి మీకు ఫంక్షన్‌లు అవసరం. ఫైల్ డిస్క్రిప్టర్‌లలో రీడ్ మరియు రైట్ ఆపరేషన్‌ల సమయంలో ఫంక్షన్‌లను కాల్ చేయడానికి మీకు కొన్ని మార్గాలు అవసరం. మరియు పైన వివరించిన ప్రత్యేక ప్రవర్తనను అమలు చేయడానికి మీకు తాళాలు అవసరం.

ఇప్పుడు మేము మా అస్పష్టమైన మానసిక నమూనాను నిర్ధారించడానికి లేదా తిరస్కరించడానికి ప్రకాశవంతమైన ల్యాంప్‌లైట్ కింద కెర్నల్ సోర్స్ కోడ్‌ను ప్రశ్నించడానికి సిద్ధంగా ఉన్నాము. కానీ ఎప్పుడూ ఊహించని వాటికి సిద్ధంగా ఉండండి.

మనం ఎక్కడ చూస్తున్నాం?

ప్రసిద్ధ పుస్తకం యొక్క నా కాపీ ఎక్కడ ఉందో నాకు తెలియదు "లయన్స్ పుస్తకం"Unix 6 సోర్స్ కోడ్‌తో, కానీ ధన్యవాదాలు యునిక్స్ హెరిటేజ్ సొసైటీ మీరు ఆన్‌లైన్‌లో శోధించవచ్చు సోర్స్ కోడ్ Unix యొక్క పాత వెర్షన్లు కూడా.

TUHS ఆర్కైవ్‌ల ద్వారా సంచరించడం మ్యూజియాన్ని సందర్శించడం లాంటిది. మేము మా భాగస్వామ్య చరిత్రను చూడవచ్చు మరియు పాత టేప్‌లు మరియు ప్రింట్‌ల నుండి ఈ మెటీరియల్‌ను బిట్‌బైట్‌గా రికవర్ చేయడానికి చాలా సంవత్సరాల ప్రయత్నానికి నాకు గౌరవం ఉంది. ఇంకా తప్పిపోయిన ఆ శకలాల గురించి నాకు బాగా తెలుసు.

కన్వేయర్‌ల పురాతన చరిత్ర గురించి మన ఉత్సుకతను సంతృప్తిపరిచిన తర్వాత, మేము పోలిక కోసం ఆధునిక కెర్నల్‌లను చూడవచ్చు.

మార్గం ద్వారా, pipe పట్టికలో సిస్టమ్ కాల్ నంబర్ 42 sysent[]. యాదృచ్ఛికమా?

సాంప్రదాయ యునిక్స్ కెర్నలు (1970–1974)

నేను ఎలాంటి జాడలను కనుగొనలేదు pipe(2) ఏదీ లేదు PDP-7 Unix (జనవరి 1970), లేదా ఇన్ Unix మొదటి ఎడిషన్ (నవంబర్ 1971), లేదా అసంపూర్ణ సోర్స్ కోడ్‌లో లేదు రెండవ ఎడిషన్ (జూన్ 1972).

అని TUHS పేర్కొంది Unix యొక్క మూడవ ఎడిషన్ (ఫిబ్రవరి 1973) కన్వేయర్‌లతో మొదటి వెర్షన్‌గా మారింది:

Unix 1973వ ఎడిషన్ అసెంబ్లీ భాషలో వ్రాసిన కెర్నల్‌తో చివరి వెర్షన్, కానీ పైప్‌లైన్‌లతో మొదటి వెర్షన్ కూడా. XNUMXలో, మూడవ ఎడిషన్‌ను మెరుగుపరచడానికి పని జరిగింది, కెర్నల్ Cలో తిరిగి వ్రాయబడింది మరియు యునిక్స్ యొక్క నాల్గవ ఎడిషన్ కనిపించింది.

ఒక పాఠకుడు డాక్యుమెంట్ యొక్క స్కాన్‌ను కనుగొన్నాడు, దీనిలో డగ్ మెక్‌ల్రాయ్ "గార్డెన్ హోస్ వంటి ప్రోగ్రామ్‌లను కనెక్ట్ చేయడం" అనే ఆలోచనను ప్రతిపాదించాడు.

Unixలో పైప్‌లైన్‌లు ఎలా అమలు చేయబడతాయి
బ్రియాన్ కెర్నిఘన్ పుస్తకంలోయునిక్స్: ఎ హిస్టరీ అండ్ ఎ మెమోయిర్", కన్వేయర్ల ఆవిర్భావ చరిత్రలో, ఈ పత్రం కూడా ప్రస్తావించబడింది: "... ఇది 30 సంవత్సరాలుగా బెల్ ల్యాబ్స్‌లోని నా కార్యాలయంలో గోడపై వేలాడదీయబడింది." ఇక్కడ మెక్‌ల్రాయ్‌తో ఇంటర్వ్యూ, మరియు నుండి మరొక కథ 2014లో రాసిన మెక్‌ల్రాయ్ రచన:

Unix బయటకు వచ్చినప్పుడు, కరోటీన్‌లపై నాకున్న ఆకర్షణ, ఒక ప్రక్రియకు వ్రాసిన డేటాను పరికరానికి మాత్రమే కాకుండా, మరొక ప్రక్రియకు అవుట్‌పుట్ చేయడానికి కూడా అనుమతించమని OS యొక్క రచయిత కెన్ థాంప్సన్‌ని అడిగాను. కెన్ అది సాధ్యమేనని నిర్ణయించుకున్నాడు. అయినప్పటికీ, ఒక మినిమలిస్ట్‌గా, ప్రతి సిస్టమ్ ఫంక్షన్ ముఖ్యమైన పాత్రను పోషించాలని అతను కోరుకున్నాడు. ఇంటర్మీడియట్ ఫైల్‌కి వ్రాయడం కంటే ప్రక్రియల మధ్య నేరుగా రాయడం నిజంగా పెద్ద ప్రయోజనమా? నేను "పైప్‌లైన్" అనే ఆకర్షణీయమైన పేరు మరియు ప్రక్రియల మధ్య పరస్పర చర్య కోసం వాక్యనిర్మాణం యొక్క వివరణతో ఒక నిర్దిష్ట ప్రతిపాదన చేసినప్పుడు మాత్రమే కెన్ చివరకు ఇలా అన్నాడు: "నేను దీన్ని చేస్తాను!"

మరియు చేసాడు. ఒక అదృష్ట సాయంత్రం, కెన్ కెర్నల్ మరియు షెల్‌ను మార్చాడు, ఇన్‌పుట్‌ను ఎలా అంగీకరించాడో (ఇది పైప్‌లైన్ నుండి రావచ్చు) ప్రమాణీకరించడానికి అనేక ప్రామాణిక ప్రోగ్రామ్‌లను పరిష్కరించాడు మరియు ఫైల్ పేర్లను కూడా మార్చాడు. మరుసటి రోజు, పైప్లైన్లు అప్లికేషన్లలో చాలా విస్తృతంగా ఉపయోగించడం ప్రారంభించాయి. వారం చివరి నాటికి, కార్యదర్శులు వర్డ్ ప్రాసెసర్‌ల నుండి ప్రింటర్‌కు పత్రాలను పంపడానికి వాటిని ఉపయోగిస్తున్నారు. కొద్దిసేపటి తర్వాత, పైప్‌లైన్‌ల వినియోగాన్ని క్లీనర్ కన్వెన్షన్‌లతో చుట్టడం కోసం కెన్ అసలు API మరియు సింటాక్స్‌ను భర్తీ చేశాడు, అవి అప్పటి నుండి ఉపయోగించబడుతున్నాయి.

దురదృష్టవశాత్తు, మూడవ ఎడిషన్ Unix కెర్నల్ యొక్క సోర్స్ కోడ్ పోయింది. మరియు మన వద్ద కెర్నల్ సోర్స్ కోడ్ C లో వ్రాయబడినప్పటికీ నాల్గవ ఎడిషన్, నవంబర్ 1973లో విడుదలైంది, అయితే ఇది అధికారికంగా విడుదల చేయడానికి చాలా నెలల ముందు వచ్చింది మరియు పైప్‌లైన్ అమలులను కలిగి ఉండదు. ఈ లెజెండరీ Unix ఫంక్షన్‌కి సంబంధించిన సోర్స్ కోడ్ కోల్పోవడం సిగ్గుచేటు, బహుశా ఎప్పటికీ.

మా వద్ద టెక్స్ట్ డాక్యుమెంటేషన్ ఉంది pipe(2) రెండు విడుదలల నుండి, కాబట్టి మీరు డాక్యుమెంటేషన్‌ను శోధించడం ద్వారా ప్రారంభించవచ్చు మూడవ ఎడిషన్ (నిర్దిష్ట పదాల కోసం, "మాన్యువల్‌గా" అండర్‌లైన్ చేయబడింది, లిటరల్స్ ^H స్ట్రింగ్, అండర్ స్కోర్ తర్వాత!). ఈ ప్రోటో-pipe(2) అసెంబ్లీ భాషలో వ్రాయబడింది మరియు ఒక ఫైల్ డిస్క్రిప్టర్‌ను మాత్రమే అందిస్తుంది, కానీ ఇప్పటికే ఆశించిన ప్రాథమిక కార్యాచరణను అందిస్తుంది:

సిస్టమ్ కాల్ పైపు పైప్‌లైన్ అని పిలువబడే ఇన్‌పుట్/అవుట్‌పుట్ మెకానిజంను సృష్టిస్తుంది. తిరిగి వచ్చిన ఫైల్ డిస్క్రిప్టర్ చదవడం మరియు వ్రాయడం కార్యకలాపాల కోసం ఉపయోగించవచ్చు. పైప్‌లైన్‌కు ఏదైనా వ్రాయబడినప్పుడు, 504 బైట్‌ల వరకు డేటా బఫర్ చేయబడుతుంది, ఆ తర్వాత వ్రాత ప్రక్రియ నిలిపివేయబడుతుంది. పైప్‌లైన్ నుండి చదివేటప్పుడు, బఫర్ చేయబడిన డేటా తీసివేయబడుతుంది.

తరువాతి సంవత్సరం నాటికి కెర్నల్ C లో తిరిగి వ్రాయబడింది మరియు పైపు (2) నాల్గవ ఎడిషన్‌లో ప్రోటోటైప్‌తో దాని ఆధునిక రూపాన్ని పొందింది "pipe(fildes)»:

సిస్టమ్ కాల్ పైపు పైప్‌లైన్ అనే ఇన్‌పుట్/అవుట్‌పుట్ మెకానిజంను సృష్టిస్తుంది. తిరిగి వచ్చిన ఫైల్ డిస్క్రిప్టర్‌లను రీడ్ అండ్ రైట్ ఆపరేషన్‌లలో ఉపయోగించవచ్చు. పైప్‌లైన్‌కు ఏదైనా వ్రాయబడినప్పుడు, r1 (resp. fildes[1])లో తిరిగి ఇవ్వబడిన హ్యాండిల్ ఉపయోగించబడుతుంది, 4096 బైట్‌ల డేటాకు బఫర్ చేయబడుతుంది, ఆ తర్వాత వ్రాత ప్రక్రియ నిలిపివేయబడుతుంది. పైప్‌లైన్ నుండి చదివేటప్పుడు, హ్యాండిల్ r0కి తిరిగి వస్తుంది (resp. fildes[0]) డేటాను తీసుకుంటుంది.

పైప్‌లైన్ నిర్వచించబడిన తర్వాత, రెండు (లేదా అంతకంటే ఎక్కువ) కమ్యూనికేట్ చేసే ప్రక్రియలు (తరువాతి కాల్‌ల ద్వారా సృష్టించబడతాయి. ఫోర్క్) కాల్‌లను ఉపయోగించి పైప్‌లైన్ నుండి డేటాను బదిలీ చేస్తుంది చదవండి и వ్రాయడానికి.

పైప్‌లైన్ ద్వారా అనుసంధానించబడిన ప్రక్రియల యొక్క సరళ శ్రేణిని నిర్వచించడానికి షెల్ ఒక వాక్యనిర్మాణాన్ని కలిగి ఉంది.

ఒక చివర మాత్రమే (అన్ని వ్రాసే ఫైల్ డిస్క్రిప్టర్లు మూసివేయబడ్డాయి) ఉన్న ఖాళీ పైప్‌లైన్ (బఫర్డ్ డేటా లేని) నుండి చదవడానికి కాల్‌లు "ఫైల్ ముగింపు"ని అందిస్తాయి. ఇలాంటి పరిస్థితిలో వ్రాయడానికి వచ్చిన కాల్స్ విస్మరించబడతాయి.

ప్రారంభమైనది సంరక్షించబడిన పైప్లైన్ అమలు సంబంధించింది Unix యొక్క ఐదవ ఎడిషన్‌కు (జూన్ 1974), అయితే ఇది తదుపరి విడుదలలో కనిపించిన దానితో దాదాపు సమానంగా ఉంటుంది. వ్యాఖ్యలు ఇప్పుడే జోడించబడ్డాయి, కాబట్టి మీరు ఐదవ ఎడిషన్‌ను దాటవేయవచ్చు.

యునిక్స్ ఆరవ ఎడిషన్ (1975)

Unix సోర్స్ కోడ్ చదవడం ప్రారంభిద్దాం ఆరవ ఎడిషన్ (మే 1975). చాలా ధన్యవాదాలు లయన్స్ మునుపటి సంస్కరణల మూలాల కంటే కనుగొనడం చాలా సులభం:

చాలా సంవత్సరాలు పుస్తకం లయన్స్ Unix కెర్నల్‌లో బెల్ ల్యాబ్స్ వెలుపల అందుబాటులో ఉన్న ఏకైక పత్రం. ఆరవ ఎడిషన్ లైసెన్స్ ఉపాధ్యాయులు దాని సోర్స్ కోడ్‌ని ఉపయోగించడానికి అనుమతించినప్పటికీ, ఏడవ ఎడిషన్ లైసెన్స్ ఈ అవకాశాన్ని మినహాయించింది, కాబట్టి పుస్తకం చట్టవిరుద్ధమైన టైప్‌రైట్ కాపీల రూపంలో పంపిణీ చేయబడింది.

ఈ రోజు మీరు పుస్తకం యొక్క పునఃముద్రణను కొనుగోలు చేయవచ్చు, దాని కవర్ కాపీ యంత్రం వద్ద విద్యార్థులను చూపుతుంది. మరియు వారెన్ టూమీకి ధన్యవాదాలు (TUHS ప్రాజెక్ట్‌ను ప్రారంభించిన) మీరు డౌన్‌లోడ్ చేసుకోవచ్చు ఆరవ ఎడిషన్ కోసం సోర్స్ కోడ్‌తో PDF ఫైల్. ఫైల్‌ను రూపొందించడానికి ఎంత కృషి చేశారనే దాని గురించి నేను మీకు ఒక ఆలోచన ఇవ్వాలనుకుంటున్నాను:

15 సంవత్సరాల క్రితం, నేను ఇచ్చిన సోర్స్ కోడ్ కాపీని టైప్ చేసాను లయన్స్, ఎందుకంటే తెలియని ఇతర కాపీల నుండి నా కాపీ నాణ్యత నాకు నచ్చలేదు. TUHS ఇంకా ఉనికిలో లేదు మరియు పాత మూలాధారాలకు నాకు యాక్సెస్ లేదు. కానీ 1988లో, నేను PDP9 కంప్యూటర్ నుండి బ్యాకప్‌ని కలిగి ఉన్న పాత 11-ట్రాక్ టేప్‌ను కనుగొన్నాను. ఇది పని చేస్తుందో లేదో చెప్పడం కష్టంగా ఉంది, కానీ చెక్కుచెదరకుండా /usr/src/ చెట్టు ఉంది, దీనిలో చాలా ఫైల్‌లు 1979 సంవత్సరంతో లేబుల్ చేయబడ్డాయి, అది కూడా పురాతనమైనది. నేను నమ్మినట్లు ఇది ఏడవ ఎడిషన్ లేదా దాని డెరివేటివ్ PWB.

నేను కనుగొన్నదాన్ని ప్రాతిపదికగా తీసుకొని ఆరవ ఎడిషన్‌కు మూలాలను మాన్యువల్‌గా సవరించాను. కొన్ని కోడ్‌లు అలాగే ఉన్నాయి, కానీ కొన్నింటిని కొద్దిగా సవరించవలసి ఉంటుంది, ఆధునిక += టోకెన్‌ను పాతది =+కి మారుస్తుంది. కొన్ని విషయాలు కేవలం తొలగించబడ్డాయి మరియు కొన్ని పూర్తిగా తిరిగి వ్రాయవలసి ఉంటుంది, కానీ చాలా ఎక్కువ కాదు.

మరియు ఈ రోజు మనం TUHSలో ఆన్‌లైన్‌లో ఆరవ ఎడిషన్ యొక్క సోర్స్ కోడ్‌ను చదవవచ్చు ఆర్కైవ్, దీనికి డెన్నిస్ రిట్చీ ఒక చేతిని కలిగి ఉన్నాడు.

మార్గం ద్వారా, మొదటి చూపులో, కెర్నిఘన్ మరియు రిచీ కాలానికి ముందు సి-కోడ్ యొక్క ప్రధాన లక్షణం సంక్షిప్తత. నా సైట్‌లో సాపేక్షంగా ఇరుకైన డిస్‌ప్లే ప్రాంతానికి సరిపోయేలా విస్తృతమైన సవరణ లేకుండానే నేను కోడ్ ముక్కలను చొప్పించలేను.

ప్రారంభంలో /usr/sys/ken/pipe.c వివరణాత్మక వ్యాఖ్య ఉంది (మరియు అవును, ఇంకా ఉంది /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

నాల్గవ ఎడిషన్ నుండి బఫర్ పరిమాణం మారలేదు. కానీ ఇక్కడ మనం చూస్తున్నాము, ఎటువంటి పబ్లిక్ డాక్యుమెంటేషన్ లేకుండా, పైప్‌లైన్‌లు ఒకప్పుడు ఫైల్‌లను బ్యాకప్ నిల్వగా ఉపయోగించాయి!

LARG ఫైల్‌ల విషయానికొస్తే, అవి వాటికి అనుగుణంగా ఉంటాయి ఐనోడ్ ఫ్లాగ్ పెద్దది, ఇది ప్రాసెస్ చేయడానికి "పెద్ద అడ్రసింగ్ అల్గోరిథం" ద్వారా ఉపయోగించబడుతుంది పరోక్ష బ్లాక్స్ పెద్ద ఫైల్ సిస్టమ్‌లకు మద్దతు ఇవ్వడానికి. వాటిని ఉపయోగించకపోవడమే మంచిదని కెన్ చెప్పినందున, నేను అతని మాటను సంతోషంగా స్వీకరిస్తాను.

ఇక్కడ నిజమైన సిస్టమ్ కాల్ ఉంది 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;
}

వ్యాఖ్య ఇక్కడ ఏమి జరుగుతుందో స్పష్టంగా వివరిస్తుంది. కానీ కోడ్‌ను అర్థం చేసుకోవడం అంత సులభం కాదు, కొంతవరకు మార్గం కారణంగా "struct యూజర్ u» మరియు రిజిస్టర్లు R0 и R1 సిస్టమ్ కాల్ పారామితులు మరియు రిటర్న్ విలువలు ఆమోదించబడ్డాయి.

తో ప్రయత్నిద్దాం ఇల్లాక్ () డిస్క్‌లో ఉంచండి ఐనోడ్ (ఇండెక్స్ హ్యాండిల్), మరియు సహాయంతో ఫాలోక్() - మెమరీలో రెండు ఉంచండి ఫైలు. అన్నీ సరిగ్గా జరిగితే, మేము ఈ ఫైల్‌లను పైప్‌లైన్ యొక్క రెండు చివరలుగా గుర్తించడానికి ఫ్లాగ్‌లను సెట్ చేస్తాము, వాటిని ఒకే ఐనోడ్‌కి (వీటి రిఫరెన్స్ కౌంట్ 2కి సెట్ చేయబడుతుంది) మరియు ఐనోడ్‌ను సవరించినట్లు మరియు ఉపయోగంలో ఉన్నట్లు గుర్తు పెట్టండి. అభ్యర్థనలపై శ్రద్ధ వహించండి నేను ఉంచా() కొత్త ఐనోడ్‌లో రిఫరెన్స్ కౌంట్‌ని తగ్గించడానికి ఎర్రర్ పాత్‌లలో.

pipe() ద్వారా తప్పక R0 и R1 చదవడం మరియు వ్రాయడం కోసం ఫైల్ డిస్క్రిప్టర్ సంఖ్యలను తిరిగి ఇవ్వండి. falloc() ఫైల్ స్ట్రక్చర్‌కు పాయింటర్‌ను తిరిగి ఇస్తుంది, కానీ దీని ద్వారా "రిటర్న్" కూడా చేస్తుంది u.u_ar0[R0] మరియు ఫైల్ డిస్క్రిప్టర్. అంటే, కోడ్ సేవ్ అవుతుంది r చదవడానికి ఫైల్ డిస్క్రిప్టర్ మరియు నేరుగా వ్రాయడానికి ఫైల్ డిస్క్రిప్టర్‌ను కేటాయిస్తుంది u.u_ar0[R0] రెండవ కాల్ తర్వాత falloc().

జెండా FPIPE, పైప్‌లైన్‌ను సృష్టించేటప్పుడు మేము సెట్ చేసిన, ఫంక్షన్ యొక్క ప్రవర్తనను నియంత్రిస్తుంది sys2.cలో rdwr()నిర్దిష్ట 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);
    }
        /* … */
}

అప్పుడు ఫంక్షన్ readp() в pipe.c పైప్‌లైన్ నుండి డేటాను చదువుతుంది. కానీ అమలు నుండి ప్రారంభించడం మంచిది writep(). మళ్లీ, ఆర్గ్యుమెంట్‌లను ఆమోదించే సంప్రదాయాల కారణంగా కోడ్ మరింత క్లిష్టంగా మారింది, అయితే కొన్ని వివరాలను విస్మరించవచ్చు.

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

మేము పైప్‌లైన్ ఇన్‌పుట్‌కు బైట్‌లను వ్రాయాలనుకుంటున్నాము u.u_count. ముందుగా మనం ఐనోడ్‌ను లాక్ చేయాలి (క్రింద చూడండి plock/prele).

అప్పుడు మేము ఐనోడ్ రిఫరెన్స్ కౌంటర్‌ని తనిఖీ చేస్తాము. పైప్‌లైన్ యొక్క రెండు చివరలు తెరిచి ఉన్నంత వరకు, కౌంటర్ 2కి సమానంగా ఉండాలి. మేము ఒక లింక్‌ను (నుండి rp->f_inode), కాబట్టి కౌంటర్ 2 కంటే తక్కువగా ఉంటే, పఠన ప్రక్రియ పైప్‌లైన్ ముగింపును మూసివేసిందని అర్థం. మరో మాటలో చెప్పాలంటే, మేము క్లోజ్డ్ పైప్‌లైన్‌కు వ్రాయడానికి ప్రయత్నిస్తున్నాము మరియు ఇది ఒక లోపం. మొదటిసారి ఎర్రర్ కోడ్ EPIPE మరియు సిగ్నల్ SIGPIPE Unix యొక్క ఆరవ ఎడిషన్‌లో కనిపించింది.

కానీ కన్వేయర్ తెరిచి ఉన్నప్పటికీ, అది నిండి ఉండవచ్చు. ఈ సందర్భంలో, పైప్‌లైన్ నుండి మరొక ప్రక్రియ చదవబడుతుంది మరియు దానిలో తగినంత స్థలాన్ని ఖాళీ చేస్తుంది అనే ఆశతో మేము లాక్‌ని విడుదల చేసి నిద్రపోతాము. మేల్కొన్న తర్వాత, మేము ప్రారంభానికి తిరిగి వస్తాము, లాక్‌ని మళ్లీ వేలాడదీయండి మరియు కొత్త రికార్డింగ్ సైకిల్‌ను ప్రారంభిస్తాము.

పైప్‌లైన్‌లో తగినంత ఖాళీ స్థలం ఉంటే, మేము దానిని ఉపయోగించి డేటాను వ్రాస్తాము వ్రాసి(). పరామితి i_size1 inode (పైప్‌లైన్ ఖాళీగా ఉంటే, అది 0కి సమానంగా ఉంటుంది) ఇది ఇప్పటికే కలిగి ఉన్న డేటా ముగింపును సూచిస్తుంది. తగినంత రికార్డింగ్ స్థలం ఉంటే, మేము నుండి పైప్‌లైన్‌ను పూరించవచ్చు i_size1 కు PIPESIZ. అప్పుడు మేము లాక్‌ని విడుదల చేస్తాము మరియు పైప్‌లైన్ నుండి చదవడానికి వేచి ఉన్న ఏదైనా ప్రక్రియను మేల్కొలపడానికి ప్రయత్నిస్తాము. మనకు అవసరమైనన్ని బైట్‌లను వ్రాయగలిగామో లేదో చూడటానికి మేము తిరిగి ప్రారంభానికి వెళ్తాము. అది విఫలమైతే, మేము కొత్త రికార్డింగ్ చక్రాన్ని ప్రారంభిస్తాము.

సాధారణంగా పరామితి i_mode అనుమతులను నిల్వ చేయడానికి inode ఉపయోగించబడుతుంది r, w и x. కానీ పైప్‌లైన్‌ల విషయంలో, బిట్‌లను ఉపయోగించి వ్రాయడం లేదా చదవడం కోసం కొంత ప్రక్రియ వేచి ఉందని మేము సూచిస్తాము IREAD и IWRITE వరుసగా. ప్రక్రియ ఫ్లాగ్ మరియు కాల్స్ సెట్ చేస్తుంది sleep(), మరియు భవిష్యత్తులో కొన్ని ఇతర ప్రక్రియలు కారణమవుతాయని భావిస్తున్నారు wakeup().

అసలు మ్యాజిక్ జరుగుతుంది sleep() и wakeup(). లో వాటిని అమలు చేస్తారు slp.c, ప్రసిద్ధ “మీరు దీన్ని అర్థం చేసుకోలేరు” వ్యాఖ్య యొక్క మూలం. అదృష్టవశాత్తూ, మేము కోడ్‌ను అర్థం చేసుకోవలసిన అవసరం లేదు, కొన్ని వ్యాఖ్యలను చూడండి:

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

కారణమయ్యే ప్రక్రియ sleep() ఒక నిర్దిష్ట ఛానెల్ కోసం, తర్వాత మరొక ప్రక్రియ ద్వారా మేల్కొలపబడవచ్చు, ఇది కారణం అవుతుంది wakeup() అదే ఛానెల్ కోసం. writep() и readp() అటువంటి జత చేసిన కాల్‌ల ద్వారా వారి చర్యలను సమన్వయం చేసుకోండి. అని గమనించండి pipe.c ఎల్లప్పుడూ ప్రాధాన్యత ఇస్తుంది PPIPE పిలిచినప్పుడు sleep(), కాబట్టి అంతే sleep() సిగ్నల్ ద్వారా అంతరాయం కలగవచ్చు.

ఇప్పుడు మేము ఫంక్షన్ అర్థం చేసుకోవడానికి ప్రతిదీ కలిగి 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);
}

మీరు ఈ ఫంక్షన్‌ను దిగువ నుండి పైకి సులభంగా చదవవచ్చు. పైప్‌లైన్‌లో కొంత డేటా ఉన్నప్పుడు "రీడ్ అండ్ రిటర్న్" బ్రాంచ్ సాధారణంగా ఉపయోగించబడుతుంది. ఈ సందర్భంలో, మేము ఉపయోగిస్తాము రెడీ() మేము ప్రస్తుత డేటా నుండి అందుబాటులో ఉన్నంత డేటాను చదువుతాము f_offset చదివి, ఆపై సంబంధిత ఆఫ్‌సెట్ విలువను నవీకరించండి.

తదుపరి రీడ్‌లలో, రీడ్ ఆఫ్‌సెట్ చేరుకున్నట్లయితే పైప్‌లైన్ ఖాళీగా ఉంటుంది i_size1 ఇనోడ్ వద్ద. మేము స్థానాన్ని 0కి రీసెట్ చేస్తాము మరియు పైప్‌లైన్‌కు వ్రాయాలనుకునే ఏదైనా ప్రక్రియను మేల్కొలపడానికి ప్రయత్నిస్తాము. కన్వేయర్ నిండినప్పుడు మనకు తెలుసు, writep() న నిద్రలోకి జారుకుంటారు ip+1. ఇప్పుడు పైప్‌లైన్ ఖాళీగా ఉంది, దాని వ్రాత చక్రాన్ని తిరిగి ప్రారంభించడానికి మేము దానిని మేల్కొలపవచ్చు.

మీకు చదవడానికి ఏమీ లేకపోతే, అప్పుడు readp() జెండాను సెట్ చేయవచ్చు IREAD మరియు నిద్రపోవడం ip+2. అతన్ని మేల్కొల్పడం ఏమిటో మాకు తెలుసు writep(), ఇది పైప్‌లైన్‌కు కొంత డేటాను వ్రాసినప్పుడు.

కు వ్యాఖ్యలు readi() మరియు writei() "" ద్వారా పారామితులను పాస్ చేయడానికి బదులుగా అర్థం చేసుకోవడంలో మీకు సహాయం చేస్తుందిu"మేము వాటిని సాధారణ I/O ఫంక్షన్‌ల వలె పరిగణించవచ్చు, ఇవి ఫైల్, స్థానం, మెమరీలో బఫర్‌ను తీసుకుంటాయి మరియు చదవడానికి లేదా వ్రాయడానికి బైట్‌ల సంఖ్యను లెక్కించవచ్చు.

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

"సంప్రదాయ" నిరోధించడం కొరకు, అప్పుడు readp() и writep() వారు తమ పనిని పూర్తి చేసే వరకు లేదా ఫలితాన్ని స్వీకరించే వరకు ఐనోడ్‌ను బ్లాక్ చేయండి (అంటే కాల్ చేయండి wakeup). plock() и prele() సరళంగా పని చేయండి: విభిన్న కాల్‌లను ఉపయోగించడం sleep и wakeup మేము ఇప్పుడే విడుదల చేసిన లాక్ అవసరమయ్యే ఏదైనా ప్రక్రియను మేల్కొలపడానికి మమ్మల్ని అనుమతించండి:

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

ఎందుకో మొదట నాకు అర్థం కాలేదు readp() కలిగించదు prele(ip) కాల్ ముందు wakeup(ip+1). మొదటి విషయం ఏమిటంటే writep() దాని చక్రంలో కారణాలు, ఇది plock(ip), ఇది ప్రతిష్టంభనకు దారి తీస్తుంది readp() నా బ్లాక్‌ని ఇంకా తీసివేయలేదు, కాబట్టి ఏదో ఒకవిధంగా కోడ్ సరిగ్గా పని చేయాలి. మీరు చూస్తే wakeup(), అప్పుడు అది స్లీపింగ్ ప్రాసెస్‌ని అమలు చేయడానికి సిద్ధంగా ఉన్నట్లు మాత్రమే సూచిస్తుంది, తద్వారా భవిష్యత్తులో sched() నిజంగా దానిని ప్రారంభించింది. కాబట్టి readp() కారణమవుతుంది wakeup(), లాక్ తీసివేస్తుంది, సెట్ చేస్తుంది IREAD మరియు కాల్స్ sleep(ip+2)- ఇదంతా ముందు writep() చక్రం తిరిగి ప్రారంభమవుతుంది.

ఇది ఆరవ ఎడిషన్‌లోని కన్వేయర్ల వివరణను పూర్తి చేస్తుంది. సాధారణ కోడ్, సుదూర పరిణామాలు.

Unix యొక్క ఏడవ ఎడిషన్ (జనవరి 1979) అనేక కొత్త అప్లికేషన్లు మరియు కెర్నల్ ఫీచర్లను పరిచయం చేసిన కొత్త ప్రధాన విడుదల (నాలుగు సంవత్సరాల తరువాత). టైప్ కాస్టింగ్, యూనియన్‌లు మరియు నిర్మాణాలకు టైప్ చేసిన పాయింటర్‌ల వినియోగానికి సంబంధించి ఇది గణనీయమైన మార్పులకు గురైంది. అయితే కన్వేయర్ కోడ్ ఆచరణాత్మకంగా మారలేదు. మేము ఈ ఎడిషన్‌ను దాటవేయవచ్చు.

Xv6, ఒక సాధారణ Unix-వంటి కెర్నల్

కెర్నల్ సృష్టించడానికి Xv6 Unix యొక్క ఆరవ ఎడిషన్ ద్వారా ప్రభావితం చేయబడింది, అయితే ఇది x86 ప్రాసెసర్‌లపై అమలు చేయడానికి ఆధునిక Cలో వ్రాయబడింది. కోడ్ చదవడం సులభం మరియు అర్థమయ్యేలా ఉంది. అదనంగా, TUHSతో Unix మూలాధారాల వలె కాకుండా, మీరు దానిని కంపైల్ చేయవచ్చు, సవరించవచ్చు మరియు PDP 11/70 కాకుండా వేరే దానిలో దీన్ని అమలు చేయవచ్చు. అందువల్ల, ఈ కెర్నల్ ఆపరేటింగ్ సిస్టమ్‌లపై విద్యా సామగ్రిగా విశ్వవిద్యాలయాలలో విస్తృతంగా ఉపయోగించబడుతుంది. మూలాలు Github లో ఉన్నాయి.

కోడ్ స్పష్టమైన మరియు ఆలోచనాత్మకమైన అమలును కలిగి ఉంది పైపు.సి, డిస్క్‌లో ఐనోడ్‌కు బదులుగా మెమరీలో బఫర్‌తో బ్యాకప్ చేయబడింది. ఇక్కడ నేను "స్ట్రక్చరల్ పైప్‌లైన్" మరియు ఫంక్షన్ యొక్క నిర్వచనాన్ని మాత్రమే అందిస్తాను 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() మిగిలిన అమలు యొక్క స్థితిని సెట్ చేస్తుంది, ఇందులో విధులు ఉంటాయి piperead(), pipewrite() и pipeclose(). అసలు సిస్టమ్ కాల్ sys_pipe లో అమలు చేయబడిన రేపర్ sysfile.c. నేను అతని మొత్తం కోడ్ చదవమని సిఫార్సు చేస్తున్నాను. సంక్లిష్టత ఆరవ ఎడిషన్ యొక్క సోర్స్ కోడ్ స్థాయిలో ఉంది, అయితే ఇది చదవడానికి చాలా సులభం మరియు మరింత ఆనందదాయకంగా ఉంటుంది.

Linux 0.01

Linux 0.01 సోర్స్ కోడ్ కనుగొనవచ్చు. తనలో పైపులైన్ల అమలుపై అధ్యయనం చేయడం బోధపడుతుంది fs/pipe.c. ఇది పైప్‌లైన్‌ను సూచించడానికి ఐనోడ్‌ను ఉపయోగిస్తుంది, కానీ పైప్‌లైన్ ఆధునిక Cలో వ్రాయబడింది. మీరు 6వ ఎడిషన్ కోడ్ ద్వారా పని చేసినట్లయితే, మీకు ఇక్కడ ఎలాంటి ఇబ్బంది ఉండదు. ఫంక్షన్ ఇలా కనిపిస్తుంది 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;
}

నిర్మాణ నిర్వచనాలను కూడా చూడకుండా, వ్రాత ఆపరేషన్ ఫలితమిస్తుందో లేదో తనిఖీ చేయడానికి ఐనోడ్ రిఫరెన్స్ కౌంట్ ఎలా ఉపయోగించబడుతుందో మీరు గుర్తించవచ్చు SIGPIPE. బైట్-బై-బైట్ పని చేయడంతో పాటు, ఈ ఫంక్షన్ పైన వివరించిన ఆలోచనలతో పోల్చడం సులభం. లాజిక్ కూడా sleep_on/wake_up అంత పరాయిగా కనిపించడం లేదు.

ఆధునిక Linux కెర్నలు, FreeBSD, NetBSD, OpenBSD

నేను కొన్ని ఆధునిక కెర్నల్స్ ద్వారా త్వరగా పరిగెత్తాను. వాటిలో ఏదీ ఇప్పుడు డిస్క్ అమలును కలిగి లేదు (ఆశ్చర్యం లేదు). Linux దాని స్వంత అమలును కలిగి ఉంది. మూడు ఆధునిక BSD కెర్నలు జాన్ డైసన్ రాసిన కోడ్ ఆధారంగా అమలులను కలిగి ఉన్నప్పటికీ, సంవత్సరాలుగా అవి ఒకదానికొకటి భిన్నంగా మారాయి.

చదవడానికి fs/pipe.c (Linuxలో) లేదా sys/kern/sys_pipe.c (*BSDలో), దీనికి నిజమైన అంకితభావం అవసరం. నేటి కోడ్ పనితీరు మరియు వెక్టర్ మరియు అసమకాలిక I/O వంటి లక్షణాలకు మద్దతు గురించి. మరియు మెమొరీ కేటాయింపు, లాక్‌లు మరియు కెర్నల్ కాన్ఫిగరేషన్ వివరాలు చాలా మారుతూ ఉంటాయి. పరిచయ ఆపరేటింగ్ సిస్టమ్స్ కోర్సు కోసం కళాశాలలకు ఇది అవసరం లేదు.

ఏది ఏమైనప్పటికీ, నేను కొన్ని పాత నమూనాలను (ఉత్పత్తి చేయడం వంటివి) త్రవ్వడానికి ఆసక్తి కలిగి ఉన్నాను SIGPIPE మరియు తిరిగి EPIPE మూసివేసిన పైప్‌లైన్‌కు వ్రాసేటప్పుడు) ఈ విభిన్న ఆధునిక కెర్నల్స్‌లో. నేను నిజ జీవితంలో PDP-11 కంప్యూటర్‌ను ఎప్పటికీ చూడలేను, కానీ నేను పుట్టడానికి సంవత్సరాల ముందు వ్రాసిన కోడ్ నుండి ఇంకా చాలా నేర్చుకోవాలి.

2011లో దివి కపూర్ రాసిన వ్యాసం:పైప్స్ మరియు FIFOల Linux కెర్నల్ అమలు" లైనక్స్‌లో పైప్‌లైన్‌లు (ఇప్పటికీ) ఎలా పని చేస్తాయో ఒక అవలోకనాన్ని అందిస్తుంది. ఎ Linuxలో ఇటీవలి కమిట్ పరస్పర చర్య యొక్క పైప్‌లైన్ నమూనాను వివరిస్తుంది, దీని సామర్థ్యాలు తాత్కాలిక ఫైల్‌ల కంటే ఎక్కువగా ఉంటాయి; మరియు ఆరవ ఎడిషన్ Unix కెర్నల్ యొక్క "చాలా సాంప్రదాయిక లాకింగ్" నుండి పైప్‌లైన్‌లు ఎంత దూరం వచ్చాయో కూడా చూపుతుంది.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి