1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297 |
- /*
- * Copyright (c) 2006-2025 RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-06-10 Bernard first version
- * 2021-02-03 lizhirui add limit condition for network syscall and add 64-bit arch support
- * 2021-02-06 lizhirui fix some bugs
- * 2021-02-12 lizhirui add 64-bit support for sys_brk
- * 2021-02-20 lizhirui fix some warnings
- * 2023-03-13 WangXiaoyao Format & fix syscall return value
- * 2023-07-06 Shell adapt the signal API, and clone, fork to new implementation of lwp signal
- * 2023-07-27 Shell Move tid_put() from lwp_free() to sys_exit()
- * 2023-11-16 xqyjlj fix some syscalls (about sched_*, get/setpriority)
- * 2023-11-17 xqyjlj add process group and session support
- * 2023-11-30 Shell Fix sys_setitimer() and exit(status)
- */
- #define __RT_IPC_SOURCE__
- #define _GNU_SOURCE
- /* RT-Thread System call */
- #include <rtthread.h>
- #include <rthw.h>
- #include <board.h>
- #include <string.h>
- #include <stdint.h>
- #define DBG_TAG "lwp.syscall"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #include "syscall_generic.h"
- #include "libc_musl.h"
- #include "lwp_internal.h"
- #ifdef ARCH_MM_MMU
- #include <mm_aspace.h>
- #include <lwp_user_mm.h>
- #include <lwp_arch.h>
- #endif
- #include <fcntl.h>
- #include <sys/utsname.h>
- #ifdef RT_USING_DFS
- #include <eventfd.h>
- #include <poll.h>
- #include <sys/epoll.h>
- #include <sys/select.h>
- #include <dfs_file.h>
- #ifdef RT_USING_DFS_V2
- #include <dfs_dentry.h>
- #endif
- #include <unistd.h>
- #include <stdio.h> /* rename() */
- #include <sys/stat.h>
- #include <sys/statfs.h> /* statfs() */
- #include <sys/timerfd.h>
- #include <sys/ioctl.h>
- #ifdef RT_USING_MUSLLIBC
- #include <sys/signalfd.h>
- #endif
- #endif
- #include "mqueue.h"
- #ifdef RT_USING_SAL
- #include <netdev_ipaddr.h>
- #include <netdev.h>
- #include <sal_netdb.h>
- #include <sal_socket.h>
- #include <sys/socket.h>
- #endif /* RT_USING_SAL */
- #if (defined(RT_USING_SAL) && defined(SAL_USING_POSIX))
- #include <sys/socket.h>
- #define SYSCALL_NET(f) f
- #else
- #define SYSCALL_NET(f) SYSCALL_SIGN(sys_notimpl)
- #endif /* (defined(RT_USING_SAL) && defined(SAL_USING_POSIX)) */
- #if defined(RT_USING_DFS) && defined(ARCH_MM_MMU)
- #define SYSCALL_USPACE(f) f
- #else
- #define SYSCALL_USPACE(f) SYSCALL_SIGN(sys_notimpl)
- #endif /* defined(RT_USING_DFS) && defined(ARCH_MM_MMU) */
- #include "lwp_ipc_internal.h"
- #include <sched.h>
- #include <sys/sysinfo.h>
- #ifndef GRND_NONBLOCK
- #define GRND_NONBLOCK 0x0001
- #endif /* GRND_NONBLOCK */
- #ifndef GRND_RANDOM
- #define GRND_RANDOM 0x0002
- #endif /*GRND_RANDOM */
- #ifndef RT_USING_POSIX_TIMER
- #error "No definition RT_USING_POSIX_TIMER"
- #endif /* RT_USING_POSIX_TIMER */
- #ifndef RT_USING_POSIX_CLOCK
- #error "No definition RT_USING_POSIX_CLOCK"
- #endif /* RT_USING_POSIX_CLOCK */
- void lwp_cleanup(struct rt_thread *tid);
- #ifdef ARCH_MM_MMU
- #define ALLOC_KERNEL_STACK_SIZE 5120
- static void *kmem_get(size_t size)
- {
- return rt_malloc(size);
- }
- static void kmem_put(void *kptr)
- {
- rt_free(kptr);
- }
- #else /* ARCH_MM_MMU */
- #define ALLOC_KERNEL_STACK_SIZE 1536
- #define ALLOC_KERNEL_STACK_SIZE_MIN 1024
- #define ALLOC_KERNEL_STACK_SIZE_MAX 4096
- extern void set_user_context(void *stack);
- #endif /* ARCH_MM_MMU */
- #ifdef RT_USING_SAL
- /* The same socket option is defined differently in the user interfaces and the
- * implementation. The options should be converted in the kernel. */
- #include "lwp_sys_socket.h"
- static void convert_sockopt(int *level, int *optname)
- {
- if (*level == INTF_SOL_SOCKET)
- {
- *level = IMPL_SOL_SOCKET;
- switch (*optname)
- {
- case INTF_SO_REUSEADDR:
- *optname = IMPL_SO_REUSEADDR;
- break;
- case INTF_SO_KEEPALIVE:
- *optname = IMPL_SO_KEEPALIVE;
- break;
- case INTF_SO_BROADCAST:
- *optname = IMPL_SO_BROADCAST;
- break;
- case INTF_SO_ACCEPTCONN:
- *optname = IMPL_SO_ACCEPTCONN;
- break;
- case INTF_SO_DONTROUTE:
- *optname = IMPL_SO_DONTROUTE;
- break;
- case INTF_SO_LINGER:
- *optname = IMPL_SO_LINGER;
- break;
- case INTF_SO_OOBINLINE:
- *optname = IMPL_SO_OOBINLINE;
- break;
- case INTF_SO_REUSEPORT:
- *optname = IMPL_SO_REUSEPORT;
- break;
- case INTF_SO_SNDBUF:
- *optname = IMPL_SO_SNDBUF;
- break;
- case INTF_SO_RCVBUF:
- *optname = IMPL_SO_RCVBUF;
- break;
- case INTF_SO_SNDLOWAT:
- *optname = IMPL_SO_SNDLOWAT;
- break;
- case INTF_SO_RCVLOWAT:
- *optname = IMPL_SO_RCVLOWAT;
- break;
- case INTF_SO_SNDTIMEO:
- *optname = IMPL_SO_SNDTIMEO;
- break;
- case INTF_SO_RCVTIMEO:
- *optname = IMPL_SO_RCVTIMEO;
- break;
- case INTF_SO_ERROR:
- *optname = IMPL_SO_ERROR;
- break;
- case INTF_SO_TYPE:
- *optname = IMPL_SO_TYPE;
- break;
- case INTF_SO_NO_CHECK:
- *optname = IMPL_SO_NO_CHECK;
- break;
- case INTF_SO_BINDTODEVICE:
- *optname = IMPL_SO_BINDTODEVICE;
- break;
- case INTF_SO_TIMESTAMPNS:
- *optname = IMPL_SO_TIMESTAMPNS;
- break;
- case INTF_SO_TIMESTAMPING:
- *optname = IMPL_SO_TIMESTAMPING;
- break;
- case INTF_SO_SELECT_ERR_QUEUE:
- *optname = IMPL_SO_SELECT_ERR_QUEUE;
- break;
- /*
- * SO_DONTLINGER (*level = ((int)(~SO_LINGER))),
- * SO_USELOOPBACK (*level = 0x0040) and
- * SO_CONTIMEO (*level = 0x1009) are not supported for now.
- */
- default:
- *optname = 0;
- break;
- }
- return;
- }
- if (*level == INTF_IPPROTO_IP)
- {
- *level = IMPL_IPPROTO_IP;
- switch (*optname)
- {
- case INTF_IP_TTL:
- *optname = IMPL_IP_TTL;
- break;
- case INTF_IP_TOS:
- *optname = IMPL_IP_TOS;
- break;
- case INTF_IP_MULTICAST_TTL:
- *optname = IMPL_IP_MULTICAST_TTL;
- break;
- case INTF_IP_MULTICAST_IF:
- *optname = IMPL_IP_MULTICAST_IF;
- break;
- case INTF_IP_MULTICAST_LOOP:
- *optname = IMPL_IP_MULTICAST_LOOP;
- break;
- case INTF_IP_ADD_MEMBERSHIP:
- *optname = IMPL_IP_ADD_MEMBERSHIP;
- break;
- case INTF_IP_DROP_MEMBERSHIP:
- *optname = IMPL_IP_DROP_MEMBERSHIP;
- break;
- default:
- break;
- }
- }
- if (*level == INTF_IPPROTO_TCP)
- {
- *level = IMPL_IPPROTO_TCP;
- switch (*optname)
- {
- case INTF_TCP_NODELAY:
- *optname = IMPL_TCP_NODELAY;
- break;
- case INTF_TCP_KEEPALIVE:
- *optname = IMPL_TCP_KEEPALIVE;
- break;
- case INTF_TCP_KEEPIDLE:
- *optname = IMPL_TCP_KEEPIDLE;
- break;
- case INTF_TCP_KEEPINTVL:
- *optname = IMPL_TCP_KEEPINTVL;
- break;
- case INTF_TCP_KEEPCNT:
- *optname = IMPL_TCP_KEEPCNT;
- break;
- default:
- break;
- }
- return;
- }
- if (*level == INTF_IPPROTO_IPV6)
- {
- *level = IMPL_IPPROTO_IPV6;
- switch (*optname)
- {
- case INTF_IPV6_V6ONLY:
- *optname = IMPL_IPV6_V6ONLY;
- break;
- default:
- break;
- }
- return;
- }
- }
- #endif /* RT_USING_SAL */
- #if defined(RT_USING_LWIP) || defined(SAL_USING_UNET)
- static void sockaddr_tolwip(const struct musl_sockaddr *std, struct sockaddr *lwip)
- {
- if (std && lwip)
- {
- lwip->sa_len = sizeof(*lwip);
- lwip->sa_family = (sa_family_t) std->sa_family;
- memcpy(lwip->sa_data, std->sa_data, sizeof(lwip->sa_data));
- }
- }
- static void sockaddr_tomusl(const struct sockaddr *lwip, struct musl_sockaddr *std)
- {
- if (std && lwip)
- {
- std->sa_family = (uint16_t) lwip->sa_family;
- memcpy(std->sa_data, lwip->sa_data, sizeof(std->sa_data));
- }
- }
- #endif
- static void _crt_thread_entry(void *parameter)
- {
- rt_thread_t tid;
- rt_size_t user_stack;
- tid = rt_thread_self();
- user_stack = (rt_size_t)tid->user_stack + tid->user_stack_size;
- user_stack &= ~7; /* align 8 */
- #ifdef ARCH_MM_MMU
- arch_crt_start_umode(parameter, tid->user_entry, (void *)user_stack, (char *)tid->stack_addr + tid->stack_size);
- #else
- set_user_context((void*)user_stack);
- arch_start_umode(parameter, tid->user_entry, ((struct rt_lwp *)tid->lwp)->data_entry, (void*)user_stack);
- #endif /* ARCH_MM_MMU */
- }
- /**
- * @brief Terminates all threads in the current thread group.
- *
- * This system call ends execution for all threads within the same thread group,
- * releasing resources such as memory and file descriptors. It is typically used
- * in multithreaded environments to ensure a clean exit for the entire process.
- *
- * @param value The exit code to be returned to the parent process.
- * @return sysret_t: return value of the system call execution.
- */
- sysret_t sys_exit_group(int value)
- {
- sysret_t rc = 0;
- lwp_status_t lwp_status;
- struct rt_lwp *lwp = lwp_self();
- if (lwp)
- {
- lwp_status = LWP_CREATE_STAT_EXIT(value);
- lwp_exit(lwp, lwp_status);
- }
- else
- {
- LOG_E("Can't find matching process of current thread");
- rc = -EINVAL;
- }
- return rc;
- }
- /**
- * @brief Terminates the calling thread and exits the process.
- *
- * This system call ends the execution of the calling thread and the process
- * it belongs to.
- *
- * @param status The exit code to be returned to the parent process.
- * A value of 0 typically indicates successful execution, while
- * non-zero values indicate an error or specific exit condition.
- * @return sysret_t: return value of the system call execution.
- *
- * @note Unlike `sys_exit_group`, which terminates all threads in a thread group,
- * `sys_exit` only terminates the calling thread and the process.
- */
- sysret_t sys_exit(int status)
- {
- sysret_t rc = 0;
- rt_thread_t tid;
- tid = rt_thread_self();
- if (tid && tid->lwp)
- {
- lwp_thread_exit(tid, status);
- }
- else
- {
- LOG_E("Can't find matching process of current thread");
- rc = -EINVAL;
- }
- return rc;
- }
- /**
- * @brief Reads data from a file descriptor into a buffer.
- *
- * This system call reads up to `nbyte` bytes of data from the file descriptor
- * specified by `fd` into the buffer pointed to by `buf`.
- *
- * @param fd The file descriptor to read from. This should be a valid file
- * descriptor obtained through system calls like `open()` or `socket()`.
- * @param buf A pointer to the buffer where the read data will be stored. The buffer
- * must have enough space to accommodate up to `nbyte` bytes.
- * @param nbyte The maximum number of bytes to read. If the file contains fewer
- * bytes than `nbyte`, only the available bytes will be read.
- * @return The number of bytes actually read, which may be less than `nbyte` if fewer
- * bytes are available or if the end of the file is reached. Returns `0` if
- * the end of the file is encountered. On error, returns `errno`.
- * @warning Ensure the buffer `buf` has sufficient space to hold the requested number
- * of bytes, as failing to do so may result in undefined behavior.
- */
- ssize_t sys_read(int fd, void *buf, size_t nbyte)
- {
- #ifdef ARCH_MM_MMU
- void *kmem = RT_NULL;
- ssize_t ret = -1;
- if (!nbyte)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)buf, nbyte))
- {
- return -EFAULT;
- }
- kmem = kmem_get(nbyte);
- if (!kmem)
- {
- return -ENOMEM;
- }
- ret = read(fd, kmem, nbyte);
- if (ret > 0)
- {
- if (ret != lwp_put_to_user(buf, kmem, ret))
- return -EFAULT;
- }
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmem);
- return ret;
- #else
- if (!lwp_user_accessable((void *)buf, nbyte))
- {
- return -EFAULT;
- }
- ssize_t ret = read(fd, buf, nbyte);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Writes data from a buffer to a file descriptor.
- *
- * This system call writes up to `nbyte` bytes of data from the buffer pointed
- * to by `buf` to the file descriptor specified by `fd`.
- *
- * @param fd The file descriptor to write to. This should be a valid file
- * descriptor obtained through system calls like `open()` or `socket()`.
- * @param buf A pointer to the buffer containing the data to be written. The
- * buffer must remain valid and accessible for the duration of the
- * write operation.
- * @param nbyte The number of bytes to write from the buffer. If the file descriptor
- * refers to a device or a socket, the actual number of bytes written
- * may be less than `nbyte`.
- * @return The number of bytes actually written. This may be less than `nbyte` if
- * the underlying resource cannot accept more data at the moment. On error,
- * returns `errno`.
- *
- * @warning Ensure the buffer `buf` contains at least `nbyte` valid bytes to
- * avoid undefined behavior. Additionally, verify that `fd` is writable
- * to prevent errors.
- *
- * @see sys_read(), write()
- */
- ssize_t sys_write(int fd, const void *buf, size_t nbyte)
- {
- #ifdef ARCH_MM_MMU
- void *kmem = RT_NULL;
- ssize_t ret = -1;
- if (nbyte)
- {
- if (!lwp_user_accessable((void *)buf, nbyte))
- {
- return -EFAULT;
- }
- kmem = kmem_get(nbyte);
- if (!kmem)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kmem, (void *)buf, nbyte);
- }
- ret = write(fd, kmem, nbyte);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmem);
- return ret;
- #else
- if (!lwp_user_accessable((void *)buf, nbyte))
- {
- return -EFAULT;
- }
- ssize_t ret = write(fd, buf, nbyte);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Repositions the file offset of the open file descriptor.
- *
- * This system call sets the file offset for the open file descriptor `fd`
- * to a new position based on the `offset` and `whence` parameters. It is used
- * for seeking within files, enabling random access to file content.
- *
- * @param fd The file descriptor whose offset is to be modified. The descriptor
- * must refer to a file capable of seeking (e.g., regular files, but
- * not pipes or sockets).
- * @param offset The new offset value relative to the position specified by `whence`.
- * Can be a positive or negative value, depending on the seek direction.
- * @param whence The reference point for the new offset. Must be one of the following:
- * - `SEEK_SET`: Set the offset to `offset` bytes from the beginning of the file.
- * - `SEEK_CUR`: Set the offset to its current position plus `offset`.
- * - `SEEK_END`: Set the offset to the size of the file plus `offset`.
- * @return On success, returns the resulting offset location as measured in bytes
- * from the beginning of the file. On failure, returns `errno`.
- *
- * @warning Ensure the file descriptor `fd` supports seeking. Using this function
- * on non-seekable file descriptors (e.g., pipes or sockets) will result in an error.
- *
- * @see sys_read(), sys_write(), lseek()
- */
- size_t sys_lseek(int fd, size_t offset, int whence)
- {
- ssize_t ret = lseek(fd, offset, whence);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Opens or creates a file, returning a file descriptor.
- *
- * This system call opens the file specified by `name` with the specified
- * access mode and flags. If the file does not exist and the `O_CREAT` flag
- * is provided, it will create the file with the specified mode.
- *
- * @param name The path to the file to be opened. This can be an absolute or
- * relative path.
- * @param flag Flags controlling how the file is opened. Common values include:
- * - `O_RDONLY`: Open the file for read-only access.
- * - `O_WRONLY`: Open the file for write-only access.
- * - `O_RDWR`: Open the file for both reading and writing.
- * - `O_CREAT`: Create the file if it does not exist (requires a mode argument).
- * - `O_TRUNC`: Truncate the file to zero length if it exists.
- * - `O_APPEND`: Open the file in append mode.
- * @param ... Optional. If the `O_CREAT` flag is specified, an additional
- * `mode_t` argument must be provided, defining the file permissions
- * (e.g., `0644` for user-read/write and group/world-read).
- * @return On success, returns the file descriptor.
- * On failure, returns `errno`.
- *
- * @note The file descriptor returned can be used with other system calls like
- * `sys_read()`, `sys_write()`, and `sys_close()`.
- *
- * @warning When using the `O_CREAT` flag, ensure to provide the `mode` argument
- * to avoid undefined behavior. Additionally, verify that the process
- * has the necessary permissions to access or create the file.
- *
- * @see sys_close(), sys_read(), sys_write(), open()
- */
- sysret_t sys_open(const char *name, int flag, ...)
- {
- #ifdef ARCH_MM_MMU
- int ret = -1;
- rt_size_t len = 0;
- char *kname = RT_NULL;
- mode_t mode = 0;
- if (!lwp_user_accessable((void *)name, 1))
- {
- return -EFAULT;
- }
- len = lwp_user_strlen(name);
- if (!len)
- {
- return -EINVAL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return -ENOMEM;
- }
- if ((flag & O_CREAT) || (flag & O_TMPFILE) == O_TMPFILE)
- {
- va_list ap;
- va_start(ap, flag);
- mode = va_arg(ap, mode_t);
- va_end(ap);
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return -EINVAL;
- }
- ret = open(kname, flag, mode);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kname);
- return ret;
- #else
- int ret;
- mode_t mode = 0;
- if (!lwp_user_accessable((void *)name, 1))
- {
- return -EFAULT;
- }
- if ((flag & O_CREAT) || (flag & O_TMPFILE) == O_TMPFILE)
- {
- va_list ap;
- va_start(ap, flag);
- mode = va_arg(ap, mode_t);
- va_end(ap);
- }
- ret = open(name, flag, mode);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Opens or creates a file relative to a directory file descriptor.
- *
- * This system call opens the file specified by `name`, relative to the directory
- * indicated by `dirfd`, with the specified flags and mode. It provides more
- * flexibility than `sys_open` for handling files in specific directory contexts.
- *
- * @param dirfd The file descriptor of the directory relative to which the file is opened.
- * Special values include:
- * - `AT_FDCWD`: Use the current working directory as the base.
- * @param name The path to the file to be opened. If `name` is absolute, `dirfd` is ignored.
- * @param flag Flags controlling how the file is opened. Common values include:
- * - `O_RDONLY`: Open the file for read-only access.
- * - `O_WRONLY`: Open the file for write-only access.
- * - `O_RDWR`: Open the file for both reading and writing.
- * - `O_CREAT`: Create the file if it does not exist.
- * - `O_TRUNC`: Truncate the file to zero length if it exists.
- * - `O_APPEND`: Open the file in append mode.
- * - `O_EXCL`: Ensure the file is created exclusively (used with `O_CREAT`).
- * @param mode The permissions to set if the file is created (e.g., `0644` for user read/write
- * and group/world read). This parameter is ignored unless `O_CREAT` is specified.
- * @return On success, returns the file descriptor.
- * On failure, returns `errno`.
- *
- * @note The `sys_openat` system call is particularly useful for implementing secure
- * directory traversal and operations, as it avoids race conditions when working
- * with relative paths.
- *
- * @warning Ensure that `dirfd` is a valid directory file descriptor if a relative
- * `name` is provided. Combining `O_CREAT` and `mode` requires proper handling
- * to avoid unintended permission settings.
- *
- * @see sys_open(), sys_read(), sys_write(), sys_close()
- */
- sysret_t sys_openat(int dirfd, const char *name, int flag, mode_t mode)
- {
- #ifdef ARCH_MM_MMU
- int ret = -1;
- rt_size_t len = 0;
- char *kname = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return -EINVAL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kname, (void *)name, len + 1);
- ret = openat(dirfd, kname, flag, mode);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kname);
- return ret;
- #else
- if (!lwp_user_accessable((void *)name, 1))
- {
- return -EFAULT;
- }
- int ret = openat(dirfd, name, flag, mode);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Closes a file descriptor.
- *
- * This system call closes the file descriptor specified by `fd`, releasing any
- * resources associated with it. Once closed, the file descriptor can no longer
- * be used for operations such as reading or writing, and it may be reassigned
- * by subsequent calls to functions like `sys_open()`.
- *
- * @param fd The file descriptor to be closed. This must be a valid open file descriptor.
- * @return On success, returns 0. On failure, returns `errno`.
- *
- * @note Closing a file descriptor that is already closed results in an error.
- * Additionally, if the file descriptor refers to a file or resource shared
- * among multiple processes or threads, only the reference count is decremented,
- * and the resource itself is not released until all references are closed.
- *
- * @warning Always ensure `fd` is valid before calling this function. Attempting
- * to close an invalid or already closed descriptor may lead to undefined
- * behavior or errors.
- *
- * @see sys_open(), sys_read(), sys_write(), close()
- */
- sysret_t sys_close(int fd)
- {
- int ret = close(fd);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Performs control operations on a file descriptor.
- *
- * This system call allows a program to manipulate the behavior of a device or file
- * associated with the file descriptor `fd` by issuing a control command (`cmd`).
- * The function provides an interface to interact with device drivers, such as modifying
- * the settings of a device or performing custom operations.
- *
- * @param fd The file descriptor representing the device or file on which the ioctl
- * command will be performed. This should be a valid, open file descriptor.
- * @param cmd The control command to be executed. The exact behavior depends on the
- * device and the command. Commands are usually defined by the device driver
- * or the kernel and can vary widely.
- * @param data A pointer to a buffer used for passing data to and from the command.
- * The contents of the buffer depend on the specific command. For input
- * commands, it may contain the data to be written to the device. For output
- * commands, it may hold the data returned by the device.
- * @return On success, returns 0. On failure, returns `errno`.
- *
- * @note The actual functionality of `sys_ioctl` depends heavily on the specific `cmd`
- * and the type of device associated with the file descriptor `fd`. Each device
- * may have a different set of valid ioctl commands.
- *
- * @warning Ensure that `fd` refers to a valid file descriptor for a device that supports
- * ioctl commands. Providing an invalid command or using an unsupported device
- * may lead to undefined behavior or errors.
- *
- * @see sys_open(), sys_read(), sys_write(), ioctl()
- */
- sysret_t sys_ioctl(int fd, unsigned long cmd, void* data)
- {
- int ret = ioctl(fd, cmd, data);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Retrieves information about a file associated with a file descriptor.
- *
- * This system call retrieves the status information about the file referred to
- * by the file descriptor `file` and stores it in the structure pointed to by `buf`.
- * It is typically used to obtain metadata such as file size, permissions, type,
- * and timestamps.
- *
- * @param file The file descriptor referring to an open file. It must be a valid file
- * descriptor returned by `sys_open()` or similar system calls.
- * @param buf A pointer to a `struct stat` that will be populated with the file's
- * status information, including attributes like size, access times,
- * permissions, and more.
- * @return On success, returns `0`. On failure, returns `errno` to indicate the error.
- *
- * @note The structure `struct stat` typically includes the following fields:
- * - `st_size`: Size of the file in bytes.
- * - `st_mode`: File type and permissions.
- * - `st_mtime`: Last modification time.
- * - `st_atime`: Last access time.
- * - `st_ctime`: Time of last status change.
- *
- * @warning Ensure that `file` is a valid, open file descriptor. Invalid file
- * descriptors or unsupported file types may lead to errors when using
- * this function.
- *
- * @see sys_open(), sys_close(), stat(), fstat()
- */
- sysret_t sys_fstat(int file, struct stat *buf)
- {
- #ifdef ARCH_MM_MMU
- int ret = -1;
- struct stat statbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct stat)))
- {
- return -EFAULT;
- }
- else
- {
- ret = fstat(file, &statbuff);
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statbuff, sizeof statbuff);
- }
- else
- {
- ret = GET_ERRNO();
- }
- return ret;
- }
- #else
- if (!lwp_user_accessable((void *)buf, sizeof(struct stat)))
- {
- return -EFAULT;
- }
- int ret = fstat(file, buf);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Monitors multiple file descriptors to see if they are ready for I/O.
- *
- * This system call monitors the file descriptors specified in `fds` for any
- * I/O events such as readiness for reading, writing, or exceptional conditions.
- * It waits up to the specified timeout and returns with information about which
- * file descriptors are ready for the requested operations.
- *
- * @param fds An array of `struct pollfd` structures, each specifying a file descriptor
- * to be monitored and the events to be checked for. On return, each structure
- * will contain the result of the poll operation for that file descriptor.
- * @param nfds The number of elements in the `fds` array.
- * @param timeout The maximum time (in milliseconds) to wait for events. If `timeout`
- * is `-1`, the call will block indefinitely. If `timeout` is `0`,
- * the call will return immediately.
- * @return On success, returns the number of file descriptors with events that are ready,
- * or `0` if the timeout expired with no events. On error, returns `-1` and sets `errno`.
- *
- * @note The `pollfd` structure used for each file descriptor contains the following fields:
- * - `fd`: The file descriptor to be monitored.
- * - `events`: The events to monitor (e.g., `POLLIN`, `POLLOUT`).
- * - `revents`: The events that actually occurred.
- *
- * @warning Ensure that `fds` contains valid file descriptors. Invalid descriptors or
- * unsupported types (such as sockets) may result in errors. Also, be mindful
- * of the timeout behavior - passing `0` will cause an immediate return, and passing
- * `-1` will block indefinitely.
- *
- * @see sys_select(), poll(), select()
- */
- sysret_t sys_poll(struct pollfd *fds, nfds_t nfds, int timeout)
- {
- int ret = -1;
- #ifdef ARCH_MM_MMU
- struct pollfd *kfds = RT_NULL;
- if (!lwp_user_accessable((void *)fds, nfds * sizeof *fds))
- {
- return -EFAULT;
- }
- kfds = (struct pollfd *)kmem_get(nfds * sizeof *kfds);
- if (!kfds)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kfds, fds, nfds * sizeof *kfds);
- ret = poll(kfds, nfds, timeout);
- if (ret > 0)
- {
- lwp_put_to_user(fds, kfds, nfds * sizeof *kfds);
- }
- kmem_put(kfds);
- return ret;
- #else
- if (!lwp_user_accessable((void *)fds, nfds * sizeof *fds))
- {
- return -EFAULT;
- }
- ret = poll(fds, nfds, timeout);
- return ret;
- #endif /* ARCH_MM_MMU */
- }
- /**
- * @brief Monitors multiple file descriptors for readiness to perform I/O operations.
- *
- * This system call allows a program to monitor multiple file descriptors to see if
- * they are ready for reading, writing, or have exceptional conditions. It waits
- * for one or more of the file descriptors to become ready or for the specified
- * timeout to expire.
- *
- * @param nfds The highest-numbered file descriptor in any of the sets, plus one.
- * This is the number of file descriptors to monitor.
- * @param readfds A pointer to an `fd_set` structure specifying the file descriptors
- * to be checked for readability. If a file descriptor is ready to
- * read, it will be set in the returned `fd_set`.
- * @param writefds A pointer to an `fd_set` structure specifying the file descriptors
- * to be checked for writability. If a file descriptor is ready to
- * write, it will be set in the returned `fd_set`.
- * @param exceptfds A pointer to an `fd_set` structure specifying the file descriptors
- * to be checked for exceptional conditions (e.g., out-of-band data).
- * If a file descriptor has exceptional conditions, it will be set in
- * the returned `fd_set`.
- * @param timeout A pointer to a `struct timeval` that specifies the maximum time
- * to wait for an event. If `NULL`, the call blocks indefinitely. If
- * `timeout` is `0`, the call will return immediately.
- * @return On success, returns the number of file descriptors that are ready for
- * the requested operations, or `0` if the timeout expired without any events.
- * On error, returns `-1` and sets `errno`.
- *
- * @note The `fd_set` structures should be initialized using the `FD_ZERO` macro
- * and populated using the `FD_SET` macro. After the call, the `fd_set` structures
- * will contain the file descriptors that are ready for the requested operations.
- *
- * @warning Ensure that the `fd_set` structures are properly initialized and that
- * `nfds` correctly reflects the number of file descriptors to monitor.
- * Passing invalid file descriptors or incorrect `nfds` can lead to undefined behavior.
- *
- * @see sys_poll(), sys_read(), sys_write(), poll(), select()
- */
- sysret_t sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
- {
- #ifdef ARCH_MM_MMU
- int ret = -1;
- fd_set *kreadfds = RT_NULL, *kwritefds = RT_NULL, *kexceptfds = RT_NULL;
- if (readfds)
- {
- if (!lwp_user_accessable((void *)readfds, sizeof *readfds))
- {
- SET_ERRNO(EFAULT);
- goto quit;
- }
- kreadfds = (fd_set *)kmem_get(sizeof *kreadfds);
- if (!kreadfds)
- {
- SET_ERRNO(ENOMEM);
- goto quit;
- }
- lwp_get_from_user(kreadfds, readfds, sizeof *kreadfds);
- }
- if (writefds)
- {
- if (!lwp_user_accessable((void *)writefds, sizeof *writefds))
- {
- SET_ERRNO(EFAULT);
- goto quit;
- }
- kwritefds = (fd_set *)kmem_get(sizeof *kwritefds);
- if (!kwritefds)
- {
- SET_ERRNO(ENOMEM);
- goto quit;
- }
- lwp_get_from_user(kwritefds, writefds, sizeof *kwritefds);
- }
- if (exceptfds)
- {
- if (!lwp_user_accessable((void *)exceptfds, sizeof *exceptfds))
- {
- SET_ERRNO(EFAULT);
- goto quit;
- }
- kexceptfds = (fd_set *)kmem_get(sizeof *kexceptfds);
- if (!kexceptfds)
- {
- SET_ERRNO(EINVAL);
- goto quit;
- }
- lwp_get_from_user(kexceptfds, exceptfds, sizeof *kexceptfds);
- }
- ret = select(nfds, kreadfds, kwritefds, kexceptfds, timeout);
- if (kreadfds)
- {
- lwp_put_to_user(readfds, kreadfds, sizeof *kreadfds);
- }
- if (kwritefds)
- {
- lwp_put_to_user(writefds, kwritefds, sizeof *kwritefds);
- }
- if (kexceptfds)
- {
- lwp_put_to_user(exceptfds, kexceptfds, sizeof *kexceptfds);
- }
- quit:
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- if (kreadfds)
- {
- kmem_put(kreadfds);
- }
- if (kwritefds)
- {
- kmem_put(kwritefds);
- }
- if (kexceptfds)
- {
- kmem_put(kexceptfds);
- }
- return ret;
- #else
- int ret;
- if (!lwp_user_accessable((void *)readfds, sizeof *readfds))
- {
- return -EFAULT;
- }
- if (!lwp_user_accessable((void *)writefds, sizeof *writefds))
- {
- return -EFAULT;
- }
- if (!lwp_user_accessable((void *)exceptfds, sizeof *exceptfds))
- {
- return -EFAULT;
- }
- ret = select(nfds, readfds, writefds, exceptfds, timeout);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Removes a file or symbolic link from the filesystem.
- *
- * This system call deletes the file or symbolic link specified by `pathname`.
- * After the call, the file will be unlinked from the filesystem, meaning it will
- * no longer be accessible via its pathname. If the file is still open, it will
- * remain available to processes that have it open until all file descriptors are
- * closed. If the file is a regular file and has no other hard links, it will be
- * removed from the disk once all references to it are closed.
- *
- * @param pathname The path to the file or symbolic link to be removed. It can be
- * an absolute or relative path.
- * @return On success, returns `0`. On failure, returns `errno` to indicate
- * the error.
- *
- * @note If the file is currently being used by a process (i.e., the file descriptor
- * is still open), it will not be immediately removed from the disk. The actual
- * removal occurs once the file is no longer in use. Symbolic links are removed
- * as soon as the call is executed.
- *
- * @warning Ensure that the file or link to be removed exists and that the `pathname`
- * is correctly specified. The operation will fail if the file is open and
- * in use by other processes or if the pathname does not exist.
- *
- * @see sys_open(), sys_remove(), unlink()
- */
- sysret_t sys_unlink(const char *pathname)
- {
- #ifdef ARCH_MM_MMU
- int ret = -1;
- rt_size_t len = 0;
- char *kname = RT_NULL;
- len = lwp_user_strlen(pathname);
- if (!len)
- {
- return -EINVAL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kname, (void *)pathname, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return -EINVAL;
- }
- ret = unlink(kname);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kname);
- return ret;
- #else
- int ret = 0;
- ret = unlink(pathname);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Suspends execution for a specified amount of time.
- *
- * This system call suspends the execution of the calling thread for the duration
- * specified by the `rqtp` argument. The `rqtp` argument is a pointer to a `struct timespec`
- * that defines the sleep time in seconds and nanoseconds. If the sleep is interrupted by a signal,
- * the function may return early with the remaining time in `rmtp`, which is an optional argument.
- *
- * @param rqtp A pointer to a `struct timespec` that specifies the requested sleep time.
- * The structure contains two fields: `tv_sec` (seconds) and `tv_nsec` (nanoseconds).
- * @param rmtp A pointer to a `struct timespec` where the remaining time will be stored if the
- * sleep is interrupted by a signal. This can be `NULL` if the remaining time is not needed.
- * @return On success, returns `0`. On failure, returns `errno` to indicate the error.
- *
- * @note The `timespec` structure has two fields:
- * - `tv_sec`: The number of whole seconds to sleep.
- * - `tv_nsec`: The number of nanoseconds to sleep after the seconds. This value should be
- * in the range [0, 1,000,000,000) nanoseconds.
- *
- * @warning Ensure that the values in `rqtp` are within valid ranges. A `tv_nsec` value greater than
- * or equal to 1,000,000,000 will result in an error. If `rmtp` is provided, the caller
- * must ensure the buffer is large enough to store the remaining time.
- *
- * @see sys_sleep(), clock_nanosleep(), nanosleep()
- */
- sysret_t sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
- {
- int ret = 0;
- LOG_D("sys_nanosleep\n");
- if (!lwp_user_accessable((void *)rqtp, sizeof *rqtp))
- return -EFAULT;
- #ifdef ARCH_MM_MMU
- struct timespec rqtp_k;
- struct timespec rmtp_k;
- lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
- ret = nanosleep(&rqtp_k, &rmtp_k);
- if ((ret != -1 || rt_get_errno() == EINTR) && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
- {
- lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
- if(ret != 0)
- return -EINTR;
- }
- #else
- if (rmtp)
- {
- if (!lwp_user_accessable((void *)rmtp, sizeof *rmtp))
- return -EFAULT;
- ret = nanosleep(rqtp, rmtp);
- }
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Retrieves the current time and timezone information.
- *
- * This system call retrieves the current time in seconds and microseconds since
- * the Unix epoch (1970-01-01 00:00:00 UTC) and stores it in the `tp` argument.
- * It also retrieves the timezone information, if requested, and stores it in the
- * `tzp` argument. The time returned is the local time of the system unless
- * UTC is specified.
- *
- * @param tp A pointer to a `struct timeval` where the current time will be stored.
- * The `struct timeval` contains two fields:
- * - `tv_sec`: The number of seconds since the Unix epoch.
- * - `tv_usec`: The number of microseconds past `tv_sec`.
- * @param tzp A pointer to a `struct timezone` where the timezone information will
- * be stored. This structure contains two fields:
- * - `tz_minuteswest`: The number of minutes west of UTC.
- * - `tz_dsttime`: A flag indicating the type of daylight saving time (DST) adjustment.
- * If `tzp` is `NULL`, timezone information is not provided.
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @note The `struct timeval` represents the current time in seconds and microseconds,
- * while `struct timezone` provides information on the timezone relative to UTC
- * and any daylight saving adjustments.
- *
- * @warning Ensure that `tp` and `tzp` are valid pointers before calling the function.
- * If you don't need timezone information, you can pass `NULL` for `tzp`.
- *
- * @see sys_time(), time(), gettimeofday()
- */
- sysret_t sys_gettimeofday(struct timeval *tp, struct timezone *tzp)
- {
- #ifdef ARCH_MM_MMU
- struct timeval t_k;
- if (tp)
- {
- if (!lwp_user_accessable((void *)tp, sizeof *tp))
- {
- return -EFAULT;
- }
- t_k.tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;
- t_k.tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND);
- lwp_put_to_user(tp, (void *)&t_k, sizeof t_k);
- }
- #else
- if (tp)
- {
- if (!lwp_user_accessable((void *)tp, sizeof *tp))
- {
- return -EFAULT;
- }
- tp->tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;
- tp->tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND);
- }
- #endif
- return 0;
- }
- /**
- * @brief Sets the system's current time and timezone information.
- *
- * @param tv A pointer to a `struct timeval` that contains the new system time to set.
- * The `struct timeval` consists of:
- * - `tv_sec`: The number of seconds since the Unix epoch (1970-01-01 00:00:00 UTC).
- * - `tv_usec`: The number of microseconds past `tv_sec`.
- * @param tzp A pointer to a `struct timezone` that contains the new timezone settings.
- * The `struct timezone` consists of:
- * - `tz_minuteswest`: The number of minutes west of UTC.
- * - `tz_dsttime`: The type of daylight saving time adjustment.
- * If `tzp` is `NULL`, the timezone information is not changed.
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @note haven't supported now.
- *
- * @see sys_gettimeofday(), settimeofday(), time()
- */
- sysret_t sys_settimeofday(const struct timeval *tv, const struct timezone *tzp)
- {
- return 0;
- }
- /**
- * @brief Replaces the current process with a new process.
- *
- * This system call loads a new program into the current process's address space,
- * replacing the current program with the one specified by `filename`. It passes the
- * arguments `argv` and environment variables `envp` to the new program. If the execution
- * is successful, the current process is completely replaced, and no code after the
- * `sys_exec` call is executed. If an error occurs, the system call returns, and the
- * current process continues executing.
- *
- * @param filename The path to the executable file to be run. This can be an absolute
- * or relative path.
- * @param argc The number of arguments passed to the new program. This includes the
- * executable name itself as the first argument.
- * @param argv An array of strings (character pointers), where each string is an argument
- * passed to the new program. The first element (`argv[0]`) is conventionally
- * the name of the executable.
- * @param envp An array of strings representing the environment variables for the new
- * process. The array is terminated by a `NULL` pointer.
- * @return This function does not return on success, as the current process is replaced.
- * On failure, it returns error code to indicate the error.
- *
- * @note The new process inherits most of the attributes of the current process, such
- * as file descriptors, unless explicitly modified. It is important that `argv`
- * and `envp` are properly formatted, and the `filename` points to a valid executable.
- *
- * @warning If `filename` is invalid or not an executable, or if the arguments or
- * environment variables are incorrectly set, the system call will fail and
- * return `-1`. Ensure that the executable file is accessible and that `argv`
- * and `envp` are properly constructed.
- *
- * @see execve(), execvp(), execv(), execle()
- */
- sysret_t sys_exec(char *filename, int argc, char **argv, char **envp)
- {
- int ret = 0;
- int len = 0;
- char *kfilename = RT_NULL;
- len = lwp_user_strlen(filename);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kfilename = (char *)kmem_get(len + 1);
- if (!kfilename)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kfilename, (void *)filename, len + 1) != (len + 1))
- {
- kmem_put(kfilename);
- return -EFAULT;
- }
- ret = lwp_execve(kfilename, 0, argc, argv, envp);
- kmem_put(kfilename);
- return ret;
- }
- /**
- * @brief Sends a signal to a process or a group of processes.
- *
- * This system call sends the signal specified by `signo` to the process or process group
- * identified by `pid`. If `pid` is positive, the signal is sent to the process with the
- * specified process ID. If `pid` is `0`, the signal is sent to all processes in the
- * same process group as the caller. If `pid` is `-1`, the signal is sent to all processes
- * except for the caller. If `pid` is less than `-1`, the signal is sent to all processes
- * in the process group with the process group ID equal to `-pid`.
- *
- * @param pid The process ID or process group ID to which the signal is to be sent.
- * - A positive value sends the signal to the process with that ID.
- * - `0` sends the signal to all processes in the same process group as the caller.
- * - `-1` sends the signal to all processes except the caller.
- * - A negative value sends the signal to all processes in the process group
- * with the process group ID equal to `-pid`.
- * @param signo The signal to send. This is an integer value that specifies the signal
- * type. Common signal values include:
- * - `SIGTERM` (terminate process)
- * - `SIGKILL` (force kill process)
- * - `SIGSTOP` (suspend process)
- * - `SIGCONT` (resume process)
- * @return On success, returns `0`. On failure, it returns error code to indicate the error.
- *
- * @note Signals are a mechanism for inter-process communication, allowing processes
- * to send notifications or requests to other processes. The behavior of signals
- * depends on the signal type and how the receiving process handles them.
- *
- * @warning The `signo` value must be a valid signal number. Passing an invalid signal
- * number or an invalid `pid` may result in an error. Additionally, some signals
- * (e.g., `SIGKILL`) cannot be caught or ignored by processes.
- *
- * @see signal(), killpg(), raise()
- */
- sysret_t sys_kill(int pid, int signo)
- {
- rt_err_t kret = 0;
- sysret_t sysret;
- struct rt_lwp *lwp = RT_NULL;
- /* handling the semantics of sys_kill */
- if (pid > 0)
- {
- /**
- * Brief: Match the pid and send signal to the lwp if found
- * Note: Critical Section
- * - pid tree (READ. since the lwp is fetch from the pid tree, it must stay there)
- */
- lwp_pid_lock_take();
- lwp = lwp_from_pid_raw_locked(pid);
- if (lwp)
- {
- lwp_ref_inc(lwp);
- lwp_pid_lock_release();
- }
- else
- {
- lwp_pid_lock_release();
- kret = -RT_ENOENT;
- }
- if (lwp)
- {
- kret = lwp_signal_kill(lwp, signo, SI_USER, 0);
- lwp_ref_dec(lwp);
- }
- }
- else if (pid < -1 || pid == 0)
- {
- pid_t pgid = 0;
- rt_processgroup_t group;
- if (pid == 0)
- {
- /**
- * sig shall be sent to all processes (excluding an unspecified set
- * of system processes) whose process group ID is equal to the process
- * group ID of the sender, and for which the process has permission to
- * send a signal.
- */
- pgid = lwp_pgid_get_byprocess(lwp_self());
- }
- else
- {
- /**
- * sig shall be sent to all processes (excluding an unspecified set
- * of system processes) whose process group ID is equal to the absolute
- * value of pid, and for which the process has permission to send a signal.
- */
- pgid = -pid;
- }
- group = lwp_pgrp_find(pgid);
- if (group != RT_NULL)
- {
- PGRP_LOCK(group);
- kret = lwp_pgrp_signal_kill(group, signo, SI_USER, 0);
- PGRP_UNLOCK(group);
- }
- else
- {
- kret = -ECHILD;
- }
- }
- else if (pid == -1)
- {
- /**
- * sig shall be sent to all processes (excluding an unspecified set
- * of system processes) for which the process has permission to send
- * that signal.
- */
- kret = lwp_signal_kill_all(signo, SI_USER, 0);
- }
- switch (kret)
- {
- case -RT_ENOENT:
- case -ECHILD:
- sysret = -ESRCH;
- break;
- case -RT_EINVAL:
- sysret = -EINVAL;
- break;
- case -RT_ENOSYS:
- sysret = -ENOSYS;
- break;
- /**
- * kill() never returns ENOMEM, so return normally to caller.
- * IEEE Std 1003.1-2017 says the kill() function is successful
- * if the process has permission to send sig to any of the
- * processes specified by pid.
- */
- case -RT_ENOMEM:
- default:
- sysret = 0;
- }
- return sysret;
- }
- /**
- * @brief Retrieves the process ID of the calling process.
- *
- * This system call returns the process ID (PID) of the calling process. The PID is a
- * unique identifier assigned by the operating system to each running process. It can
- * be used to refer to or manipulate the process in subsequent system calls.
- *
- * @return The PID of the calling process. On failure, returns `-1` and sets `errno`
- * to indicate the error (although this function typically does not fail).
- *
- * @note The PID returned by this function is a positive integer, and it remains
- * unique during the lifetime of the process. This value can be used to manage
- * the process, including sending signals or querying process information.
- *
- * @warning This function does not take any arguments and is typically used when
- * a process needs to obtain its own PID for management or logging purposes.
- *
- * @see getppid(), getuid(), getgid()
- */
- sysret_t sys_getpid(void)
- {
- return lwp_getpid();
- }
- /**
- * @brief Retrieves the parent process ID of the calling process.
- *
- * This system call returns the process ID (PID) of the parent process of the calling process.
- * The parent process is the process that created the calling process, typically through a
- * system call like `fork()`. This information can be useful for process management and
- * for determining the hierarchy of processes.
- *
- * @return The PID of the parent process. If the calling process has no parent (for example,
- * the init process), it typically returns `1` as the PID of the system's "root" process.
- * On failure, returns `-1` and sets `errno` to indicate the error (although this function
- * typically does not fail).
- *
- * @note The `getppid()` function is commonly used when a process needs to know which
- * process is responsible for it, or for managing relationships between parent and child processes.
- *
- * @warning This function does not take any arguments and is typically used when the
- * process requires information about its parent. It should not be confused with `getpid()`,
- * which retrieves the PID of the calling process itself.
- *
- * @see getpid(), getuid(), getgid()
- */
- sysret_t sys_getppid(void)
- {
- rt_lwp_t process;
- process = lwp_self();
- if (process->parent == RT_NULL)
- {
- LOG_E("%s: process %d has no parent process", __func__, lwp_to_pid(process));
- return 0;
- }
- else
- {
- return lwp_to_pid(process->parent);
- }
- }
- /**
- * @brief Retrieves the priority of a process or process group.
- *
- * This system call returns the priority of a process or a process group, depending on
- * the value of the `which` argument.
- *
- * @param which The entity for which the priority is being requested. Possible values include:
- * - `PRIO_PROCESS`: Retrieves the priority of the process specified by `who`.
- * - `PRIO_PGRP`: Retrieves the priority of the process group specified by `who`. (Currently not supported.)
- * - `PRIO_USER`: Retrieves the priority of the user specified by `who` (the user ID). (Currently not supported.)
- * @param who The ID of the process, process group, or user. The meaning of this parameter
- * depends on the value of `which`:
- * - When `which` is `PRIO_PROCESS`, `who` is the process ID (PID) of the process.
- * - When `which` is `PRIO_PGRP`(Currently not supported.), `who` is the process group ID (PGID).
- * - When `which` is `PRIO_USER`(Currently not supported.), `who` is the user ID (UID) of the user whose
- * priority is being queried.
- * @return On success, returns the priority value (a negative integer indicates a lower
- * priority).
- *
- * @warning Ensure that `which` and `who` are correctly specified to avoid errors.
- * Invalid values for `which` or `who` may result in an error, and the function
- * will return `-1`.
- *
- * @see setpriority(), getpid(), getppid()
- */
- sysret_t sys_getpriority(int which, id_t who)
- {
- long prio = 0xff;
- if (which == PRIO_PROCESS)
- {
- struct rt_lwp *lwp = RT_NULL;
- lwp_pid_lock_take();
- lwp = lwp_from_pid_locked(who);
- if (lwp)
- {
- rt_thread_t thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
- prio = RT_SCHED_PRIV(thread).current_priority;
- }
- lwp_pid_lock_release();
- }
- return prio;
- }
- /**
- * @brief Sets the priority of a process, process group, or user.
- *
- * This system call sets the priority of a process, process group, or user, depending
- * on the value of the `which` argument. The priority is used by the operating system
- * for scheduling processes. Lower numerical values represent higher priority in many
- * systems, and the priority range may be system-specific.
- *
- * @param which The entity for which the priority is being set. Possible values include:
- * - `PRIO_PROCESS`: Sets the priority of the process specified by `who`.
- * - `PRIO_PGRP`: Sets the priority of the process group specified by `who`.(Currently not supported.)
- * - `PRIO_USER`: Sets the priority of the user specified by `who` (the user ID).(Currently not supported.)
- * @param who The ID of the process, process group, or user for which the priority is being set.
- * The meaning of this parameter depends on the value of `which`:
- * - When `which` is `PRIO_PROCESS`, `who` is the process ID (PID) of the process.
- * - When `which` is `PRIO_PGRP`(Currently not supported.) , `who` is the process group ID (PGID).
- * - When `which` is `PRIO_USER`(Currently not supported.) , `who` is the user ID (UID) of the user whose priority
- * is being set.
- * @param prio The priority value to set.
- * @return On success, returns `0`. On failure, returns `-1`.
- *
- * @note This function modifies the priority of the specified process, process group, or user.
- * The priority value is system-specific and may vary based on the system's scheduling
- * policies. Ensure that the specified priority is within the acceptable range.
- *
- * @warning Ensure that `which`, `who`, and `prio` are valid. Invalid values for these
- * parameters can result in errors, and the system call will return `-1`.
- *
- * @see getpriority(), getpid(), getppid()
- */
- sysret_t sys_setpriority(int which, id_t who, int prio)
- {
- if (which == PRIO_PROCESS)
- {
- struct rt_lwp *lwp = RT_NULL;
- lwp_pid_lock_take();
- lwp = lwp_from_pid_locked(who);
- if (lwp && prio >= 0 && prio < RT_THREAD_PRIORITY_MAX)
- {
- rt_list_t *list;
- rt_thread_t thread;
- for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
- {
- thread = rt_list_entry(list, struct rt_thread, sibling);
- rt_thread_control(thread, RT_THREAD_CTRL_RESET_PRIORITY, &prio);
- }
- lwp_pid_lock_release();
- return 0;
- }
- else
- {
- lwp_pid_lock_release();
- }
- }
- return -1;
- }
- /**
- * @brief Creates a semaphore.
- *
- * This system call creates a new semaphore with the specified `name` and initializes
- * its value. The semaphore is used for synchronizing access to shared resources in
- * concurrent programming. The semaphore's behavior is defined by the value (`value`)
- * and any flags (`flag`) that specify additional properties or settings.
- *
- * @param name The name of the semaphore. This is a string used to identify the semaphore
- * in the system. The name must be unique if the system requires it for reference.
- * @param value The initial value of the semaphore. The value typically represents the
- * number of available resources or tokens. The semaphore will be initialized
- * with this value.
- * @param flag The flag that specifies the attributes or properties of the semaphore.
- * Flags can be used to define various characteristics of the semaphore,
- * such as whether it is binary or counting, whether it is shared, etc.
- *
- * @return On success, returns a handle or reference to the created semaphore. On failure,
- * returns `NULL`.
- *
- * @note Semaphores are commonly used in multithreading and multiprocessing environments
- * to synchronize access to shared resources and ensure proper order of execution.
- * The behavior of the semaphore depends on its type and the system's implementation.
- *
- * @warning Ensure that the `name` is unique and appropriate for your system's naming
- * conventions. Invalid values for `value` or `flag` may lead to errors in semaphore
- * creation.
- *
- * @see sem_wait(), sem_post(), sem_destroy()
- */
- rt_sem_t sys_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
- {
- int len = 0;
- char *kname = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- rt_sem_t sem = rt_sem_create(kname, value, flag);
- if (lwp_user_object_add(lwp_self(), (rt_object_t)sem) != 0)
- {
- rt_sem_delete(sem);
- sem = NULL;
- }
- kmem_put(kname);
- return sem;
- }
- /**
- * @brief Deletes a semaphore and releases associated resources.
- *
- * This system call deletes an existing semaphore identified by the given handle `sem`.
- * It releases any resources associated with the semaphore and ensures that it is no longer
- * available for further synchronization operations. After deletion, the semaphore handle
- * is invalid and should not be used.
- *
- * @param sem The semaphore handle to be deleted. This handle is obtained when the semaphore
- * is created using `sys_sem_create()` or similar functions.
- *
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @note Deleting a semaphore is a critical operation that should be performed only when
- * the semaphore is no longer needed and no tasks are currently waiting or posting
- * to it. Deleting a semaphore while it is still in use may lead to undefined behavior.
- *
- * @warning Ensure that no tasks are using or blocking on the semaphore before deleting it.
- * Using a deleted semaphore will result in undefined behavior and potential system errors.
- *
- * @see sys_sem_create(), sem_wait(), sem_post()
- */
- sysret_t sys_sem_delete(rt_sem_t sem)
- {
- return lwp_user_object_delete(lwp_self(), (rt_object_t)sem);
- }
- /**
- * @brief Attempts to take (acquire) a semaphore.
- *
- * This system call attempts to acquire a semaphore, blocking the calling task until the
- * semaphore becomes available or the specified timeout expires. If the semaphore is already
- * available, the calling task will immediately take it and proceed. If the semaphore is not
- * available, the task will block until the semaphore becomes available or the timeout period
- * has elapsed. The `time` parameter specifies the maximum amount of time the task will block
- * waiting for the semaphore.
- *
- * @param sem The semaphore handle to be taken. This handle is obtained when the semaphore
- * is created using `sys_sem_create()` or similar functions.
- * @param time The maximum time to wait for the semaphore to become available. If the semaphore
- * is not acquired within this time period, the function will return with an error.
- * A value of `0` means no waiting (non-blocking), while a negative value may indicate
- * an infinite wait, depending on the system's implementation.
- *
- * @return On success, returns `0` if the semaphore was successfully taken. On failure, returns error code.
- *
- * @warning Ensure that the semaphore handle is valid and has been properly created before
- * calling this function. If the semaphore is deleted or invalid, the behavior of
- * this function is undefined.
- *
- * @see sys_sem_create(), sys_sem_delete(), sem_post()
- */
- sysret_t sys_sem_take(rt_sem_t sem, rt_int32_t time)
- {
- return rt_sem_take_interruptible(sem, time);
- }
- /**
- * @brief Releases a semaphore and wakes up any waiting tasks.
- *
- * This system call releases a semaphore, incrementing its value and allowing any tasks
- * that are blocked (waiting) on the semaphore to proceed. If there are tasks waiting for
- * the semaphore, one of them will be unblocked and allowed to take the semaphore.
- * The release operation does not block the calling task, and it will return immediately.
- *
- * @param sem The semaphore handle to be released. This handle is obtained when the semaphore
- * is created using `sys_sem_create()` or similar functions.
- *
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @warning Ensure that the semaphore handle is valid before calling this function. If the semaphore
- * is deleted or invalid, the behavior of this function is undefined.
- *
- * @see sys_sem_create(), sys_sem_delete(), sys_sem_take()
- */
- sysret_t sys_sem_release(rt_sem_t sem)
- {
- return rt_sem_release(sem);
- }
- /**
- * @brief Creates a mutex.
- *
- * This system call creates a new mutex with the specified `name` and initializes it
- * with the given `flag`. The mutex is used for synchronizing access to shared resources
- * between tasks. Mutexes are typically used to ensure that only one task can access
- * a critical section of code or a resource at a time. The `flag` parameter allows
- * for setting certain properties of the mutex, such as whether it is recursive or whether
- * it can be used by multiple tasks.
- *
- * @param name The name of the mutex. This is a string used to uniquely identify the mutex
- * within the system. The name must be unique if the system requires it.
- * @param flag The flag that specifies the attributes or properties of the mutex. Flags can
- * define various mutex behaviors, such as whether the mutex is recursive (allows
- * the same task to lock it multiple times) or whether it can be shared across
- * different parts of the system.
- *
- * @return On success, returns a handle to the created mutex. On failure, returns `-RT_NULL`.
- *
- * @note Mutexes are typically used to prevent race conditions and ensure mutual exclusion
- * when multiple tasks or threads are accessing shared resources.
- *
- * @warning Ensure that the `name` is unique and appropriate according to the system's
- * naming conventions. Invalid values for `flag` or `name` may result in errors.
- *
- * @see sys_mutex_delete(), sys_mutex_lock(), sys_mutex_unlock()
- */
- rt_mutex_t sys_mutex_create(const char *name, rt_uint8_t flag)
- {
- int len = 0;
- char *kname = RT_NULL;
- rt_mutex_t mutex = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- mutex = rt_mutex_create(kname, flag);
- if(mutex == RT_NULL)
- return RT_NULL;
- if (lwp_user_object_add(lwp_self(), (rt_object_t)mutex) != 0)
- {
- rt_mutex_delete(mutex);
- mutex = RT_NULL;
- }
- kmem_put(kname);
- return mutex;
- }
- /**
- * @brief Deletes a mutex and releases associated resources.
- *
- * This system call deletes an existing mutex identified by the given handle `mutex`.
- * It releases any resources associated with the mutex and ensures that it is no longer
- * available for further synchronization operations. After deletion, the mutex handle
- * becomes invalid and should not be used. This operation also ensures that no tasks
- * can block or attempt to lock the mutex after it has been deleted.
- *
- * @param mutex The mutex handle to be deleted. This handle is obtained when the mutex
- * is created using `sys_mutex_create()` or similar functions.
- *
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @warning Ensure that the mutex handle is valid before calling this function. Deleting
- * an already deleted or invalid mutex will result in undefined behavior.
- *
- * @see sys_mutex_create(), sys_mutex_lock(), sys_mutex_unlock()
- */
- sysret_t sys_mutex_delete(rt_mutex_t mutex)
- {
- return lwp_user_object_delete(lwp_self(), (rt_object_t)mutex);
- }
- /**
- * @brief Attempts to acquire (lock) a mutex.
- *
- * This system call attempts to acquire a mutex, blocking the calling task until the
- * mutex becomes available or the specified timeout expires. If the mutex is available,
- * the calling task will immediately acquire it and proceed. If the mutex is already locked
- * by another task, the calling task will block until the mutex is released or the timeout
- * period elapses. The `time` parameter specifies the maximum amount of time the task will
- * block while waiting for the mutex.
- *
- * @param mutex The mutex handle to be locked. This handle is obtained when the mutex is
- * created using `sys_mutex_create()` or similar functions.
- * @param time The maximum time to wait for the mutex to become available. If the mutex
- * is not acquired within this time period, the function will return an error.
- * A value of `0` means no waiting (non-blocking), while a negative value may
- * indicate an infinite wait.
- *
- * @return On success, returns `0` if the mutex was successfully acquired. On failure, returns error code.
- *
- * @warning Ensure that the mutex handle is valid and has been properly created before
- * calling this function. If the mutex is deleted or invalid, the behavior of
- * this function is undefined.
- *
- * @see sys_mutex_create(), sys_mutex_delete(), sys_mutex_unlock()
- */
- sysret_t sys_mutex_take(rt_mutex_t mutex, rt_int32_t time)
- {
- return rt_mutex_take_interruptible(mutex, time);
- }
- /**
- * @brief Releases (unlocks) a mutex.
- *
- * This system call releases a mutex that was previously acquired (locked) by the calling task.
- * If any other task is waiting for the mutex, one of them will be unblocked and allowed to
- * acquire the mutex. The release operation does not block the calling task, and it will return
- * immediately after unlocking the mutex.
- *
- * @param mutex The mutex handle to be released. This handle is obtained when the mutex is
- * created using `sys_mutex_create()` or similar functions.
- *
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @warning Ensure that the mutex handle is valid before calling this function. Attempting
- * to release a mutex that has not been locked or is already released can result
- * in undefined behavior.
- *
- * @see sys_mutex_create(), sys_mutex_delete(), sys_mutex_take()
- */
- sysret_t sys_mutex_release(rt_mutex_t mutex)
- {
- return rt_mutex_release(mutex);
- }
- #ifdef ARCH_MM_MMU
- /**
- * @brief Adjusts the end of the data segment (heap) of the calling process.
- *
- * This system call changes the location of the program break, which defines the end of
- * the data segment (heap) of the calling process. It provides a unified interface for adjusting
- * the heap size. The `addr` parameter specifies the new location for the program break.
- *
- * @param addr The new program break location. If `addr` is `NULL`, the current program
- * break is returned. If a valid address is provided, the program break will
- * be adjusted to this address. The address must be page-aligned, and changes
- * must stay within the process's allowed address space.
- *
- * @return On success, returns the new program break.
- *
- * @note This function is typically used to manage heap space in a process. The program
- * break adjustment can impact memory allocations and deallocations in the heap.
- *
- * @warning The `addr` must be a valid address within the process's allocated memory
- * space. Attempting to set an invalid program break address may result in
- * undefined behavior or memory corruption.
- *
- * @see malloc(), free(), sys_sbrk()
- */
- rt_base_t sys_brk(void *addr)
- {
- return lwp_brk(addr);
- }
- /**
- * @brief Maps a file or device into memory.
- *
- * This system call implements the `mmap2` system call, which maps a file or device into memory.
- * It provides a way for processes to access file contents directly in memory, bypassing
- * the need for explicit read or write operations. This function supports advanced memory
- * mapping options such as shared or private mappings, specific protection flags, and
- * offset alignment.
- *
- * @param addr The starting address for the memory mapping. If `NULL`, the kernel chooses
- * the address. If not `NULL`, the address must be page-aligned and meet
- * platform-specific alignment constraints.
- * @param length The length of the memory mapping in bytes. This value is rounded up to
- * the nearest page size.
- * @param prot The memory protection flags. Possible values include:
- * - `PROT_READ`: Pages can be read.
- * - `PROT_WRITE`: Pages can be written.
- * - `PROT_EXEC`: Pages can be executed.
- * - `PROT_NONE`: Pages cannot be accessed.
- * These flags can be combined using bitwise OR (`|`).
- * @param flags Flags that determine the type and behavior of the mapping. Possible values include:
- * - `MAP_SHARED`: Updates are visible to other processes that map this file.
- * - `MAP_PRIVATE`: Updates are not visible to other processes and are not written to the file.
- * - `MAP_FIXED`: Use the exact address specified in `addr`.
- * - `MAP_ANONYMOUS`: The mapping is not backed by a file and uses zero-initialized memory.
- * @param fd The file descriptor of the file to map. If `MAP_ANONYMOUS` is set in `flags`,
- * `fd` is ignored and should be set to `-1`.
- * @param pgoffset The offset in the file where the mapping starts, specified in pages (not bytes).
- * This allows finer-grained control over the starting point of the mapping.
- *
- * @return On success, returns a pointer to the mapped memory region.
- *
- * @warning Ensure that the combination of `addr`, `length`, `prot`, `flags`, and `fd` is valid.
- * Improper use may lead to undefined behavior or memory access violations.
- *
- * @see mmap(), munmap(), msync()
- */
- void *sys_mmap2(void *addr, size_t length, int prot,
- int flags, int fd, size_t pgoffset)
- {
- sysret_t rc = 0;
- long offset = 0;
- /* aligned for user addr */
- if ((rt_base_t)addr & ARCH_PAGE_MASK)
- {
- if (flags & MAP_FIXED)
- rc = -EINVAL;
- else
- {
- offset = (char *)addr - (char *)RT_ALIGN_DOWN((rt_base_t)addr, ARCH_PAGE_SIZE);
- length += offset;
- addr = (void *)RT_ALIGN_DOWN((rt_base_t)addr, ARCH_PAGE_SIZE);
- }
- }
- if (rc == 0)
- {
- /* fix parameter passing (both along have same effect) */
- if (fd == -1 || flags & MAP_ANONYMOUS)
- {
- fd = -1;
- /* MAP_SHARED has no effect and treated as nothing */
- flags &= ~MAP_SHARED;
- flags |= MAP_PRIVATE | MAP_ANONYMOUS;
- }
- rc = (sysret_t)lwp_mmap2(lwp_self(), addr, length, prot, flags, fd, pgoffset);
- }
- return rc < 0 ? (char *)rc : (char *)rc + offset;
- }
- /**
- * @brief Unmaps a memory region previously mapped with mmap or mmap2.
- *
- * This system call implements the `munmap` system call, which removes a mapping
- * for a region of memory that was previously created using `mmap` or `mmap2`.
- *
- * @param addr The starting address of the memory region to unmap. This address
- * must be page-aligned and refer to a region previously mapped.
- * @param length The length of the memory region to unmap, in bytes. This value
- * is rounded up to the nearest page size internally if needed.
- *
- * @return On success, returns `0`. On failure, returns error code.
- *
- * @warning
- * - Ensure the specified memory region corresponds to a valid, active mapping.
- * Providing invalid parameters may result in undefined behavior.
- * - Unmapping a region that is still in use by another thread or process can
- * cause concurrency issues or data corruption.
- *
- * @see mmap(), mmap2(), msync()
- */
- sysret_t sys_munmap(void *addr, size_t length)
- {
- return lwp_munmap(lwp_self(), addr, length);
- }
- /**
- * @brief Changes the size or location of an existing memory mapping.
- *
- * This system call implements the `mremap` system call, allowing the resizing
- * or relocation of a previously created memory mapping. It is typically used
- * to dynamically adjust memory allocation for mapped regions without unmapping
- * and remapping them explicitly.
- *
- * @param old_address The starting address of the existing memory mapping to be resized
- * or relocated. This must be the address returned by a previous
- * `mmap` or `mremap` call.
- * @param old_size The current size of the memory mapping, in bytes. It must match
- * the size of the original mapping.
- * @param new_size The new desired size of the memory mapping, in bytes. The size will
- * be rounded up to the nearest page size if necessary.
- * @param flags Options to control the behavior of the remapping. Possible values include:
- * - `MREMAP_MAYMOVE`: Allows the kernel to move the mapping to a new
- * address if the current region cannot be resized in place.
- * - `MREMAP_FIXED`: Requires the mapping to be relocated to the
- * specified `new_address`. This flag must be used with caution.
- * @param new_address If `MREMAP_FIXED` is set in `flags`, this specifies the address
- * for the new mapping. Otherwise, it is ignored.
- *
- * @return On success, returns a pointer to the resized or relocated memory mapping.
- *
- * @warning
- * - Ensure that the `old_address` and `old_size` correspond to a valid, existing mapping.
- *
- * @see mmap(), munmap(), msync()
- */
- void *sys_mremap(void *old_address, size_t old_size,
- size_t new_size, int flags, void *new_address)
- {
- return lwp_mremap(lwp_self(), old_address, old_size, new_size, flags, new_address);
- }
- sysret_t sys_madvise(void *addr, size_t len, int behav)
- {
- return -ENOSYS;
- }
- #endif
- /**
- * @brief Creates an event object for inter-thread or inter-process communication.
- *
- * @param name A string representing the name of the event. If `NULL`, the event will
- * be created without a name. Named events can be identified and accessed
- * globally if supported by the system.
- * @param flag Specifies the behavior of the event. Possible values include:
- * - `RT_IPC_FLAG_FIFO`: Events are handled in a first-in, first-out order.
- * - `RT_IPC_FLAG_PRIO`: Events are handled in priority order.
- *
- * @return On success, returns a handle (`rt_event_t`) to the created event. On failure,
- * returns `-RT_NULL` to indicate that the event could not be created.
- *
- * @note
- * - The event object must be explicitly deleted using `sys_event_delete` when it is
- * no longer needed to free system resources.
- *
- * @warning
- * - Ensure that sufficient system resources (e.g., memory) are available to create
- * the event. If resources are insufficient, the function will fail.
- * - Named events can potentially lead to naming conflicts if multiple events with
- * the same name are created. Use unique names to avoid such issues.
- *
- * @see sys_event_delete(), sys_event_send(), sys_event_recv()
- */
- rt_event_t sys_event_create(const char *name, rt_uint8_t flag)
- {
- int len = 0;
- rt_event_t event = RT_NULL;
- char *kname = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- event = rt_event_create(kname, flag);
- if (lwp_user_object_add(lwp_self(), (rt_object_t)event) != 0)
- {
- rt_event_delete(event);
- event = NULL;
- }
- kmem_put(kname);
- return event;
- }
- /**
- * @brief Deletes a system event object.
- *
- * This system call removes the specified system event object, releasing
- * any resources associated with it. After deletion, the event object
- * should not be used.
- *
- * @param[in] event The handle to the event object to be deleted.
- * Must be a valid `rt_event_t` object.
- *
- * @return sysret_t Returns a status code indicating the result of the
- * operation:
- * - `0` if the operation was successful.
- * - An appropriate error code otherwise.
- *
- * @note Ensure that the event is no longer being accessed by any
- * threads or tasks before calling this function.
- *
- * @warning Deleting an event that is in use or invalid may lead to
- * undefined behavior.
- * @see sys_event_create(), sys_event_send(), sys_event_recv()
- */
- sysret_t sys_event_delete(rt_event_t event)
- {
- return lwp_user_object_delete(lwp_self(), (rt_object_t)event);
- }
- /**
- * @brief Sends an event to the specified event object.
- *
- * This system call sends an event to the specified event object, setting
- * the specified bits in the event object's set. The event can be used
- * to signal other threads or tasks that a particular condition has
- * occurred.
- *
- * @param[in] event The handle to the event object to which the event
- * will be sent. Must be a valid `rt_event_t` object.
- * @param[in] set The bits to set in the event object's set. The bits
- * are specified as a bitmask, where each bit represents
- * a different event condition.
- *
- * @return sysret_t Returns a status code indicating the result of the
- * operation:
- * - `0` if the operation was successful.
- * - An appropriate error code otherwise.
- *
- * @note The event object must be created before sending events to it.
- *
- * @warning Ensure that the event object is valid and has been created
- * before calling this function.
- * @see sys_event_create(), sys_event_recv()
- */
- sysret_t sys_event_send(rt_event_t event, rt_uint32_t set)
- {
- return rt_event_send(event, set);
- }
- /**
- * @brief Receives an event from the specified event object.
- *
- * This system call waits for an event to be received from the specified
- * event object. The function blocks until the specified event bits are
- * set in the event object's set or the specified timeout period has
- * elapsed. If the event is received, the function returns the set of
- * bits that were set in the event object.
- *
- * @param[in] event The handle to the event object from which the event
- * will be received. Must be a valid `rt_event_t` object.
- * @param[in] set The bits to wait for in the event object's set. The
- * bits are specified as a bitmask, where each bit
- * represents a different event condition.
- * @param[in] opt The options for receiving the event. Possible values
- * include:
- * - `EV_EVENT_ANY`: Wait for any of the specified bits
- * to be set.
- * - `EV_EVENT_ALL`: Wait for all of the specified bits
- * to be set.
- * @param[in] timeout The maximum time to wait for the event to be
- * received, in milliseconds. A value of `0` means
- * no waiting (non-blocking), while a negative value
- * may indicate an infinite wait.
- * @param[out] recved A pointer to a variable that will receive the set
- * of bits that were set in the event object. If the
- * event is received, this variable will be updated
- * with the set of bits.
- *
- * @return sysret_t Returns a status code indicating the result of the
- * operation:
- * - `0` if the operation was successful.
- * - An appropriate error code otherwise.
- *
- * @note The event object must be created before receiving events from it.
- *
- * @warning Ensure that the event object is valid and has been created
- * before calling this function.
- * @see sys_event_create(), sys_event_send()
- */
- sysret_t sys_event_recv(rt_event_t event,
- rt_uint32_t set,
- rt_uint8_t opt,
- rt_int32_t timeout,
- rt_uint32_t *recved)
- {
- int ret = 0;
- rt_uint32_t krecved;
- if ((recved != NULL) && !lwp_user_accessable((void *)recved, sizeof(rt_uint32_t *)))
- {
- return -EFAULT;
- }
- ret = rt_event_recv(event, set, opt, timeout, &krecved);
- if ((ret == RT_EOK) && recved)
- {
- lwp_put_to_user((void *)recved, &krecved, sizeof(rt_uint32_t *));
- }
- return ret;
- }
- /**
- * @brief Creates a mailbox for inter-thread or inter-process communication.
- *
- * This system call creates a mailbox object with the specified name and size.
- * The mailbox is used to exchange messages between threads or tasks in a
- * synchronized manner. The mailbox can be used to send and receive messages
- * of a specified size.
- *
- * @param[in] name A string representing the name of the mailbox. If `NULL`,
- * the mailbox will be created without a name. Named mailboxes
- * can be identified and accessed globally if supported by the system.
- * @param[in] size The size of the mailbox, which determines the maximum number
- * of messages that can be stored in the mailbox at any given time.
- * @param[in] flag The behavior of the mailbox. Possible values include:
- * - `RT_IPC_FLAG_FIFO`: Messages are handled in a first-in, first-out order.
- * - `RT_IPC_FLAG_PRIO`: Messages are handled in priority order.
- *
- * @return rt_mailbox_t Returns a handle to the created mailbox object.
- * On failure, returns `-RT_NULL`.
- *
- * @note
- * - The mailbox object must be explicitly deleted using `sys_mb_delete` when it is
- * no longer needed to free system resources.
- *
- * @warning
- * - Ensure that sufficient system resources (e.g., memory) are available to create
- * the mailbox. If resources are insufficient, the function will fail.
- * - Named mailboxes can potentially lead to naming conflicts if multiple mailboxes
- * with the same name are created. Use unique names to avoid such issues.
- *
- * @see sys_mb_delete(), sys_mb_send(), sys_mb_recv()
- */
- rt_mailbox_t sys_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
- {
- int len = 0;
- rt_mailbox_t mb = RT_NULL;
- char *kname = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- mb = rt_mb_create(kname, size, flag);
- if (lwp_user_object_add(lwp_self(), (rt_object_t)mb) != 0)
- {
- rt_mb_delete(mb);
- mb = NULL;
- }
- kmem_put(kname);
- return mb;
- }
- /**
- * @brief Deletes a mailbox object.
- *
- * This system call deletes the specified mailbox object, releasing any resources
- * associated with it. After deletion, the mailbox object should not be used.
- *
- * @param[in] mb The handle to the mailbox object to be deleted.
- * Must be a valid `rt_mailbox_t` object.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0` if the operation was successful.
- * - An appropriate error code otherwise.
- *
- * @note Ensure that the mailbox is no longer being accessed by any threads or tasks
- * before calling this function.
- *
- * @warning Deleting a mailbox that is in use or invalid may lead to undefined behavior.
- *
- * @see sys_mb_create(), sys_mb_send(), sys_mb_recv()
- */
- sysret_t sys_mb_delete(rt_mailbox_t mb)
- {
- return lwp_user_object_delete(lwp_self(), (rt_object_t)mb);
- }
- /**
- * @brief Sends a message to a mailbox object.
- *
- * This system call posts a message (a single value) to the specified mailbox.
- * If the mailbox is full, the function will return an error code immediately without waiting time.
- *
- * @param[in] mb The handle to the mailbox object where the message
- * will be sent. Must be a valid `rt_mailbox_t` object.
- * @param[in] value The value to be sent to the mailbox. Typically, this
- * is a pointer or an integral value that represents
- * the message content.
- *
- * @return sysret_t Returns a status code indicating the result of the
- * operation:
- * - `0` if the message was successfully sent.
- * - `-RT_EFULL` if the mailbox is full.
- * - An appropriate error code for other failures.
- *
- * @note Ensure the mailbox has been properly initialized before calling
- * this function. Sending messages to an uninitialized or invalid
- * mailbox may result in undefined behavior.
- *
- * @warning If the mailbox is full and the function blocks, ensure
- * proper handling to avoid potential deadlocks.
- *
- * @see sys_mb_create(), sys_mb_recv(), sys_mb_send_wait()
- */
- sysret_t sys_mb_send(rt_mailbox_t mb, rt_ubase_t value)
- {
- return rt_mb_send(mb, value);
- }
- /**
- * @brief Sends a message to a mailbox object with a timeout.
- *
- * This system call attempts to post a message (a single value) to the specified mailbox.
- * If the mailbox is full, the function will wait for a specified timeout period
- * for space to become available. If the timeout expires before the message is sent,
- * the function returns an error.
- *
- * @param[in] mb The handle to the mailbox object where the message
- * will be sent. Must be a valid `rt_mailbox_t` object.
- * @param[in] value The value to be sent to the mailbox. Typically, this
- * is a pointer or an integral value representing the
- * message content.
- * @param[in] timeout The maximum time to wait for space to become available
- * in the mailbox, in milliseconds.
- * - a negative value can be used to wait indefinitely.
- * - `0` can be used for non-blocking behavior.
- *
- * @return sysret_t Returns a status code indicating the result of the
- * operation:
- * - `0` if the message was successfully sent.
- * - `-RT_ETIMEOUT` if the operation timed out.
- * - `-RT_EFULL` if the mailbox is full and `timeout` is `0`.
- * - An appropriate error code for other failures.
- *
- * @note Ensure the mailbox has been properly initialized before calling this function.
- * Passing an uninitialized or invalid mailbox handle may result in undefined behavior.
- *
- * @warning Using a negative value without appropriate logic may lead to indefinite blocking,
- * potentially causing deadlocks.
- * @see sys_mb_send()
- */
- sysret_t sys_mb_send_wait(rt_mailbox_t mb,
- rt_ubase_t value,
- rt_int32_t timeout)
- {
- return rt_mb_send_wait(mb, value, timeout);
- }
- /**
- * @brief Receives a message from a mailbox with a timeout.
- *
- * This system call attempts to receive a message from the specified mailbox.
- * If the mailbox is empty, the function will wait for a specified timeout
- * period for a message to arrive. If no message is received within the timeout,
- * an error is returned.
- *
- * @param[in] mb The handle to the mailbox object from which the message
- * is to be received. Must be a valid `rt_mailbox_t` object.
- * @param[out] value Pointer to a variable where the received message will
- * be stored. Must not be NULL.
- * @param[in] timeout The maximum time to wait for a message, in milliseconds.
- * - a negative value: Wait indefinitely until a message is available.
- * - `0`: Non-blocking mode. If no message is available, return immediately.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The message was successfully received.
- * - `-RT_ETIMEOUT`: The operation timed out before a message was received.
- * - Other error codes may indicate failures.
- *
- * @note Ensure the mailbox is properly initialized and the `value` pointer
- * is valid before calling this function. Passing an invalid mailbox
- * or NULL `value` pointer may lead to undefined behavior.
- *
- * @warning Using a negative value without proper safeguards may cause
- * indefinite blocking, potentially resulting in deadlocks.
- */
- sysret_t sys_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
- {
- int ret = 0;
- rt_ubase_t *kvalue;
- if (!lwp_user_accessable((void *)value, sizeof(rt_ubase_t *)))
- {
- return -EFAULT;
- }
- kvalue = kmem_get(sizeof(rt_ubase_t *));
- if (kvalue == RT_NULL)
- {
- return -ENOMEM;
- }
- ret = rt_mb_recv(mb, (rt_ubase_t *)kvalue, timeout);
- if (ret == RT_EOK)
- {
- lwp_put_to_user(value, kvalue, sizeof(rt_ubase_t *));
- }
- kmem_put(kvalue);
- return ret;
- }
- rt_weak int syslog_ctrl(int type, char *buf, int len)
- {
- return -EINVAL;
- }
- /**
- * @brief Sends a log message to the system log.
- *
- * This system call sends a message to the system log for recording or debugging purposes.
- *
- * @param[in] type The type of the log message, typically representing the severity
- * or category (e.g., debug, info, warning, error). This should be
- * a valid predefined log type.
- * @param[in] buf A pointer to a buffer containing the log message. Must be a
- * null-terminated string and a valid pointer.
- * @param[in] len The length of the log message to be sent, excluding the null
- * terminator. If the length exceeds the system log's limit,
- * the message may be truncated.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The log message was successfully recorded.
- * - Other error codes may indicate additional failures.
- *
- * @note Ensure the log type is a valid predefined value supported by the system.
- * The buffer must remain valid and accessible during the execution of this function.
- *
- * @warning Sending excessively large or frequent log messages may impact system performance.
- */
- sysret_t sys_syslog(int type, char *buf, int len)
- {
- char *tmp;
- int ret = -1;
- if (!lwp_user_accessable((void *)buf, len))
- {
- return -EFAULT;
- }
- tmp = (char *)rt_malloc(len);
- if (!tmp)
- {
- return -ENOMEM;
- }
- ret = syslog_ctrl(type, tmp, len);
- lwp_put_to_user(buf, tmp, len);
- rt_free(tmp);
- return ret;
- }
- /**
- * @brief Creates a message queue.
- *
- * This system call creates a new message queue with a specified name, message size,
- * maximum number of messages, and associated flags. The message queue allows
- * messages of a given size to be sent and received between tasks or threads.
- *
- * @param[in] name The name of the message queue. It should be a unique
- * identifier and a null-terminated string.
- * @param[in] msg_size The size of each message in the queue. This defines
- * the maximum size for individual messages that can
- * be sent or received.
- * @param[in] max_msgs The maximum number of messages the queue can hold.
- * If the queue is full, further send operations may
- * block or return an error depending on the flags.
- * @param[in] flag Flags that control the behavior of the message queue.
- * This can specify whether the queue is blocking,
- * non-blocking, or has other specific attributes.
- *
- * @return rt_mq_t Returns the handle to the created message queue, or `NULL`
- * if the creation failed (e.g., due to invalid parameters
- * or insufficient resources).
- *
- * @note Ensure that the message queue name is unique. The size of the messages
- * and the number of messages should be chosen based on the application
- * requirements.
- *
- * @warning Creating too many message queues or setting an overly large
- * `max_msgs` may lead to resource exhaustion.
- */
- rt_mq_t sys_mq_create(const char *name,
- rt_size_t msg_size,
- rt_size_t max_msgs,
- rt_uint8_t flag)
- {
- rt_mq_t mq = RT_NULL;
- int len = 0;
- char *kname = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- mq = rt_mq_create(kname, msg_size, max_msgs, flag);
- if (lwp_user_object_add(lwp_self(), (rt_object_t)mq) != 0)
- {
- rt_mq_delete(mq);
- mq = NULL;
- }
- kmem_put(kname);
- return mq;
- }
- /**
- * @brief Deletes a message queue.
- *
- * This system call deletes the specified message queue and releases any resources
- * associated with it. After calling this function, the message queue handle
- * becomes invalid and should not be used.
- *
- * @param[in] mq The handle to the message queue to be deleted.
- * Must be a valid `rt_mq_t` object.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The message queue was successfully deleted.
- * - An appropriate error code for other failures.
- *
- * @note Ensure that no tasks or threads are using the message queue before
- * deleting it to avoid undefined behavior or data loss.
- *
- * @warning Deleting an active message queue that is being used by tasks or
- * threads may lead to resource leaks or corruption. Ensure proper
- * synchronization before deletion.
- */
- sysret_t sys_mq_delete(rt_mq_t mq)
- {
- return lwp_user_object_delete(lwp_self(), (rt_object_t)mq);
- }
- /**
- * @brief Sends a message to a message queue.
- *
- * This system call sends a message to the specified message queue. The message
- * is copied into the queue's buffer. If the queue is full, the behavior will
- * depend on the flags set during queue creation (e.g., whether it is blocking
- * or non-blocking).
- *
- * @param[in] mq The handle to the message queue where the message will be sent.
- * Must be a valid `rt_mq_t` object.
- * @param[in] buffer A pointer to the message data to be sent. This must not be NULL.
- * @param[in] size The size of the message to be sent, in bytes. This should be
- * less than or equal to the maximum message size defined when
- * the queue was created.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The message was successfully sent to the queue.
- * - An appropriate error code for other failures.
- *
- * @note Ensure that the message size does not exceed the maximum allowed message
- * size when the queue was created. Passing an invalid queue handle or buffer
- * may result in undefined behavior.
- *
- * @warning Sending messages to a full queue in blocking mode may cause the calling
- * task or thread to block indefinitely if not properly handled.
- */
- sysret_t sys_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
- {
- int ret = 0;
- void *kbuffer = RT_NULL;
- if (!lwp_user_accessable((void *)buffer, size))
- {
- return -EFAULT;
- }
- kbuffer = kmem_get(size);
- if (kbuffer == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kbuffer, buffer, size) != size)
- {
- kmem_put(kbuffer);
- return -EINVAL;
- }
- ret = rt_mq_send(mq, kbuffer, size);
- kmem_put(kbuffer);
- return ret;
- }
- /**
- * @brief Sends an urgent message to a message queue.
- *
- * This system call sends a message to the specified message queue with higher priority,
- * meaning it will be placed at the front of the queue, bypassing normal message
- * order. The message is copied into the queue's buffer. If the queue is full,
- * the behavior will depend on the flags set during queue creation (e.g., whether
- * it is blocking or non-blocking).
- *
- * @param[in] mq The handle to the message queue where the message will be sent.
- * Must be a valid `rt_mq_t` object.
- * @param[in] buffer A pointer to the message data to be sent. This must not be NULL.
- * @param[in] size The size of the message to be sent, in bytes. This should be
- * less than or equal to the maximum message size defined when
- * the queue was created.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The urgent message was successfully sent to the queue.
- * - `-RT_EFULL`: The queue is full and the message could not be sent.
- * - An appropriate error code for other failures.
- *
- * @note Ensure that the message size does not exceed the maximum allowed message
- * size when the queue was created. The urgent message will be processed before
- * other normal messages in the queue.
- *
- * @warning Sending urgent messages to a full queue in blocking mode may cause the
- * calling task or thread to block indefinitely if not properly handled.
- */
- sysret_t sys_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size)
- {
- int ret = 0;
- void *kbuffer = RT_NULL;
- if (!lwp_user_accessable((void *)buffer, size))
- {
- return -EFAULT;
- }
- kbuffer = kmem_get(size);
- if (kbuffer == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kbuffer, buffer, size) != size)
- {
- kmem_put(kbuffer);
- return -EINVAL;
- }
- ret = rt_mq_urgent(mq, kbuffer, size);
- kmem_put(kbuffer);
- return ret;
- }
- /**
- * @brief Receives a message from a message queue.
- *
- * This system call attempts to receive a message from the specified message queue.
- * The message is copied into the provided buffer. If no message is available
- * in the queue, the function will block for a specified timeout period before
- * returning. If the timeout expires without receiving a message, an error is returned.
- *
- * @param[in] mq The handle to the message queue from which the message
- * will be received. Must be a valid `rt_mq_t` object.
- * @param[out] buffer A pointer to the buffer where the received message will
- * be stored. Must not be NULL and large enough to hold the
- * message.
- * @param[in] size The size of the buffer, in bytes. This should be at least
- * the size of a message in the queue.
- * @param[in] timeout The maximum time to wait for a message, in milliseconds.
- * - a negative value: Wait indefinitely until a message is available.
- * - `0`: Non-blocking mode. If no message is available, return immediately.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The message was successfully received.
- * - `-RT_ETIMEOUT`: The operation timed out before a message was received.
- * - Other error codes may indicate additional failures.
- *
- * @note Ensure the buffer is large enough to store the message received from the queue.
- * If the buffer is too small, the function may fail or behave unexpectedly.
- *
- * @warning Using a negative value without proper safeguards may cause indefinite
- * blocking, potentially resulting in deadlocks if no message is received.
- */
- sysret_t sys_mq_recv(rt_mq_t mq,
- void *buffer,
- rt_size_t size,
- rt_int32_t timeout)
- {
- int ret = 0;
- void *kbuffer = RT_NULL;
- if (!lwp_user_accessable((void *)buffer, size))
- {
- return -EFAULT;
- }
- kbuffer = kmem_get(size);
- if (kbuffer == RT_NULL)
- {
- return -ENOMEM;
- }
- ret = rt_mq_recv(mq, kbuffer, size, timeout);
- if (ret > 0)
- lwp_put_to_user((void *)buffer, (void *)kbuffer, ret);
- kmem_put(kbuffer);
- return ret;
- }
- static void timer_timeout_callback(void *parameter)
- {
- rt_sem_t sem = (rt_sem_t)parameter;
- rt_sem_release(sem);
- }
- /**
- * @brief Creates a timer.
- *
- * This system call creates a timer that can be used to trigger events or
- * actions after a specified timeout or interval. The timer will operate in a
- * real-time manner and can be configured to trigger once or repeatedly. The
- * created timer can be started, stopped, or deleted as required.
- *
- * @param[in] name The name of the timer. It should be a unique string identifier.
- * The name is used for debugging and logging purposes.
- * @param[in] data A pointer to user-defined data that will be passed to the timer's
- * callback function when it is triggered. This may be used to carry
- * context or other necessary information for the callback.
- * @param[in] period The timer period in milliseconds. The timer will trigger every
- * `period` milliseconds, or after the specified timeout.
- * @param[in] flag Flags that control the behavior of the timer. These can specify
- * whether the timer is one-shot (triggers once) or periodic
- * (triggers repeatedly).
- *
- * @return rt_timer_t Returns the handle to the created timer, or `NULL` if the creation failed.
- *
- * @note The timer callback function must be implemented to handle the event triggered
- * by the timer. Ensure that the `data` parameter, if used, is properly handled
- * in the callback.
- *
- * @warning Ensure the timer's period and flags are configured correctly to avoid
- * undesired behavior, especially if the timer is periodic.
- */
- rt_timer_t sys_rt_timer_create(const char *name,
- void *data,
- rt_tick_t time,
- rt_uint8_t flag)
- {
- int len = 0;
- char *kname = RT_NULL;
- rt_timer_t timer = RT_NULL;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- timer = rt_timer_create(kname, timer_timeout_callback, (void *)data, time, flag);
- if (lwp_user_object_add(lwp_self(), (rt_object_t)timer) != 0)
- {
- rt_timer_delete(timer);
- timer = NULL;
- }
- kmem_put(kname);
- return timer;
- }
- /**
- * @brief Deletes a timer.
- *
- * This system call deletes the specified timer and releases any resources
- * associated with it. Once the timer is deleted, its handle becomes invalid,
- * and any further operations on the timer should be avoided.
- *
- * @param[in] timer The handle to the timer to be deleted. Must be a valid `rt_timer_t` object.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer was successfully deleted.
- * - Other error codes may indicate additional failures.
- *
- * @note Ensure that the timer is not active or being used before deleting it to avoid
- * any unexpected behavior or resource leaks.
- *
- * @warning Deleting an active timer may lead to undefined behavior, especially
- * if the timer is in the middle of triggering or executing its callback.
- */
- sysret_t sys_rt_timer_delete(rt_timer_t timer)
- {
- return lwp_user_object_delete(lwp_self(), (rt_object_t)timer);
- }
- /**
- * @brief Starts a timer.
- *
- * This system call starts the specified timer, causing it to begin counting down
- * based on its configured period. Once the timer reaches the set period, it triggers the
- * associated callback function. The behavior depends on whether the timer is configured
- * as one-shot or periodic.
- *
- * @param[in] timer The handle to the timer to be started. Must be a valid `rt_timer_t` object.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer was successfully started.
- * - Other error codes may indicate additional failures.
- *
- * @note Ensure that the timer has been created and is in a valid state before attempting to start it.
- *
- * @warning Starting a timer that is already running may lead to undefined behavior. Ensure that the
- * timer is stopped or not in use before starting it.
- */
- sysret_t sys_rt_timer_start(rt_timer_t timer)
- {
- return rt_timer_start(timer);
- }
- /**
- * @brief Stops a timer.
- *
- * This system call stops the specified timer, halting its countdown and
- * preventing it from triggering further callbacks. If the timer is periodic,
- * stopping it will prevent further periodic triggers until it is started again.
- *
- * @param[in] timer The handle to the timer to be stopped. Must be a valid `rt_timer_t` object.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer was successfully stopped.
- * - Other error codes may indicate additional failures.
- *
- * @note Ensure that the timer is in a valid state before attempting to stop it.
- * Stopping an inactive or already stopped timer may not have any effect.
- *
- * @warning Stopping a timer that is actively triggering or in use may disrupt its expected
- * behavior. Ensure proper synchronization or state management when stopping
- * the timer during active use.
- */
- sysret_t sys_rt_timer_stop(rt_timer_t timer)
- {
- return rt_timer_stop(timer);
- }
- /**
- * @brief Controls various properties of a timer.
- *
- * This system call provides control over various aspects of a timer, such as
- * modifying its configuration, querying its status, or changing its behavior.
- * The specific behavior is determined by the command (`cmd`) and any associated arguments (`arg`).
- *
- * @param[in] timer The handle to the timer to be controlled. Must be a valid `rt_timer_t` object.
- * @param[in] cmd The command to execute. The meaning of this parameter depends on the command value.
- * Common commands might include modifying the timer period, changing its callback,
- * or querying its current state.
- * @param[in] arg A pointer to any additional arguments needed for the command. The type and content
- * of this argument depend on the specific command being executed.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer control operation was successful.
- * - Other error codes may indicate additional failures.
- *
- * @note Ensure that the provided command (`cmd`) is valid for the specific timer implementation.
- * Incorrect commands or arguments may lead to unexpected behavior or errors.
- *
- * @warning Using invalid or unsupported commands may cause undefined behavior or crashes.
- */
- sysret_t sys_rt_timer_control(rt_timer_t timer, int cmd, void *arg)
- {
- return rt_timer_control(timer, cmd, arg);
- }
- /* MUSL compatible */
- struct ksigevent
- {
- union sigval sigev_value;
- int sigev_signo;
- int sigev_notify;
- int sigev_tid;
- };
- /* to protect unsafe implementation in current rt-smart toolchain */
- RT_STATIC_ASSERT(sigevent_compatible, offsetof(struct ksigevent, sigev_tid) == offsetof(struct sigevent, sigev_notify_function));
- /**
- * @brief Creates a per-process timer.
- *
- * This system call creates a new timer associated with the specified clock, and
- * initializes the timer with the provided event notification attributes.
- * Once created, the timer can be started, stopped, or controlled as needed.
- * The timer will trigger when the specified expiration time or interval is reached.
- *
- * @param[in] clockid The clock to be used for the timer. Common clock values include:
- * - `CLOCK_REALTIME`: System real-time clock.
- * - `CLOCK_MONOTONIC`: Monotonic clock that cannot be set and is not affected by system time changes.
- * - Other clock IDs can be used depending on the platform and requirements.
- * @param[in] sevp A pointer to a `sigevent` structure that specifies how the process
- * should be notified when the timer expires. This can include notification
- * types such as signal delivery, thread notification, or posting to a queue.
- * @param[out] timerid A pointer to a `timer_t` variable where the created timer's ID will be stored.
- * The timer ID will be used for subsequent timer operations (e.g., starting, stopping).
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer was successfully created.
- * - Other error codes may indicate additional failures.
- *
- * @warning Ensure that the provided `sigevent` structure is properly configured, as invalid or
- * unsupported notification types may result in unexpected behavior.
- */
- sysret_t sys_timer_create(clockid_t clockid, struct sigevent *restrict sevp, timer_t *restrict timerid)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- struct sigevent sevp_k;
- timer_t timerid_k;
- int utimer;
- if (sevp == NULL)
- {
- sevp_k.sigev_notify = SIGEV_SIGNAL;
- sevp_k.sigev_signo = SIGALRM;
- sevp = &sevp_k;
- }
- else
- {
- /* clear extra bytes if any */
- if (sizeof(struct ksigevent) < sizeof(struct sigevent))
- memset(&sevp_k, 0, sizeof(sevp_k));
- /* musl passes `struct ksigevent` to kernel, we shoule only get size of that bytes */
- if (!lwp_get_from_user(&sevp_k, (void *)sevp, sizeof(struct ksigevent)))
- {
- return -EINVAL;
- }
- }
- ret = _SYS_WRAP(timer_create(clockid, &sevp_k, &timerid_k));
- if (ret != -RT_ERROR)
- {
- utimer = (rt_ubase_t)timerid_k;
- if (!lwp_put_to_user(sevp, (void *)&sevp_k, sizeof(struct ksigevent)) ||
- !lwp_put_to_user(timerid, (void *)&utimer, sizeof(utimer)))
- ret = -EINVAL;
- }
- #else
- ret = _SYS_WRAP(timer_create(clockid, sevp, timerid));
- #endif
- return ret;
- }
- /**
- * @brief Deletes a timer.
- *
- * This system call deletes the specified timer and releases any resources associated
- * with it. Once the timer is deleted, it can no longer be used, and any further
- * operations on the timer (such as starting or stopping) will result in an error.
- *
- * @param[in] timerid The ID of the timer to be deleted. This is the timer handle
- * returned by `sys_timer_create`.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer was successfully deleted.
- * - Other error codes may indicate additional failures.
- *
- * @note After calling this function, the timer ID becomes invalid, and it should
- * not be used in any further operations.
- *
- * @warning Make sure the timer is not active or in use when attempting to delete it,
- * as deleting an active timer may cause unexpected behavior or resource leaks.
- */
- sysret_t sys_timer_delete(timer_t timerid)
- {
- int ret = timer_delete(timerid);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Changes the time or interval of an existing timer.
- *
- * This system call modifies the expiration time or interval of a previously created
- * timer. It can either set a new expiration time for the timer or update the
- * interval for periodic timers. The timer can be started or modified based on
- * the flags provided. The current (old) timer settings can be retrieved if
- * requested.
- *
- * @param[in] timerid The ID of the timer to modify. This is the timer handle
- * returned by `sys_timer_create`.
- * @param[in] flags Flags that control the behavior of the operation. Common
- * values include:
- * - `TIMER_ABSTIME`: Specifies that `new_value` contains
- * an absolute time. Otherwise, it is treated as relative.
- * @param[in] new_value A pointer to the `itimerspec` structure specifying
- * the new time settings for the timer. The structure includes:
- * - `it_value`: The initial expiration time (relative or absolute).
- * - `it_interval`: The period for periodic timers.
- * @param[out] old_value A pointer to an `itimerspec` structure where the previous
- * timer settings will be stored. If NULL, the old value is ignored.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The timer time/interval was successfully updated.
- * - Other error codes may indicate additional failures.
- *
- * @warning Modifying a timer that is currently active can cause timing-related issues
- * if not handled correctly. Make sure the timer is in an appropriate state
- * before making changes.
- */
- sysret_t sys_timer_settime(timer_t timerid, int flags,
- const struct itimerspec *restrict new_value,
- struct itimerspec *restrict old_value)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- struct itimerspec new_value_k;
- struct itimerspec old_value_k;
- if (!lwp_get_from_user(&new_value_k, (void *)new_value, sizeof(*new_value)) ||
- (old_value && !lwp_get_from_user(&old_value_k, (void *)old_value, sizeof(*old_value))))
- {
- return -EFAULT;
- }
- ret = timer_settime(timerid, flags, &new_value_k, &old_value_k);
- lwp_put_to_user(old_value, (void *)&old_value_k, sizeof old_value_k);
- #else
- ret = timer_settime(timerid, flags, new_value, old_value);
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Retrieves the current time and interval of a timer.
- *
- * This system call fetches the current expiration time (`it_value`) and interval (`it_interval`)
- * of a previously created timer. It allows the caller to determine the current state of the timer,
- * whether it is one-shot or periodic, and the remaining time before expiration.
- *
- * @param[in] timerid The ID of the timer to query. This is the timer handle
- * returned by `sys_timer_create`.
- * @param[out] curr_value A pointer to an `itimerspec` structure where the current timer values
- * will be stored. This structure includes:
- * - `it_value`: The remaining time until the timer expires.
- * - `it_interval`: The interval between subsequent expirations (for periodic timers).
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The current time/interval was successfully retrieved.
- * - Other error codes may indicate additional failures.
- *
- * @warning Ensure that the timer ID is valid before calling this function, as invalid timer IDs
- * will result in errors.
- */
- sysret_t sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- struct itimerspec curr_value_k;
- lwp_get_from_user(&curr_value_k, (void *)curr_value, sizeof curr_value_k);
- ret = timer_gettime(timerid, &curr_value_k);
- lwp_put_to_user(curr_value, (void *)&curr_value_k, sizeof curr_value_k);
- #else
- ret = timer_gettime(timerid, curr_value);
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Retrieves the overrun count for a periodic timer.
- *
- * This system call retrieves the number of times a periodic timer has "overrun." An overrun occurs
- * when a timer expires before the previous expiration has been acknowledged or handled. For periodic
- * timers, this indicates how many times the timer's expiration has been missed due to delayed processing
- * or handling.
- *
- * @param[in] timerid The ID of the timer to query. This is the timer handle
- * returned by `sys_timer_create`.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - `0`: The overrun count was successfully retrieved.
- * - Other error codes may indicate additional failures.
- *
- * @warning Ensure that the timer ID is valid before calling this function, as invalid timer IDs
- * will result in errors.
- */
- sysret_t sys_timer_getoverrun(timer_t timerid)
- {
- int ret = 0;
- ret = timer_getoverrun(timerid);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Creates a new thread.
- *
- * This system call creates a new thread within the calling process. The newly created
- * thread starts executing the function specified by the `arg` argument, which typically
- * contains the necessary arguments or function pointer for the thread's execution.
- *
- * @param[in] arg An array of arguments that will be passed to the function executed
- * by the new thread. This can include function pointers, structures,
- * or any necessary data the thread will need to execute its work.
- *
- * @return rt_thread_t Returns a handle to the newly created thread. If the thread
- * creation fails, `NULL` is returned.
- *
- * @warning Ensure that the system has sufficient resources to create a new thread.
- * Thread creation failures can occur if system limits are exceeded or resources
- * are unavailable.
- */
- rt_thread_t sys_thread_create(void *arg[])
- {
- void *user_stack = 0;
- struct rt_lwp *lwp = 0;
- rt_thread_t thread = RT_NULL;
- int tid = 0;
- lwp = rt_thread_self()->lwp;
- lwp_ref_inc(lwp);
- #ifdef ARCH_MM_MMU
- user_stack = lwp_map_user(lwp, 0, (size_t)arg[3], 0);
- if (!user_stack)
- {
- goto fail;
- }
- if ((tid = lwp_tid_get()) == 0)
- {
- goto fail;
- }
- thread = rt_thread_create((const char *)arg[0],
- _crt_thread_entry,
- (void *)arg[2],
- ALLOC_KERNEL_STACK_SIZE,
- (rt_uint8_t)(size_t)arg[4],
- (rt_uint32_t)(rt_size_t)arg[5]);
- if (!thread)
- {
- goto fail;
- }
- #ifdef RT_USING_SMP
- RT_SCHED_CTX(thread).bind_cpu = lwp->bind_cpu;
- #endif
- thread->cleanup = lwp_cleanup;
- thread->user_entry = (void (*)(void *))arg[1];
- thread->user_stack = (void *)user_stack;
- thread->user_stack_size = (rt_size_t)arg[3];
- #else
- rt_uint32_t kstack_size = (rt_uint32_t)arg[7];
- if (kstack_size < ALLOC_KERNEL_STACK_SIZE_MIN)
- {
- /* When kstack size is 0, the default size of the kernel stack is used */
- kstack_size = kstack_size ? ALLOC_KERNEL_STACK_SIZE_MIN : ALLOC_KERNEL_STACK_SIZE;
- }
- else if (kstack_size > ALLOC_KERNEL_STACK_SIZE_MAX)
- {
- kstack_size = ALLOC_KERNEL_STACK_SIZE_MAX;
- }
- user_stack = (void *)arg[3];
- if ((!user_stack) || ((rt_uint32_t)arg[6] == RT_NULL))
- {
- goto fail;
- }
- if ((tid = lwp_tid_get()) == 0)
- {
- goto fail;
- }
- thread = rt_thread_create((const char *)arg[0], _crt_thread_entry, (void *)arg[2], kstack_size, (rt_uint8_t)(size_t)arg[5], (rt_uint32_t)arg[6]);
- if (!thread)
- {
- goto fail;
- }
- thread->cleanup = lwp_cleanup;
- thread->user_entry = (void (*)(void *))arg[1];
- thread->user_stack = (void *)user_stack;
- thread->user_stack_size = (uint32_t)arg[4];
- rt_memset(thread->user_stack, '#', thread->user_stack_size);
- #endif /* ARCH_MM_MMU */
- thread->lwp = (void*)lwp;
- thread->tid = tid;
- lwp_tid_set_thread(tid, thread);
- if (lwp->debug)
- {
- rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
- }
- LWP_LOCK(lwp);
- rt_list_insert_after(&lwp->t_grp, &thread->sibling);
- LWP_UNLOCK(lwp);
- return thread;
- fail:
- lwp_tid_put(tid);
- if (lwp)
- {
- lwp_ref_dec(lwp);
- }
- return RT_NULL;
- }
- #ifdef ARCH_MM_MMU
- long _sys_clone(void *arg[])
- {
- struct rt_lwp *lwp = 0;
- rt_thread_t thread = RT_NULL;
- rt_thread_t self = RT_NULL;
- int tid = 0;
- rt_err_t err;
- unsigned long flags = 0;
- void *user_stack = RT_NULL;
- int *new_tid = RT_NULL;
- void *tls = RT_NULL;
- /*
- musl call flags (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
- | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
- | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED);
- */
- /* check args */
- if (!lwp_user_accessable(arg, sizeof(void *[SYS_CLONE_ARGS_NR])))
- {
- return -EFAULT;
- }
- flags = (unsigned long)(size_t)arg[0];
- if ((flags & (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
- != (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
- {
- return -EINVAL;
- }
- user_stack = arg[1];
- new_tid = (int *)arg[2];
- tls = (void *)arg[3];
- if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
- {
- if (!lwp_user_accessable(new_tid, sizeof(int)))
- {
- return -EFAULT;
- }
- }
- self = rt_thread_self();
- lwp = self->lwp;
- lwp_ref_inc(lwp);
- if (!user_stack)
- {
- SET_ERRNO(EINVAL);
- goto fail;
- }
- if ((tid = lwp_tid_get()) == 0)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- thread = rt_thread_create(self->parent.name,
- RT_NULL,
- RT_NULL,
- self->stack_size,
- RT_SCHED_PRIV(self).init_priority,
- RT_SCHED_PRIV(self).init_tick);
- if (!thread)
- {
- goto fail;
- }
- #ifdef RT_USING_SMP
- RT_SCHED_CTX(self).bind_cpu = lwp->bind_cpu;
- #endif
- thread->cleanup = lwp_cleanup;
- thread->user_entry = RT_NULL;
- thread->user_stack = RT_NULL;
- thread->user_stack_size = 0;
- thread->lwp = (void *)lwp;
- thread->tid = tid;
- if ((flags & CLONE_SETTLS) == CLONE_SETTLS)
- {
- thread->thread_idr = tls;
- }
- if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
- {
- *new_tid = (int)(tid);
- }
- if ((flags & CLONE_CHILD_CLEARTID) == CLONE_CHILD_CLEARTID)
- {
- thread->clear_child_tid = (int *)arg[4];
- }
- if (lwp->debug)
- {
- rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
- }
- LWP_LOCK(lwp);
- rt_list_insert_after(&lwp->t_grp, &thread->sibling);
- LWP_UNLOCK(lwp);
- /* copy origin stack */
- lwp_memcpy(thread->stack_addr, self->stack_addr, thread->stack_size);
- lwp_tid_set_thread(tid, thread);
- arch_set_thread_context(arch_clone_exit,
- (void *)((char *)thread->stack_addr + thread->stack_size),
- user_stack, &thread->sp);
- /* new thread never reach there */
- rt_thread_startup(thread);
- return (long)tid;
- fail:
- err = GET_ERRNO();
- RT_ASSERT(err < 0);
- lwp_tid_put(tid);
- if (thread)
- {
- rt_thread_delete(thread);
- }
- if (lwp)
- {
- lwp_ref_dec(lwp);
- }
- return (long)err;
- }
- /**
- * @brief Creates a new process or thread (clone).
- *
- * This system call creates a new process or thread by duplicating the calling process.
- * The new process/thread begins execution by calling the function specified in the
- * `arg[]` array, which typically contains the necessary arguments or function pointer.
- * It is used to implement process/thread creation in the system and is often a lower-level
- * operation in process management.
- *
- * @param[in] arg An array of arguments passed to the new process or thread. This could
- * include function pointers, structures, or any necessary data the
- * new process/thread will need to execute its work.
- *
- * @return long Returns a status code or the process/thread ID of the newly created
- * process/thread. On success, it may return a positive value (such as a
- * thread ID). On failure, a negative value indicating the error is returned.
- *
- * @warning Be cautious when using this function as improper management of process/thread
- * creation can lead to resource exhaustion, deadlocks, or other synchronization issues.
- */
- rt_weak long sys_clone(void *arg[])
- {
- return _sys_clone(arg);
- }
- static void lwp_struct_copy(struct rt_lwp *dst, struct rt_lwp *src)
- {
- #ifdef ARCH_MM_MMU
- dst->end_heap = src->end_heap;
- #endif
- dst->lwp_type = src->lwp_type;
- dst->text_entry = src->text_entry;
- dst->text_size = src->text_size;
- dst->data_entry = src->data_entry;
- dst->data_size = src->data_size;
- dst->args = src->args;
- dst->background = src->background;
- dst->tty = src->tty;
- /* terminal API */
- dst->term_ctrlterm = src->term_ctrlterm;
- rt_memcpy(dst->cmd, src->cmd, RT_NAME_MAX);
- if (src->exe_file)
- {
- if (dst->exe_file)
- {
- rt_free(dst->exe_file);
- }
- dst->exe_file = strndup(src->exe_file, DFS_PATH_MAX);
- }
- rt_memcpy(&dst->signal.sig_action, &src->signal.sig_action, sizeof(dst->signal.sig_action));
- rt_memcpy(&dst->signal.sig_action_mask, &src->signal.sig_action_mask, sizeof(dst->signal.sig_action_mask));
- rt_memcpy(&dst->signal.sig_action_nodefer, &src->signal.sig_action_nodefer, sizeof(dst->signal.sig_action_nodefer));
- rt_memcpy(&dst->signal.sig_action_onstack, &src->signal.sig_action_onstack, sizeof(dst->signal.sig_action_onstack));
- rt_memcpy(&dst->signal.sig_action_restart, &dst->signal.sig_action_restart, sizeof(dst->signal.sig_action_restart));
- rt_memcpy(&dst->signal.sig_action_siginfo, &dst->signal.sig_action_siginfo, sizeof(dst->signal.sig_action_siginfo));
- rt_memcpy(&dst->signal.sig_action_nocldstop, &dst->signal.sig_action_nocldstop, sizeof(dst->signal.sig_action_nocldstop));
- rt_memcpy(&dst->signal.sig_action_nocldwait, &dst->signal.sig_action_nocldwait, sizeof(dst->signal.sig_action_nocldwait));
- rt_strcpy(dst->working_directory, src->working_directory);
- }
- static int lwp_copy_files(struct rt_lwp *dst, struct rt_lwp *src)
- {
- struct dfs_fdtable *dst_fdt;
- struct dfs_fdtable *src_fdt;
- src_fdt = &src->fdt;
- dst_fdt = &dst->fdt;
- /* init fds */
- dst_fdt->fds = rt_calloc(src_fdt->maxfd, sizeof(void *));
- if (dst_fdt->fds)
- {
- struct dfs_file *d_s;
- int i;
- dst_fdt->maxfd = src_fdt->maxfd;
- dfs_file_lock();
- /* dup files */
- for (i = 0; i < src_fdt->maxfd; i++)
- {
- d_s = fdt_get_file(src_fdt, i);
- if (d_s)
- {
- dst_fdt->fds[i] = d_s;
- d_s->ref_count++;
- }
- }
- dfs_file_unlock();
- return 0;
- }
- return -RT_ERROR;
- }
- sysret_t _sys_fork(void)
- {
- int tid = 0;
- sysret_t falival = 0;
- struct rt_lwp *lwp = RT_NULL;
- struct rt_lwp *self_lwp = RT_NULL;
- rt_thread_t thread = RT_NULL;
- rt_thread_t self_thread = RT_NULL;
- void *user_stack = RT_NULL;
- rt_processgroup_t group;
- /* new lwp */
- lwp = lwp_create(LWP_CREATE_FLAG_ALLOC_PID);
- if (!lwp)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- /* new tid */
- if ((tid = lwp_tid_get()) == 0)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- /* user space init */
- if (lwp_user_space_init(lwp, 1) != 0)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- self_lwp = lwp_self();
- /* copy address space of process from this proc to forked one */
- if (lwp_fork_aspace(lwp, self_lwp) != 0)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- /* copy lwp struct data */
- lwp_struct_copy(lwp, self_lwp);
- /* copy files */
- if (lwp_copy_files(lwp, self_lwp) != 0)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- /* create thread */
- self_thread = rt_thread_self();
- thread = rt_thread_create(self_thread->parent.name,
- RT_NULL,
- RT_NULL,
- self_thread->stack_size,
- RT_SCHED_PRIV(self_thread).init_priority,
- RT_SCHED_PRIV(self_thread).init_tick);
- if (!thread)
- {
- SET_ERRNO(ENOMEM);
- goto fail;
- }
- thread->cleanup = self_thread->cleanup;
- thread->user_entry = self_thread->user_entry;
- thread->user_stack = self_thread->user_stack;
- thread->user_stack_size = self_thread->user_stack_size;
- thread->signal.sigset_mask = self_thread->signal.sigset_mask;
- thread->thread_idr = self_thread->thread_idr;
- thread->clear_child_tid = self_thread->clear_child_tid;
- thread->lwp = (void *)lwp;
- thread->tid = tid;
- LWP_LOCK(self_lwp);
- /* add thread to lwp process */
- rt_list_insert_after(&lwp->t_grp, &thread->sibling);
- LWP_UNLOCK(self_lwp);
- lwp_children_register(self_lwp, lwp);
- /* set pgid and sid */
- group = lwp_pgrp_find(lwp_pgid_get_byprocess(self_lwp));
- if (group)
- {
- lwp_pgrp_insert(group, lwp);
- }
- else
- {
- LOG_W("the process group of pid: %d cannot be found", lwp_pgid_get_byprocess(self_lwp));
- }
- /* copy kernel stack context from self thread */
- lwp_memcpy(thread->stack_addr, self_thread->stack_addr, self_thread->stack_size);
- lwp_tid_set_thread(tid, thread);
- /* duplicate user objects */
- lwp_user_object_dup(lwp, self_lwp);
- user_stack = arch_get_user_sp();
- arch_set_thread_context(arch_fork_exit,
- (void *)((char *)thread->stack_addr + thread->stack_size),
- user_stack, &thread->sp);
- rt_thread_startup(thread);
- return lwp_to_pid(lwp);
- fail:
- falival = GET_ERRNO();
- if (tid != 0)
- {
- lwp_tid_put(tid);
- }
- if (thread)
- {
- rt_thread_delete(thread);
- }
- if (lwp)
- {
- lwp_ref_dec(lwp);
- }
- return falival;
- }
- /* arm needs to wrap fork/clone call to preserved lr & caller saved regs */
- /**
- * @brief Creates a child process by duplicating the calling process.
- *
- * This system call creates a new child process by duplicating the calling process. The
- * new child process is a copy of the parent process, except for the returned value.
- * The child process starts executing from the point of the fork, but the return value
- * differs between the parent and child: the parent receives the process ID (PID) of the
- * child, and the child receives a return value of 0.
- *
- * @return sysret_t Returns a status code indicating the result of the operation:
- * - A positive value (the child's PID) is returned to the parent.
- * - A value of 0 is returned to the child process.
- * - A negative value indicates an error (e.g., resource limits exceeded).
- *
- * @note This function is commonly used in operating systems to create new processes.
- *
- * @warning Be aware that improper management of child processes (such as failing to handle
- * process termination or excessive forking) can lead to resource exhaustion or
- * other system issues. Ensure proper process handling in the parent and child
- * processes to avoid leaks and inconsistencies.
- */
- rt_weak sysret_t sys_fork(void)
- {
- return _sys_fork();
- }
- rt_weak sysret_t sys_vfork(void)
- {
- return sys_fork();
- }
- #define _swap_lwp_data(lwp_used, lwp_new, type, member) \
- do {\
- type tmp;\
- tmp = lwp_used->member;\
- lwp_used->member = lwp_new->member;\
- lwp_new->member = tmp;\
- } while (0)
- /**
- * @brief Executes a program in the current process.
- *
- * This system call replaces the current process image with a new program specified by the
- * `path` argument. It loads the program located at the given `path` and passes the arguments
- * (`argv`) and environment variables (`envp`) to it. This effectively replaces the calling
- * process with a new one, and if successful, it never returns. If there is an error, the current
- * process continues to execute, and an error code is returned.
- *
- * @param[in] path The path to the executable file to be executed. This should be an
- * absolute or relative file path to the program.
- * @param[in] argv An array of arguments to pass to the new program. The first element
- * (`argv[0]`) should typically be the name of the program, and the array
- * should be terminated with a `NULL` pointer.
- * @param[in] envp An array of environment variables to pass to the new program. This is
- * typically in the form of `key=value` strings, with the array terminated
- * by a `NULL` pointer.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The program was successfully executed (this value is
- * never returned since the process is replaced).
- * - Other error codes may indicate issues with the program execution
- *
- * @note If `execve` is successful, it does not return to the calling function. The process
- * image is replaced by the new program.
- */
- sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
- {
- rt_err_t error = -1;
- size_t len;
- struct rt_lwp *new_lwp = NULL;
- struct rt_lwp *lwp;
- int uni_thread;
- rt_thread_t thread;
- struct process_aux *aux;
- struct lwp_args_info args_info;
- char *kpath = RT_NULL;
- lwp = lwp_self();
- thread = rt_thread_self();
- uni_thread = 1;
- LWP_LOCK(lwp);
- if (lwp->t_grp.prev != &thread->sibling)
- {
- uni_thread = 0;
- }
- if (lwp->t_grp.next != &thread->sibling)
- {
- uni_thread = 0;
- }
- LWP_UNLOCK(lwp);
- if (!uni_thread)
- {
- return -EINVAL;
- }
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kpath = rt_malloc(len + 1);
- if (!kpath)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kpath, (void *)path, len) != len)
- {
- rt_free(kpath);
- return -EFAULT;
- }
- kpath[len] = '\0';
- if (access(kpath, X_OK) != 0)
- {
- error = rt_get_errno();
- rt_free(kpath);
- return (sysret_t)error;
- }
- /* setup args */
- error = lwp_args_init(&args_info);
- if (error)
- {
- rt_free(kpath);
- return -ENOMEM;
- }
- if (argv)
- {
- error = lwp_args_put_argv(&args_info, (void *)argv);
- if (error)
- {
- error = -EFAULT;
- goto quit;
- }
- }
- if (envp)
- {
- error = lwp_args_put_envp(&args_info, (void *)envp);
- if (error)
- {
- error = -EFAULT;
- goto quit;
- }
- }
- /* alloc new lwp to operation */
- new_lwp = lwp_create(LWP_CREATE_FLAG_NONE);
- if (!new_lwp)
- {
- error = -ENOMEM;
- goto quit;
- }
- error = lwp_user_space_init(new_lwp, 0);
- if (error != 0)
- {
- error = -ENOMEM;
- goto quit;
- }
- /* file is a script ? */
- path = kpath;
- while (1)
- {
- error = lwp_args_load_script(&args_info, path);
- if (error != 0)
- {
- break;
- }
- path = lwp_args_get_argv_0(&args_info);
- }
- /* now load elf */
- if ((aux = lwp_argscopy(new_lwp, &args_info)) == NULL)
- {
- error = -ENOMEM;
- goto quit;
- }
- error = lwp_load(path, new_lwp, RT_NULL, 0, aux);
- if (error == RT_EOK)
- {
- int off = 0;
- int last_backslash = 0;
- /* clear all user objects */
- lwp_user_object_clear(lwp);
- /* find last \ or / to get base name */
- while (1)
- {
- char c = path[off++];
- if (c == '\0')
- {
- break;
- }
- if (c == '\\' || c == '/')
- {
- last_backslash = off;
- }
- }
- /**
- * Set thread name and swap the data of lwp and new_lwp.
- * Since no other threads can access the lwp field, it't uneccessary to
- * take a lock here
- */
- RT_ASSERT(rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling) == thread);
- strncpy(thread->parent.name, path + last_backslash, RT_NAME_MAX - 1);
- strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX);
- rt_free(lwp->exe_file);
- lwp->exe_file = strndup(new_lwp->exe_file, DFS_PATH_MAX);
- #ifdef ARCH_MM_MMU
- _swap_lwp_data(lwp, new_lwp, struct rt_aspace *, aspace);
- _swap_lwp_data(lwp, new_lwp, size_t, end_heap);
- #endif
- _swap_lwp_data(lwp, new_lwp, uint8_t, lwp_type);
- _swap_lwp_data(lwp, new_lwp, void *, text_entry);
- _swap_lwp_data(lwp, new_lwp, uint32_t, text_size);
- _swap_lwp_data(lwp, new_lwp, void *, data_entry);
- _swap_lwp_data(lwp, new_lwp, uint32_t, data_size);
- _swap_lwp_data(lwp, new_lwp, void *, args);
- lwp_thread_signal_detach(&thread->signal);
- rt_memset(&thread->signal.sigset_mask, 0, sizeof(thread->signal.sigset_mask));
- lwp_signal_detach(&lwp->signal);
- lwp_signal_init(&lwp->signal);
- /* to do: clsoe files with flag CLOEXEC, recy sub-thread */
- lwp_aspace_switch(thread);
- lwp_ref_dec(new_lwp);
- arch_start_umode(lwp->args,
- lwp->text_entry,
- (void*)USER_STACK_VEND,
- (char *)thread->stack_addr + thread->stack_size);
- /* never reach here */
- }
- error = -EINVAL;
- quit:
- if (kpath)
- {
- rt_free(kpath);
- }
- lwp_args_detach(&args_info);
- if (new_lwp)
- {
- lwp_ref_dec(new_lwp);
- }
- return error;
- }
- #endif /* ARCH_MM_MMU */
- /**
- * @brief Deletes a thread.
- *
- * This system call is used to delete an existing thread. The specified thread is terminated,
- * and its resources are released. If the thread is currently running, it will be forcefully
- * terminated. The thread identifier (`thread`) refers to the thread that is to be deleted.
- *
- * @param[in] thread The identifier of the thread to be deleted.
- *
- * @return sysret_t Returns a status code:
- * - `SYSRET_OK`: The thread was successfully deleted.
- * - Other error codes may indicate additional failures.
- *
- * @note This function should be used carefully, as forcefully terminating a thread may
- * lead to resource leaks or inconsistent state if the thread is performing critical
- * operations at the time of termination.
- *
- * @warning Ensure that the thread being deleted has completed its necessary operations
- * and that there are no outstanding resources or critical tasks before deleting
- * it. Otherwise, it might lead to undefined behavior or resource leaks.
- */
- sysret_t sys_thread_delete(rt_thread_t thread)
- {
- #ifdef ARCH_MM_MMU
- return rt_thread_delete(thread);
- #else
- sysret_t ret = 0;
- if(thread->parent.type != RT_Object_Class_Thread)
- {
- ret = -EINVAL;
- goto __exit;
- }
- ret = rt_thread_delete(thread);
- if (rt_thread_self() == thread)
- {
- rt_schedule();
- }
- __exit:
- return ret;
- #endif
- }
- /**
- * @brief Starts a previously created thread.
- *
- * This system call is used to start a thread that was created but has not yet started running.
- * It initiates the thread's execution, allowing it to begin performing its assigned task.
- * The `thread` parameter refers to the thread that is to be started.
- *
- * @param[in] thread The identifier of the thread to be started.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The thread was successfully started.
- * - Other error codes may indicate additional failures.
- *
- * @warning Ensure that the thread has been correctly initialized and is in a valid state
- * before calling this function to avoid undefined behavior. Improper initialization
- * could lead to issues such as the thread not running as expected.
- */
- sysret_t sys_thread_startup(rt_thread_t thread)
- {
- return rt_thread_startup(thread);
- }
- /**
- * @brief Retrieves the identifier of the current thread.
- *
- * This system call returns the thread identifier of the currently executing thread. It allows
- * a thread to obtain its own identifier, which can be useful for various thread management
- * tasks such as self-identification, logging, or checking the thread's status.
- *
- * @return rt_thread_t The identifier of the current thread.
- * If no thread is currently executing, a null or invalid thread ID
- * might be returned depending on the system's implementation.
- *
- * @note This function is typically used when a thread needs to identify itself, especially
- * in cases where thread management is performed dynamically or the thread identifier
- * is required for synchronization or debugging purposes.
- *
- * @warning Be aware that in environments where there is no concept of threads or if the
- * current context is not a thread (e.g., during interrupt handling or early system
- * initialization), the return value might be invalid.
- */
- rt_thread_t sys_thread_self(void)
- {
- return rt_thread_self();
- }
- /* sys channel */
- /**
- * @brief Opens a communication channel.
- *
- * This system call is used to open a communication channel with a specified name and set of flags.
- * The channel allows for inter-process or inter-thread communication, depending on the underlying system.
- * The `name` parameter specifies the name of the channel, while the `flags` parameter allows
- * configuration of the channel's behavior (e.g., read/write permissions, blocking or non-blocking mode).
- *
- * @param[in] name The name of the communication channel to be opened.
- * @param[in] flags The flags to configure the behavior of the channel. These flags may
- * define various properties such as access mode (e.g., read-only, write-only)
- * or synchronization mode (e.g., blocking, non-blocking).
- *
- * @return sysret_t Returns a status code:
- * - `0`: The channel was successfully opened.
- * - Other error codes may indicate issues with the channel opening process.
- *
- * @warning Ensure that the correct flags are passed to configure the channel as required,
- * as improper configuration might lead to access issues, data loss, or undefined behavior.
- */
- sysret_t sys_channel_open(const char *name, int flags)
- {
- rt_size_t ret = 0;
- char *kname = RT_NULL;
- int len = 0;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return -EFAULT;
- }
- ret = lwp_channel_open(FDT_TYPE_LWP, kname, flags);
- kmem_put(kname);
- return ret;
- }
- /**
- * @brief Closes an open communication channel.
- *
- * This system call is used to close an already open communication channel specified by the file descriptor `fd`.
- * After closing, the channel can no longer be used for communication, and any resources associated with
- * the channel will be released. This function is necessary for proper resource management, ensuring that
- * system resources (e.g., memory or file handles) are freed when no longer needed.
- *
- * @param[in] fd The file descriptor of the communication channel to be closed.
- *
- * @return sysret_t Returns a status code:
- * - `SYSRET_OK`: The channel was successfully closed.
- * - Other error codes may indicate issues with the channel closing process.
- *
- * @note This function should be called after communication is finished and the channel is no longer
- * needed, to release any system resources associated with it.
- *
- * @warning Calling this function on an invalid or already closed file descriptor may lead to
- * undefined behavior or errors. Ensure that the file descriptor is valid and that the
- * channel is not already closed before attempting to close it.
- */
- sysret_t sys_channel_close(int fd)
- {
- return lwp_channel_close(FDT_TYPE_LWP, fd);
- }
- /**
- * @brief Sends a message through a communication channel.
- *
- * This system call is used to send a message through a specified communication channel identified
- * by the file descriptor `fd`. The message to be sent is provided in the `data` parameter.
- * It allows inter-process or inter-thread communication by transmitting the given message over
- * the open channel.
- *
- * @param[in] fd The file descriptor of the communication channel to send the message to.
- * @param[in] data The message data to be sent. This parameter is typically a structure
- * containing the message content and metadata.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The message was successfully sent.
- * - Other error codes may indicate issues with the message sending process.
- *
- * @note Ensure the channel is open and properly configured for sending messages before
- * calling this function. Additionally, confirm that the `data` structure is valid and
- * initialized with the appropriate content.
- *
- * @warning Failure to verify the channel's readiness or the validity of the data may lead
- * to errors, data loss, or undefined behavior.
- */
- sysret_t sys_channel_send(int fd, rt_channel_msg_t data)
- {
- rt_size_t ret = 0;
- rt_channel_msg_t kdata = RT_NULL;
- if (!lwp_user_accessable((void *)data, sizeof(*data)))
- {
- return -EFAULT;
- }
- kdata = kmem_get(sizeof(*data));
- if (kdata == RT_NULL)
- return -ENOMEM;
- if (lwp_get_from_user(kdata, data, sizeof(*kdata)) != sizeof(*kdata))
- {
- kmem_put(kdata);
- return -EFAULT;
- }
- ret = lwp_channel_send(FDT_TYPE_LWP, fd, kdata);
- kmem_put(kdata);
- return ret;
- }
- /**
- * @brief Sends a message through a communication channel and waits for a response with a timeout.
- *
- * This system call sends a message (`data`) through a specified communication channel identified by the file descriptor `fd`.
- * It then waits for a response (`data_ret`) within the specified timeout period. This is a synchronous operation
- * commonly used in request-response communication patterns between processes or threads.
- *
- * @param[in] fd The file descriptor of the communication channel to send the message to.
- * @param[in] data The message data to be sent. This is typically a structure containing
- * the message content and metadata.
- * @param[out] data_ret The buffer to store the response message received from the channel.
- * @param[in] time The timeout period (in milliseconds) to wait for the response.
- * If set to a negative value, the function will wait indefinitely.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The message was successfully sent, and a response was received.
- * - Other error codes may indicate issues with the communication process.
- *
- * @note This function combines sending and receiving operations into a single atomic action.
- * It is useful for scenarios requiring synchronous communication with a defined timeout
- * to handle cases where a response may not be immediately available.
- *
- * @warning Ensure that the channel is open and properly configured for bidirectional communication.
- * Verify that the `data` structure is valid and initialized, and the `data_ret` buffer is large
- * enough to store the expected response to avoid memory issues or data corruption.
- */
- sysret_t sys_channel_send_recv_timeout(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time)
- {
- rt_size_t ret = 0;
- rt_channel_msg_t kdata = RT_NULL;
- rt_channel_msg_t kdata_ret = RT_NULL;
- if (!lwp_user_accessable((void *)data, sizeof(*data)))
- {
- return -EFAULT;
- }
- kdata = kmem_get(sizeof(*data));
- if (kdata == RT_NULL)
- return -ENOMEM;
- if (lwp_get_from_user(kdata, data, sizeof(*kdata)) != sizeof(*kdata))
- {
- kmem_put(kdata);
- return -EFAULT;
- }
- kdata_ret = kmem_get(sizeof(*data_ret));
- if (kdata_ret == RT_NULL)
- return -ENOMEM;
- ret = lwp_channel_send_recv_timeout(FDT_TYPE_LWP, fd, kdata, kdata_ret, time);
- lwp_put_to_user(data_ret, kdata_ret, sizeof(*kdata_ret));
- kmem_put(kdata);
- kmem_put(kdata_ret);
- return ret;
- }
- /**
- * @brief Sends a reply message through a communication channel.
- *
- * This system call is used to send a reply (`data`) through a communication channel identified
- * by the file descriptor `fd`. It is typically called in response to a received request
- * within a request-response communication pattern. The reply is sent to the requesting entity
- * through the same channel.
- *
- * @param[in] fd The file descriptor of the communication channel to send the reply to.
- * @param[in] data The reply message to be sent. This is typically a structure containing
- * the reply content and metadata.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The reply was successfully sent.
- * - Other error codes may indicate issues with the reply sending process.
- *
- * @note This function is usually called in a server or responder context, where a request
- * is received, processed, and the result is sent back to the requester. Ensure that
- * the channel is open and configured to send replies before calling this function.
- *
- * @warning Ensure the `data` structure is valid and properly initialized before sending.
- * Sending invalid or corrupted data may lead to unexpected behavior or communication failures.
- */
- sysret_t sys_channel_reply(int fd, rt_channel_msg_t data)
- {
- rt_size_t ret = 0;
- rt_channel_msg_t kdata = RT_NULL;
- if (!lwp_user_accessable((void *)data, sizeof(*data)))
- {
- return -EFAULT;
- }
- kdata = kmem_get(sizeof(*data));
- if (kdata == RT_NULL)
- return -ENOMEM;
- if (lwp_get_from_user(kdata, data, sizeof(*kdata)) != sizeof(*data))
- {
- kmem_put(kdata);
- return -EFAULT;
- }
- ret = lwp_channel_reply(FDT_TYPE_LWP, fd, kdata);
- kmem_put(kdata);
- return ret;
- }
- /**
- * @brief Receives a message from a communication channel with a timeout.
- *
- * This system call attempts to receive a message from a specified communication channel identified
- * by the file descriptor `fd`. The received message is stored in the `data` buffer. If no message
- * is available within the specified timeout period, the function returns with a timeout status.
- *
- * @param[in] fd The file descriptor of the communication channel to receive the message from.
- * @param[out] data The buffer to store the received message. This parameter is typically a
- * structure containing the message content and metadata.
- * @param[in] time The timeout period (in milliseconds) to wait for a message.
- * A negative value indicates that the function will wait indefinitely.
- *
- * @return sysret_t Returns a status code:
- * - `0`: A message was successfully received.
- * - `-ETIMEDOUT`: The operation timed out before a message was received.
- * - Other error codes may indicate issues with the message receiving process.
- *
- * @note This function is useful in scenarios where blocking indefinitely is not desirable,
- * allowing the caller to specify a timeout for receiving messages. It is commonly
- * used in event-driven or time-sensitive communication systems.
- *
- * @warning Ensure that the channel is open and configured for receiving messages before calling
- * this function. The `data` buffer must be valid and large enough to store the expected
- * message to avoid memory corruption or data loss.
- */
- sysret_t sys_channel_recv_timeout(int fd, rt_channel_msg_t data, rt_int32_t time)
- {
- rt_size_t ret = 0;
- rt_channel_msg_t kdata = RT_NULL;
- kdata = kmem_get(sizeof(*data));
- if (kdata == RT_NULL)
- return -ENOMEM;
- ret = lwp_channel_recv_timeout(FDT_TYPE_LWP, fd, kdata, time);
- lwp_put_to_user(data, kdata, sizeof(*kdata));
- kmem_put(kdata);
- return ret;
- }
- static struct rt_semaphore critical_lock;
- static int critical_init(void)
- {
- rt_sem_init(&critical_lock, "ct_lock", 1, RT_IPC_FLAG_FIFO);
- return 0;
- }
- INIT_DEVICE_EXPORT(critical_init);
- /**
- * @brief Enters a critical section to prevent context switching or interrupts.
- *
- * @note Critical sections are typically used to protect shared resources or perform
- * non-interruptible operations. Ensure to exit the critical section as soon as
- * possible by calling `sys_exit_critical` to avoid system performance degradation
- * or deadlocks.
- *
- * @warning Failure to exit a critical section (e.g., due to an exception or missing
- * `sys_exit_critical` call) may lead to system instability or a complete halt.
- */
- void sys_enter_critical(void)
- {
- rt_sem_take(&critical_lock, RT_WAITING_FOREVER);
- }
- /**
- * @brief Exits a critical section and restores the system's previous state.
- *
- * @note Exiting the critical section as soon as the protected operation is completed
- * is essential to avoid performance degradation or system deadlocks. Ensure
- * that every call to `sys_enter_critical` is matched with a corresponding
- * `sys_exit_critical` call.
- *
- * @warning Calling this function without a prior `sys_enter_critical` may result
- * in undefined behavior or system instability. Use carefully in nested
- * critical sections and ensure proper tracking of critical section depth
- * if required.
- */
- void sys_exit_critical(void)
- {
- rt_sem_release(&critical_lock);
- }
- /* syscall: "sys_log" ret: "int" args: "const char*" "size" */
- static int __sys_log_enable = 0;
- static int sys_log_enable(int argc, char** argv)
- {
- if (argc == 1)
- {
- rt_kprintf("sys_log = %d\n", __sys_log_enable);
- return 0;
- }
- else
- {
- __sys_log_enable = atoi(argv[1]);
- }
- return 0;
- }
- MSH_CMD_EXPORT_ALIAS(sys_log_enable, sys_log, sys_log 1(enable)/0(disable));
- /**
- * @brief Logs a message to the system logging mechanism.
- *
- * This system call writes a log message to the system log for diagnostic or informational purposes.
- * The message is specified by the `log` parameter, and its size is given by the `size` parameter.
- * The logging mechanism is typically used for tracking system events, debugging, or reporting errors.
- *
- * @param[in] log A pointer to the message to be logged. The message should be a valid character
- * array or string.
- * @param[in] size The size of the log message in bytes. This specifies the number of bytes to write
- * from the `log` buffer.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The log message was successfully written.
- * - Other error codes may indicate issues with the logging process.
- *
- * @note Ensure that the `log` pointer is valid and points to a properly initialized memory buffer.
- * Truncation may occur if the logging system has a size limitation. Logging should not be used
- * in performance-critical paths as it may introduce latency.
- *
- * @warning Passing a `NULL` pointer or an invalid `size` may lead to undefined behavior. Ensure the
- * logging system is properly initialized before invoking this function.
- */
- sysret_t sys_log(const char* log, int size)
- {
- char *klog = RT_NULL;
- rt_device_t console = RT_NULL;
- if (!lwp_user_accessable((void *)log, size))
- return -EFAULT;
- klog = kmem_get(size);
- if (klog == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user((void *)klog, (void *)log, size) != size)
- {
- kmem_put(klog);
- return -EINVAL;
- }
- console = rt_console_get_device();
- if (console && __sys_log_enable)
- {
- rt_device_write(console, -1, klog, size);
- }
- kmem_put(klog);
- return 0;
- }
- /**
- * @brief Retrieves information about a file or directory.
- *
- * This system call obtains metadata about the specified file or directory and stores it in
- * the `buf` structure. The metadata includes attributes such as file size, permissions,
- * ownership, and timestamps.
- *
- * @param[in] file A pointer to the path of the file or directory to be queried.
- * The path should be a null-terminated string.
- * @param[out] buf A pointer to a `struct stat` structure where the file's metadata
- * will be stored. This structure must be allocated by the caller.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The operation completed successfully, and the metadata
- * has been written to `buf`.
- * - Other error codes may indicate issues with the file path.
- *
- * @note The `file` path must be valid and accessible by the calling process. Ensure that
- * the `buf` pointer points to a properly allocated memory region.
- *
- * @warning Passing a `NULL` pointer for `file` or `buf` may result in undefined behavior.
- * Check all inputs before invoking this function to avoid potential issues.
- */
- sysret_t sys_stat(const char *file, struct stat *buf)
- {
- int ret = 0;
- size_t len;
- size_t copy_len;
- char *copy_path;
- struct stat statbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct stat)))
- {
- return -EFAULT;
- }
- len = lwp_user_strlen(file);
- if (len <= 0)
- {
- return -EFAULT;
- }
- copy_path = (char*)rt_malloc(len + 1);
- if (!copy_path)
- {
- return -ENOMEM;
- }
- copy_len = lwp_get_from_user(copy_path, (void*)file, len);
- if (copy_len == 0)
- {
- rt_free(copy_path);
- return -EFAULT;
- }
- copy_path[copy_len] = '\0';
- ret = _SYS_WRAP(stat(copy_path, &statbuff));
- rt_free(copy_path);
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statbuff, sizeof statbuff);
- }
- return ret;
- }
- /**
- * @brief Retrieves metadata about a file or symbolic link.
- *
- * This system call obtains metadata for the specified file or symbolic link and stores
- * it in the `buf` structure. Unlike `sys_stat`, if the specified path refers to a
- * symbolic link, this function retrieves information about the link itself, not the
- * target it points to.
- *
- * @param[in] file A pointer to the path of the file or symbolic link to be queried.
- * The path must be a null-terminated string.
- * @param[out] buf A pointer to a `struct stat` structure where the metadata will be
- * stored. This structure must be allocated by the caller.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The operation completed successfully, and the metadata
- * has been written to `buf`.
- * - Other error codes may indicate issues with the file path.
- *
- * @note This function is particularly useful for handling symbolic links when you want
- * to get information about the link itself rather than the target file or directory.
- * The `file` path must be valid and accessible by the calling process.
- *
- * @warning Passing a `NULL` pointer for `file` or `buf` may result in undefined behavior.
- * Always check inputs for validity before invoking this function.
- */
- sysret_t sys_lstat(const char *file, struct stat *buf)
- {
- int ret = 0;
- size_t len;
- size_t copy_len;
- char *copy_path;
- struct stat statbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct stat)))
- {
- return -EFAULT;
- }
- len = lwp_user_strlen(file);
- if (len <= 0)
- {
- return -EFAULT;
- }
- copy_path = (char*)rt_malloc(len + 1);
- if (!copy_path)
- {
- return -ENOMEM;
- }
- copy_len = lwp_get_from_user(copy_path, (void*)file, len);
- if (copy_len == 0)
- {
- rt_free(copy_path);
- return -EFAULT;
- }
- copy_path[copy_len] = '\0';
- #ifdef RT_USING_DFS_V2
- ret = _SYS_WRAP(dfs_file_lstat(copy_path, &statbuff));
- #else
- ret = _SYS_WRAP(stat(copy_path, &statbuff));
- #endif
- rt_free(copy_path);
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statbuff, sizeof statbuff);
- }
- return ret;
- }
- sysret_t sys_notimpl(void)
- {
- return -ENOSYS;
- }
- uint32_t sys_hw_interrupt_disable(void)
- {
- return rt_hw_interrupt_disable();
- }
- void sys_hw_interrupt_enable(uint32_t level)
- {
- rt_hw_interrupt_enable(level);
- }
- #ifdef ARCH_MM_MMU
- /**
- * @brief Allocates or retrieves a shared memory segment.
- *
- * This system call allocates a new shared memory segment or retrieves an existing one
- * based on the specified `key`. Shared memory allows processes to communicate by
- * sharing a region of memory.
- *
- * @param[in] key A unique identifier for the shared memory segment. If `key` matches
- * an existing segment, it will be retrieved. If `create` is set and the
- * segment does not exist, a new one will be created.
- * @param[in] size The size (in bytes) of the shared memory segment. If creating a new
- * segment, this specifies its size. If retrieving an existing segment,
- * `size` is ignored.
- * @param[in] create A flag indicating whether to create the segment if it does not exist:
- * - `1`: Create the shared memory segment if it does not exist.
- * - `0`: Only retrieve an existing segment.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The shared memory segment was successfully created or
- * retrieved.
- * - Other error codes may indicate issues with the shared memory
- *
- * @note Shared memory segments identified by the same `key` are accessible across
- * processes. Ensure proper synchronization mechanisms (e.g., semaphores) are in
- * place to manage access to the shared memory.
- *
- * @warning Using a `NULL` or invalid `key` may result in undefined behavior. When creating
- * a new segment, ensure that `size` is non-zero and meaningful.
- */
- sysret_t sys_shmget(size_t key, size_t size, int create)
- {
- return lwp_shmget(key, size, create);
- }
- /**
- * @brief Removes a shared memory segment.
- *
- * This system call removes the specified shared memory segment identified by its `id`.
- * Once removed, the segment will no longer be accessible, and any memory associated
- * with it will be freed. It is typically used to clean up shared memory resources
- * when they are no longer needed.
- *
- * @param[in] id The identifier of the shared memory segment to be removed. This identifier
- * was obtained when the segment was created or retrieved using `sys_shmget`.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The shared memory segment was successfully removed.
- * - Other error codes may indicate issues with the shared memory removal.
- *
- * @note This function should be called only when all processes that were using the shared
- * memory segment have finished accessing it. Removing the segment while it is in use
- * by another process may result in undefined behavior or memory corruption.
- *
- * @warning Ensure that the shared memory segment is no longer needed by any process before
- * calling this function to avoid premature removal and potential data loss.
- */
- sysret_t sys_shmrm(int id)
- {
- return lwp_shmrm(id);
- }
- /**
- * @brief Attaches a shared memory segment to the calling process's address space.
- *
- * This system call maps a shared memory segment identified by `id` into the calling
- * process's address space. The segment can then be accessed using the returned virtual
- * address. If the segment was previously detached or created, it will be made available
- * for reading and writing.
- *
- * @param[in] id The identifier of the shared memory segment to be attached.
- * This identifier was obtained when the segment was created
- * or retrieved using `sys_shmget`.
- * @param[in] shm_vaddr A pointer to the desired virtual address where the shared
- * memory segment should be mapped. If `NULL`, the system will
- * choose an appropriate address.
- *
- * @return void* Returns the virtual address where the shared memory segment
- * is mapped. On success, this will be the address in the
- * calling process's address space. If the attachment fails,
- * `NULL` is returned.
- *
- * @note Once the shared memory segment is attached, it can be accessed like any
- * regular memory, but it should be used with caution, especially in multi-process
- * environments. Ensure that proper synchronization mechanisms (e.g., semaphores)
- * are used to manage concurrent access.
- *
- * @warning Ensure that the shared memory segment is properly allocated and not in use
- * by other processes before attaching it. Passing invalid `id` or an inaccessible
- * segment may result in undefined behavior.
- */
- void* sys_shmat(int id, void* shm_vaddr)
- {
- return lwp_shmat(id, shm_vaddr);
- }
- /**
- * @brief Detaches a shared memory segment from the calling process's address space.
- *
- * This system call detaches the shared memory segment previously attached to the calling
- * process's address space using `sys_shmat`. After calling this function, the shared
- * memory will no longer be accessible via the returned address.
- *
- * @param[in] shm_vaddr A pointer to the virtual address where the shared memory
- * segment was previously mapped. This address was returned
- * by the `sys_shmat` function.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The shared memory segment was successfully detached.
- * - Other error codes may indicate issues with the detachment process.
- *
- * @note It is important to ensure that no processes are using the shared memory segment
- * before detaching it. Detaching the segment while it is still being accessed
- * may lead to undefined behavior.
- *
- * @warning Ensure that `shm_vaddr` corresponds to a valid attached address returned
- * by `sys_shmat`. Passing an incorrect or uninitialized address may result
- * in undefined behavior.
- */
- sysret_t sys_shmdt(void* shm_vaddr)
- {
- return lwp_shmdt(shm_vaddr);
- }
- #elif defined RT_LWP_USING_SHM
- /**
- * @brief Allocates a new shared memory segment.
- *
- * This system call allocates a new shared memory segment of the specified size and
- * returns a pointer to the allocated memory. The allocated segment can be used for
- * inter-process communication or shared memory access. The segment is typically
- * managed by the system, and it can be accessed by other processes with appropriate
- * synchronization.
- *
- * @param[in] size The size (in bytes) of the shared memory segment to be allocated.
- *
- * @return void* Returns a pointer to the allocated shared memory segment.
- * If the allocation fails, `RT_NULL` is returned.
- *
- * @note The allocated shared memory segment can be used like regular memory,
- * but it should be accessed with proper synchronization mechanisms (e.g.,
- * semaphores or mutexes) to avoid race conditions or data corruption in
- * multi-process environments.
- *
- * @warning Ensure that the `size` parameter is a valid, non-zero value, and that
- * there is enough system memory to allocate the requested size.
- * Failure to do so may result in errors or resource exhaustion.
- */
- void *sys_shm_alloc(int size)
- {
- if (size < 0)
- {
- return RT_NULL;
- }
- return lwp_shm_alloc((rt_size_t)size);
- }
- /**
- * @brief Retains an existing shared memory segment.
- *
- * This system call retains an existing shared memory segment that was previously
- * allocated or attached, ensuring it remains available for further use. It is
- * typically used to increment the reference count or to ensure the segment is
- * not removed or deallocated while it is still being used.
- *
- * @param[in] mem A pointer to the shared memory segment to retain. This should be
- * the address previously returned by a memory allocation or
- * attachment function such as `sys_shmat` or `sys_shm_alloc`.
- *
- * @return void* Returns the original pointer `mem` if the retention is successful.
- * If the operation fails, `NULL` is returned.
- *
- * @note This function does not affect the actual content of the shared memory segment,
- * but ensures the segment is not removed or deallocated while still in use.
- * It is generally used in conjunction with `sys_shmdt` or `sys_shmrm` to ensure
- * proper resource management.
- *
- * @warning Ensure that the provided pointer `mem` corresponds to a valid shared
- * memory segment that is currently allocated or attached. Passing an
- * invalid or uninitialized pointer may result in undefined behavior.
- */
- void *sys_shm_retain(void *mem)
- {
- if (!lwp_user_accessable(mem, sizeof (void *)))
- {
- return RT_NULL;
- }
- return lwp_shm_retain(mem);
- }
- /**
- * @brief Frees a previously allocated shared memory segment.
- *
- * This system call frees a shared memory segment that was previously allocated or
- * retained using functions like `sys_shm_alloc` or `sys_shm_retain`. It ensures
- * that the shared memory is properly deallocated, making it available for future
- * allocations or for removal from the system.
- *
- * @param[in] mem A pointer to the shared memory segment to be freed. This should be
- * the address returned by a memory allocation or retention function.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The shared memory segment was successfully freed.
- * - Other error codes may indicate issues with the memory deallocation.
- *
- * @note After calling this function, the memory will be deallocated, and any subsequent
- * access to the freed memory will result in undefined behavior. Ensure that no
- * processes are using the shared memory before calling this function.
- *
- * @warning Ensure that `mem` corresponds to a valid shared memory segment that was
- * previously allocated or retained. Passing an invalid or already freed
- * pointer may result in undefined behavior.
- */
- sysret_t sys_shm_free(void *mem)
- {
- if (!lwp_user_accessable(mem, sizeof (void *)))
- {
- return -EFAULT;
- }
- lwp_shm_free(mem);
- return 0;
- }
- #endif
- /* device interfaces */
- /**
- * @brief Initializes a device.
- *
- * This system call initializes the specified device, preparing it for use. Device initialization
- * typically involves setting up necessary hardware configurations, registering device drivers,
- * and ensuring that the device is in a ready state for further operations. This function should
- * be called before interacting with the device.
- *
- * @param[in] dev A pointer to the device structure that represents the device to be initialized.
- * This structure contains device-specific configuration and state information.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The device was successfully initialized.
- * - Other error codes may indicate issues with the device initialization process.
- *
- * @note This function is typically called once during system startup or when a device is
- * first accessed. It ensures that all necessary setup steps are completed before
- * the device can be used.
- *
- * @warning Ensure that the device passed to this function is valid and properly configured
- * before initialization. Initializing an invalid or improperly configured device
- * may result in unpredictable behavior.
- */
- sysret_t sys_device_init(rt_device_t dev)
- {
- return rt_device_init(dev);
- }
- /**
- * @brief Registers a device with the system.
- *
- * This system call registers a device with the system, making it available for interaction
- * by the operating system or other components. Registration typically involves associating
- * the device with a name and setting up the necessary flags for the device's behavior.
- *
- * @param[in] dev A pointer to the device structure that represents the device to be registered.
- * This structure contains the device's configuration, capabilities, and state.
- * @param[in] name A string representing the name by which the device will be identified in the system.
- * This name is used for device lookup and reference.
- * @param[in] flags A set of flags that configure the behavior of the device, such as enabling
- * or disabling certain features, or specifying the device's mode of operation.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The device was successfully registered.
- * - Other error codes may indicate issues with the device registration process.
- *
- * @note This function should be called after the device has been initialized (via `sys_device_init`)
- * and before the device is used by the system or other components.
- *
- * @warning Ensure that the `name` provided is unique and not already in use by another device in the system.
- * Passing invalid `dev` or `flags` may result in unexpected behavior or failure of device registration.
- */
- sysret_t sys_device_register(rt_device_t dev, const char *name, rt_uint16_t flags)
- {
- return rt_device_register(dev, name, flags);
- }
- /**
- * @brief Controls a device by sending a command.
- *
- * This system call sends a control command to the specified device, allowing the system or other
- * components to modify the device's behavior or state. The command is specified by the `cmd`
- * parameter, and the arguments for the command are passed via the `arg` parameter.
- *
- * @param[in] dev A pointer to the device structure representing the device to be controlled.
- * The device must have been previously registered and initialized.
- * @param[in] cmd The control command to be sent to the device. The meaning and behavior of the
- * command are device-specific and depend on the device type.
- * @param[in] arg A pointer to the arguments required by the command. The type and content of
- * the arguments are determined by the command. Some commands may not require
- * arguments, in which case `arg` can be `NULL`.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The command was successfully executed on the device.
- * - Other error codes may indicate issues with the command execution or device control.
- *
- * @note The set of available commands (`cmd`) and the expected argument types (`arg`) are specific
- * to each device. Refer to the device documentation for the supported commands and argument
- * formats.
- *
- * @warning Ensure that the `dev` pointer is valid and points to a correctly initialized device.
- * Providing an invalid device or incorrect command may result in undefined behavior.
- */
- sysret_t sys_device_control(rt_device_t dev, int cmd, void *arg)
- {
- return rt_device_control(dev, cmd, arg);
- }
- /**
- * @brief Finds a device by its name.
- *
- * This system call searches for a device that has been registered with the system using the
- * specified name. If the device exists, a pointer to the device structure is returned,
- * allowing further interaction with the device. If no device with the specified name is found,
- * a `NULL` pointer is returned.
- *
- * @param[in] name The name of the device to search for. This name must match the name used
- * during device registration (e.g., via `sys_device_register`).
- *
- * @return rt_device_t Returns a pointer to the device structure if the device is found.
- * Returns `NULL` if no device with the specified name exists.
- *
- * @note The device must have been previously registered with the system using `sys_device_register`.
- *
- * @warning Ensure that the provided `name` is a valid string and corresponds to a registered device.
- * Passing an invalid or non-registered name will result in `NULL` being returned.
- */
- rt_device_t sys_device_find(const char* name)
- {
- return rt_device_find(name);
- }
- /**
- * @brief Opens a device for use.
- *
- * This system call opens the specified device, making it ready for interaction with the system
- * or other components. The device must have been previously registered and initialized.
- * The `oflag` parameter specifies the open mode, which may determine how the device is accessed
- * (e.g., read, write, or exclusive access).
- *
- * @param[in] dev A pointer to the device structure representing the device to be opened.
- * The device must be registered and initialized before being opened.
- * @param[in] oflag The open flags that determine the mode of access to the device. These flags
- * may specify read, write, or other modes of operation, depending on the device's capabilities.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The device was successfully opened.
- * - Other error codes may indicate issues with the device opening process.
- *
- * @note The open flags (`oflag`) should be set according to the device's capabilities. For example,
- * some devices may support read or write operations, while others may only support one of them.
- * Check the device documentation for supported flags.
- *
- * @warning Ensure that the device pointer (`dev`) is valid and that the device has been initialized
- * properly. Incorrect flags or attempting to open a device that is already in use may result
- * in errors or undefined behavior.
- */
- sysret_t sys_device_open(rt_device_t dev, rt_uint16_t oflag)
- {
- return rt_device_open(dev, oflag);
- }
- /**
- * @brief Closes an open device.
- *
- * This system call closes an open device, releasing any resources or locks associated with it
- * and making it unavailable for further interaction until it is opened again. The device must
- * have been previously opened using `sys_device_open`. After calling this function, any further
- * attempts to interact with the device will result in an error unless the device is opened again.
- *
- * @param[in] dev A pointer to the device structure representing the device to be closed.
- * The device must be open before it can be closed.
- *
- * @return sysret_t Returns a status code:
- * - `0`: The device was successfully closed.
- * - Other error codes may indicate issues with the device closing process.
- *
- * @note This function should be called when the device is no longer needed or before shutting
- * down the system to release device resources properly.
- *
- * @warning Ensure that the device has been opened before calling this function. Calling this function
- * on an uninitialized or already closed device may result in undefined behavior or errors.
- */
- sysret_t sys_device_close(rt_device_t dev)
- {
- return rt_device_close(dev);
- }
- /**
- * @brief Reads data from an open device.
- *
- * This system call reads data from the specified device, starting at the given position and
- * storing the data in the provided buffer. The device must be open before this function can be called.
- * The amount of data to read is determined by the `size` parameter.
- *
- * @param[in] dev A pointer to the device structure representing the device to read from.
- * The device must be open and ready for reading.
- * @param[in] pos The position within the device from which to begin reading. For devices that
- * support seeking, this value is used to specify the starting point.
- * @param[out] buffer A pointer to the buffer where the read data will be stored. This buffer should
- * be large enough to hold the specified amount of data.
- * @param[in] size The number of bytes to read from the device. This value determines how much
- * data is read into the buffer.
- *
- * @return rt_ssize_t Returns the number of bytes actually read from the device:
- * - On success: The number of bytes read, which may be less than `size` if
- * the end of the device is reached or other factors limit the read.
- * - On failure: A negative error code.
- *
- * @note The device must be open and in a readable state before calling this function.
- * The `pos` parameter allows seeking within the device if it supports such operations.
- *
- * @warning Ensure that the buffer provided is large enough to hold the data being read.
- * Providing an insufficient buffer may result in undefined behavior.
- */
- rt_ssize_t sys_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
- {
- return rt_device_read(dev, pos, buffer, size);
- }
- /**
- * @brief Writes data to an open device.
- *
- * This system call writes data to the specified device, starting at the given position and using
- * the provided buffer. The device must be open and ready for writing. The amount of data to write
- * is determined by the `size` parameter.
- *
- * @param[in] dev A pointer to the device structure representing the device to write to.
- * The device must be open and ready for writing.
- * @param[in] pos The position within the device where the writing should start. For devices
- * that support seeking, this value specifies the location to begin writing.
- * @param[in] buffer A pointer to the buffer containing the data to be written to the device.
- * This buffer should contain the data to be written and should be large enough
- * to accommodate the specified size.
- * @param[in] size The number of bytes to write to the device. This value indicates how much
- * data should be written from the buffer to the device.
- *
- * @return rt_ssize_t Returns the number of bytes actually written to the device:
- * - On success: The number of bytes written, which may be less than `size`
- * if there is an issue with the device or the data was truncated.
- * - On failure: A negative error code.
- *
- * @note The device must be open and in a writable state before calling this function.
- * The `pos` parameter allows seeking within the device if it supports such operations.
- *
- * @warning Ensure that the buffer provided contains valid data and that it is large enough
- * to fit the amount of data specified by `size`. Providing an insufficient buffer
- * or invalid data may lead to undefined behavior.
- */
- rt_ssize_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
- {
- return rt_device_write(dev, pos, buffer, size);
- }
- #ifdef RT_USING_SAL
- /* network interfaces */
- /**
- * @brief Accepts a connection on a socket.
- *
- * This system call is used to accept a pending connection request on a socket. It extracts the
- * first connection request from the incoming queue, creates a new socket for the connection,
- * and stores the address information of the remote peer in the provided address structure.
- * The original socket must be a listening socket that has been previously bound and set to listen
- * for incoming connections.
- *
- * @param[in] socket The listening socket file descriptor that is waiting for incoming connections.
- * This socket must be in a listening state, created using `sys_socket` and
- * bound to an address using `sys_bind`.
- * @param[out] addr A pointer to a `musl_sockaddr` structure where the address of the connecting
- * client will be stored. The structure is populated with information such as
- * the client's IP address and port number.
- * @param[in,out] addrlen A pointer to a socklen_t variable that specifies the size of the `addr`
- * structure on input. On output, it will contain the actual size of the
- * address returned in `addr`.
- *
- * @return sysret_t Returns a socket descriptor for the new connection on success, or
- * `SYSRET_ERROR` on failure:
- * - On success: A new socket descriptor that can be used for further
- * communication with the connected peer.
- * - On failure: A negative error code indicating the reason for the failure.
- *
- * @note The socket passed as `socket` must be in a listening state and ready to accept incoming
- * connections. The `addr` structure is populated with the client's address details, which can
- * be used for further operations, such as identifying the client.
- *
- * @warning Ensure that the `addr` structure is sufficiently large to hold the address information.
- * The `addrlen` parameter must be set to the size of the `musl_sockaddr` structure before
- * calling this function. Calling the function with an incorrectly sized `addrlen` may lead
- * to buffer overflows or undefined behavior.
- */
- sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
- {
- int ret = -1;
- struct sockaddr ksa;
- struct musl_sockaddr kmusladdr;
- socklen_t uaddrlen;
- socklen_t kaddrlen;
- if (addr)
- {
- if (!lwp_user_accessable(addrlen, sizeof(socklen_t)))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&uaddrlen, addrlen, sizeof(socklen_t));
- if (!uaddrlen)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable(addr, uaddrlen))
- {
- return -EFAULT;
- }
- }
- kaddrlen = sizeof(struct sockaddr);
- ret = accept(socket, &ksa, &kaddrlen);
- if (ret >= 0)
- {
- if (addr)
- {
- sockaddr_tomusl(&ksa, &kmusladdr);
- if (uaddrlen > sizeof(struct musl_sockaddr))
- {
- uaddrlen = sizeof(struct musl_sockaddr);
- }
- lwp_put_to_user(addr, &kmusladdr, uaddrlen);
- lwp_put_to_user(addrlen, &uaddrlen, sizeof(socklen_t));
- }
- }
- return ret;
- }
- /**
- * @brief Binds a socket to a local address.
- *
- * This system call binds a socket to a specific local address and port. The socket must be created
- * using `sys_socket` before it can be bound. The `bind` operation allows the application to associate
- * a socket with a specific address, such as an IP address and port number, which can then be used
- * for sending or receiving data.
- *
- * @param[in] socket The socket descriptor to which the address will be bound. This socket must
- * be created using `sys_socket` and should not already be bound to another address.
- * @param[in] name A pointer to a `musl_sockaddr` structure that contains the address to which
- * the socket will be bound. This can represent an IP address and port number.
- * @param[in] namelen The size of the `musl_sockaddr` structure in bytes. This value should be set
- * to the actual size of the `name` structure before calling this function.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note The `socket` must be created before calling this function, and the address provided in `name`
- * should be a valid local address for the socket. This operation is typically used for server-side
- * sockets that listen for incoming connections or for any socket that needs to specify its local
- * address before communication.
- *
- * @warning If the specified address is already in use by another socket or if the socket type is incompatible
- * with the address, the function will return an error. Ensure that the address is not in use and is
- * valid for the socket type.
- */
- sysret_t sys_bind(int socket, const struct musl_sockaddr *name, socklen_t namelen)
- {
- rt_err_t ret = 0;
- struct sockaddr sa;
- struct sockaddr_un un_addr;
- struct musl_sockaddr kname;
- rt_uint16_t family = 0;
- if (!lwp_user_accessable((void *)name, namelen))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&family, (void *)name, 2);
- if (family == AF_UNIX)
- {
- lwp_get_from_user(&un_addr, (void *)name, sizeof(struct sockaddr_un));
- ret = bind(socket, (struct sockaddr *)&un_addr, namelen);
- }
- else if (family == AF_NETLINK)
- {
- lwp_get_from_user(&sa, (void *)name, namelen);
- ret = bind(socket, &sa, namelen);
- }
- else
- {
- lwp_get_from_user(&kname, (void *)name, namelen);
- sockaddr_tolwip(&kname, &sa);
- ret = bind(socket, &sa, namelen);
- }
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Shuts down part of a full-duplex connection.
- *
- * This system call disables further send or receive operations on a socket. The `how` parameter
- * specifies which part of the connection should be shut down. This operation is typically used
- * when the application no longer needs to send or receive data, but wants to keep the connection open
- * for other purposes (e.g., receiving shutdown acknowledgment).
- *
- * @param[in] socket The socket descriptor to be shut down. This socket must be an open socket that
- * has been created using `sys_socket`.
- * @param[in] how The shutdown behavior:
- * - `SHUT_RD`: Disables further receives on the socket. The application can no longer
- * receive data from this socket.
- * - `SHUT_WR`: Disables further sends on the socket. The application can no longer
- * send data through this socket.
- * - `SHUT_RDWR`: Disables both sends and receives on the socket. The socket is
- * fully shut down for communication.
- *
- * @return sysret_t Returns `0` on success, or a negative error code (e.g., `SYSRET_ERROR`) on failure.
- *
- * @note The `socket` should be open and in a connected state when calling this function. The `how`
- * parameter determines which part of the connection is to be shut down, allowing for finer control
- * over communication termination.
- *
- * @warning Once a socket is shut down with `SHUT_RD`, no further data can be received on it. Similarly,
- * after `SHUT_WR`, no more data can be sent. Calling `sys_shutdown` with incompatible `how` values
- * or on an invalid socket may result in errors.
- */
- sysret_t sys_shutdown(int socket, int how)
- {
- return shutdown(socket, how);
- }
- /**
- * @brief Retrieves the address of the peer connected to a socket.
- *
- * This system call retrieves the address of the peer (remote endpoint) that is connected to the specified
- * socket. The socket must be connected (i.e., for stream-oriented protocols such as TCP). The address
- * of the peer is stored in the `name` structure, and the size of the structure is updated in `namelen`.
- *
- * @param[in] socket The socket descriptor of the connected socket. This socket must be in a connected
- * state (e.g., after a successful `sys_connect` or `sys_accept` call).
- * @param[out] name A pointer to a `musl_sockaddr` structure where the address of the peer will be
- * stored. This structure will be populated with the peer's IP address and port number.
- * @param[in,out] namelen A pointer to a `socklen_t` variable that specifies the size of the `name` structure
- * on input. On output, it will contain the actual size of the address returned in `name`.
- *
- * @return sysret_t Returns `SYSRET_OK` on success, or a negative error code on failure.
- *
- * @note The `socket` must be in a connected state when calling this function. The `name` structure will
- * contain the peer's address information, which can be used for logging, debugging, or further
- * communication.
- *
- * @warning Ensure that the `name` structure is sufficiently large to hold the peer's address information.
- * The `namelen` parameter must be set to the size of the `name` structure before calling this function.
- * Failing to provide a correctly sized `namelen` could result in buffer overflows or undefined behavior.
- */
- sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *namelen)
- {
- int ret = -1;
- struct sockaddr sa;
- struct musl_sockaddr kname;
- socklen_t unamelen;
- socklen_t knamelen;
- if (!lwp_user_accessable(namelen, sizeof(socklen_t)))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&unamelen, namelen, sizeof(socklen_t));
- if (!unamelen)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable(name, unamelen))
- {
- return -EFAULT;
- }
- knamelen = sizeof(struct sockaddr);
- ret = getpeername(socket, &sa, &knamelen);
- if (ret == 0)
- {
- sockaddr_tomusl(&sa, &kname);
- if (unamelen > sizeof(struct musl_sockaddr))
- {
- unamelen = sizeof(struct musl_sockaddr);
- }
- lwp_put_to_user(name, &kname, unamelen);
- lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t));
- }
- else
- {
- ret = GET_ERRNO();
- }
- return ret;
- }
- /**
- * @brief Retrieves the local address of the socket.
- *
- * This system call retrieves the local address (local endpoint) that is bound to the specified socket.
- * The socket must be created and, if necessary, bound to a local address using `sys_bind`. The address
- * of the local endpoint is stored in the `name` structure, and the size of the structure is updated in `namelen`.
- *
- * @param[in] socket The socket descriptor of the socket. This socket must be created and, if required,
- * bound to a local address.
- * @param[out] name A pointer to a `musl_sockaddr` structure where the local address of the socket will
- * be stored. This structure will be populated with the local IP address and port number.
- * @param[in,out] namelen A pointer to a `socklen_t` variable that specifies the size of the `name` structure
- * on input. On output, it will contain the actual size of the address returned in `name`.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note The `socket` must be created and, if needed, bound to a local address using `sys_bind`.
- * The `name` structure will contain the local address of the socket, which can be used for logging,
- * debugging, or further communication.
- *
- * @warning Ensure that the `name` structure is sufficiently large to hold the local address information.
- * The `namelen` parameter must be set to the size of the `name` structure before calling this function.
- * Failing to provide a correctly sized `namelen` could result in buffer overflows or undefined behavior.
- */
- sysret_t sys_getsockname(int socket, struct musl_sockaddr *name, socklen_t *namelen)
- {
- int ret = -1;
- struct sockaddr sa;
- struct musl_sockaddr kname;
- socklen_t unamelen;
- socklen_t knamelen;
- if (!lwp_user_accessable(namelen, sizeof (socklen_t)))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t));
- if (!unamelen)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable(name, unamelen))
- {
- return -EFAULT;
- }
- knamelen = sizeof(struct sockaddr);
- ret = getsockname(socket, &sa, &knamelen);
- if (ret == 0)
- {
- sockaddr_tomusl(&sa, &kname);
- if (unamelen > sizeof(struct musl_sockaddr))
- {
- unamelen = sizeof(struct musl_sockaddr);
- }
- lwp_put_to_user(name, &kname, unamelen);
- lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t));
- }
- else
- {
- ret = GET_ERRNO();
- }
- return ret;
- }
- /**
- * @brief Retrieves the value of a socket option.
- *
- * This system call retrieves the current value of a socket option for the specified socket. The socket
- * options allow fine-grained control over various aspects of socket behavior, such as timeouts, buffering,
- * and connection settings. The option value is stored in the `optval` buffer, and the size of the buffer
- * is specified by the `optlen` parameter.
- *
- * @param[in] socket The socket descriptor for which the option value is being retrieved. The socket
- * must be valid and open.
- * @param[in] level The level at which the option is defined. Typically, this is `SOL_SOCKET` for general
- * socket options, or a protocol-specific level (e.g., `IPPROTO_TCP` for TCP options).
- * @param[in] optname The option name. This specifies which socket option to retrieve (e.g., `SO_RCVBUF`
- * for receive buffer size or `SO_RCVBUF` for send buffer size).
- * @param[out] optval A pointer to a buffer where the option value will be stored. The buffer's type depends
- * on the option being retrieved.
- * @param[in,out] optlen A pointer to a `socklen_t` variable that specifies the size of the `optval` buffer on
- * input. On output, it will contain the actual size of the option value retrieved.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note The `socket` must be valid and open when calling this function. The `level` and `optname` parameters
- * define the specific option to be retrieved. The `optval` buffer will contain the option value after
- * the function call, and `optlen` will be updated to reflect the size of the retrieved value.
- *
- * @warning Ensure that the `optval` buffer is large enough to hold the value for the specified option.
- * The `optlen` parameter must be set to the correct size of the buffer before calling this function.
- * Failing to provide a correctly sized buffer could result in undefined behavior or buffer overflows.
- */
- sysret_t sys_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen)
- {
- int ret = 0;
- socklen_t koptlen = 0;
- void *koptval = RT_NULL;
- if (!lwp_user_accessable((void *)optlen, sizeof(uint32_t)))
- return -EFAULT;
- if (lwp_get_from_user(&koptlen, optlen, sizeof(uint32_t)) != sizeof(uint32_t))
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)optval, koptlen))
- return -EFAULT;
- koptval = kmem_get(koptlen);
- if (koptval == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(koptval, optval, koptlen) != koptlen)
- {
- kmem_put(koptval);
- return -EINVAL;
- }
- convert_sockopt(&level, &optname);
- ret = getsockopt(socket, level, optname, koptval, &koptlen);
- lwp_put_to_user((void *)optval, koptval, koptlen);
- lwp_put_to_user((void *)optlen, &koptlen, sizeof(uint32_t));
- kmem_put(koptval);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Sets the value of a socket option.
- *
- * This system call sets a socket option for the specified socket. Socket options control various aspects
- * of socket behavior, such as timeouts, buffer sizes, or connection parameters. The option value is
- * provided in the `optval` buffer, and its length is specified by the `optlen` parameter.
- *
- * @param[in] socket The socket descriptor for which the option is being set. The socket must be valid and open.
- * @param[in] level The level at which the option is defined. This can be `SOL_SOCKET` for general socket options,
- * or a protocol-specific level (e.g., `IPPROTO_TCP` for TCP options).
- * @param[in] optname The option name. This specifies which socket option to set (e.g., `SO_RCVBUF` for receive buffer size).
- * @param[in] optval A pointer to the buffer that contains the option value to set. The format of this buffer depends
- * on the option being set.
- * @param[in] optlen The size of the `optval` buffer. This specifies the length of the data to be used when setting
- * the option value.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure:
- *
- * @note The `socket` must be valid and open. The `level` and `optname` parameters define the specific option to be set,
- * and the `optval` buffer should contain the appropriate value for that option. The `optlen` parameter must
- * match the size of the `optval` buffer.
- *
- * @warning Ensure that the `optval` buffer contains valid data for the specified option. The `optlen` parameter must be
- * set to the correct size of the `optval` buffer before calling this function. Failing to provide a correctly
- * sized buffer could result in undefined behavior or errors.
- */
- sysret_t sys_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
- {
- int ret;
- void *koptval = RT_NULL;
- if (!lwp_user_accessable((void *)optval, optlen))
- return -EFAULT;
- koptval = kmem_get(optlen);
- if (koptval == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(koptval, (void *)optval, optlen) != optlen)
- {
- kmem_put(koptval);
- return -EINVAL;
- }
- convert_sockopt(&level, &optname);
- ret = setsockopt(socket, level, optname, koptval, optlen);
- kmem_put(koptval);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Establishes a connection to a remote socket.
- *
- * This system call attempts to establish a connection to a remote socket specified by the `name` parameter.
- * It is typically used for client-side socket operations to connect to a server. The connection is established
- * by using the specified socket descriptor and the address of the remote server.
- *
- * @param[in] socket The socket descriptor for the connection attempt. The socket must be valid and in a
- * `SOCK_STREAM` or `SOCK_DGRAM` state, depending on the protocol.
- * @param[in] name A pointer to a `sockaddr` structure containing the address of the remote host. This address
- * must include the correct IP address and port number for the connection.
- * @param[in] namelen The size of the `sockaddr` structure pointed to by `name`. This should match the size
- * of the address structure (e.g., `sizeof(struct sockaddr_in)` for IPv4).
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure:
- *
- * @note This function may block if the connection is being established, depending on the socket's configuration.
- * For non-blocking sockets, it will return immediately, even if the connection has not been established.
- *
- * @warning The `socket` must be of a valid type (e.g., `SOCK_STREAM` for TCP or `SOCK_DGRAM` for UDP).
- * The `name` parameter must point to a valid `sockaddr` structure that contains a correctly formatted address.
- */
- sysret_t sys_connect(int socket, const struct musl_sockaddr *name, socklen_t namelen)
- {
- int ret = 0;
- rt_uint16_t family = 0;
- struct sockaddr sa;
- struct musl_sockaddr kname;
- struct sockaddr_un addr_un;
- if (!lwp_user_accessable((void *)name, namelen))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&family, (void *)name, 2);
- if (family == AF_UNIX)
- {
- if (!lwp_user_accessable((void *)name, sizeof(struct sockaddr_un)))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&addr_un, (void *)name, sizeof(struct sockaddr_un));
- ret = connect(socket, (struct sockaddr *)(&addr_un), namelen);
- }
- else
- {
- lwp_get_from_user(&kname, (void *)name, namelen);
- sockaddr_tolwip(&kname, &sa);
- ret = connect(socket, &sa, namelen);
- }
- return ret;
- }
- /**
- * @brief Prepares a socket to accept incoming connection requests.
- *
- * This system call marks a socket as a passive socket, indicating that it will be used to accept
- * incoming connection requests. It is typically used on server-side sockets after binding a
- * local address and port using `sys_bind()`.
- *
- * @param[in] socket The socket descriptor to be set up for listening. The socket must be valid
- * and of type `SOCK_STREAM` (for TCP connections).
- * @param[in] backlog The maximum number of pending connections that can be queued. This value
- * is system-dependent and may be limited to a lower maximum.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note Before calling this function, the socket must be bound to a local address and port using
- * `sys_bind()`. Only sockets of type `SOCK_STREAM` can be used for listening. The actual
- * maximum queue length may be less than the specified `backlog` value, depending on system limits.
- *
- * @warning Ensure that the socket is properly initialized, bound, and of the correct type before calling this function.
- * Failure to do so will result in undefined behavior or errors.
- */
- sysret_t sys_listen(int socket, int backlog)
- {
- return listen(socket, backlog);
- }
- #define MUSLC_MSG_OOB 0x0001
- #define MUSLC_MSG_PEEK 0x0002
- #define MUSLC_MSG_DONTWAIT 0x0040
- #define MUSLC_MSG_WAITALL 0x0100
- #define MUSLC_MSG_MORE 0x8000
- static int netflags_muslc_2_lwip(int flags)
- {
- int flgs = 0;
- if (flags & MUSLC_MSG_PEEK)
- {
- flgs |= MSG_PEEK;
- }
- if (flags & MUSLC_MSG_WAITALL)
- {
- flgs |= MSG_WAITALL;
- }
- if (flags & MUSLC_MSG_OOB)
- {
- flgs |= MSG_OOB;
- }
- if (flags & MUSLC_MSG_DONTWAIT)
- {
- flgs |= MSG_DONTWAIT;
- }
- if (flags & MUSLC_MSG_MORE)
- {
- flgs |= MSG_MORE;
- }
- if (flags & MSG_ERRQUEUE)
- {
- flgs |= MSG_ERRQUEUE;
- }
- return flgs;
- }
- #ifdef ARCH_MM_MMU
- static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
- struct iovec **out_iov, void **out_msg_control)
- {
- size_t iovs_size;
- struct iovec *uiov, *kiov;
- size_t iovs_buffer_size = 0;
- void *iovs_buffer;
- if (!lwp_user_accessable(umsg, sizeof(*umsg)))
- {
- return -EFAULT;
- }
- lwp_get_from_user(kmsg, umsg, sizeof(*kmsg));
- iovs_size = sizeof(*kmsg->msg_iov) * kmsg->msg_iovlen;
- if (!lwp_user_accessable(kmsg->msg_iov, iovs_size))
- {
- return -EFAULT;
- }
- /* user and kernel */
- kiov = kmem_get(iovs_size * 2);
- if (!kiov)
- {
- return -ENOMEM;
- }
- uiov = (void *)kiov + iovs_size;
- lwp_get_from_user(uiov, kmsg->msg_iov, iovs_size);
- if (out_iov)
- {
- *out_iov = uiov;
- }
- kmsg->msg_iov = kiov;
- for (int i = 0; i < kmsg->msg_iovlen; ++i)
- {
- /*
- * We MUST check we can copy data to user after socket done in uiov
- * otherwise we will be lost the messages from the network!
- */
- if (!lwp_user_accessable(uiov->iov_base, uiov->iov_len))
- {
- kmem_put(kmsg->msg_iov);
- return -EPERM;
- }
- iovs_buffer_size += uiov->iov_len;
- kiov->iov_len = uiov->iov_len;
- ++kiov;
- ++uiov;
- }
- /* msg_iov and msg_control */
- iovs_buffer = kmem_get(iovs_buffer_size + kmsg->msg_controllen);
- if (!iovs_buffer)
- {
- kmem_put(kmsg->msg_iov);
- return -ENOMEM;
- }
- kiov = kmsg->msg_iov;
- for (int i = 0; i < kmsg->msg_iovlen; ++i)
- {
- kiov->iov_base = iovs_buffer;
- iovs_buffer += kiov->iov_len;
- ++kiov;
- }
- *out_msg_control = kmsg->msg_control;
- /* msg_control is the end of the iovs_buffer */
- kmsg->msg_control = iovs_buffer;
- return 0;
- }
- #endif /* ARCH_MM_MMU */
- /**
- * @brief Receives a message from a socket using a message header structure.
- *
- * This system call is used to receive data and associated metadata from a socket.
- * It supports both stream-oriented and message-oriented sockets and allows control
- * over the behavior of the receiving operation via the `flags` parameter.
- *
- * @param[in] socket The socket descriptor from which the message will be received.
- * The socket must be in a valid and connected state for stream-oriented
- * sockets or bound for message-oriented sockets.
- * @param[out] msg A pointer to an `msghdr` structure that specifies message buffers and
- * will receive the incoming data. The structure also stores ancillary
- * data for advanced socket operations.
- * @param[in] flags Modifiers that control the behavior of the receive operation. Common
- * flags include:
- * - `MSG_PEEK`: Peek at the incoming data without removing it from the queue.
- * - `MSG_WAITALL`: Wait for the full request to be satisfied before returning.
- * - `MSG_DONTWAIT`: Perform a non-blocking receive operation.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note The `msghdr` structure should be initialized properly, including setting up buffers for
- * receiving the data. The function can return fewer bytes than expected depending on socket
- * type and flags. For stream-oriented sockets, partial data may be received.
- *
- * @warning The `socket` must be valid and in an appropriate state. If the socket is non-blocking
- * and no data is available, the function will return immediately.
- *
- * @see sys_sendmsg()
- */
- sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags)
- {
- int flgs, ret = -1;
- struct msghdr kmsg;
- #ifdef ARCH_MM_MMU
- void *msg_control;
- struct iovec *uiov, *kiov;
- #endif
- if (!msg)
- {
- return -EPERM;
- }
- flgs = netflags_muslc_2_lwip(flags);
- #ifdef ARCH_MM_MMU
- ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control);
- if (!ret)
- {
- ret = recvmsg(socket, &kmsg, flgs);
- if (ret < 0)
- {
- goto _free_res;
- }
- kiov = kmsg.msg_iov;
- for (int i = 0; i < kmsg.msg_iovlen; ++i)
- {
- lwp_put_to_user(uiov->iov_base, kiov->iov_base, kiov->iov_len);
- ++kiov;
- ++uiov;
- }
- lwp_put_to_user(msg_control, kmsg.msg_control, kmsg.msg_controllen);
- lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags));
- _free_res:
- kmem_put(kmsg.msg_iov->iov_base);
- kmem_put(kmsg.msg_iov);
- }
- #else
- rt_memcpy(&kmsg, msg, sizeof(kmsg));
- ret = recvmsg(socket, &kmsg, flgs);
- if (!ret)
- {
- msg->msg_flags = kmsg.msg_flags;
- }
- #endif /* ARCH_MM_MMU */
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Receives data from a socket, optionally capturing the source address.
- *
- * This system call is used to receive data from a socket. For connectionless sockets, it also
- * retrieves the address of the sender. It supports both blocking and non-blocking operations
- * depending on the socket configuration and the specified flags.
- *
- * @param[in] socket The socket descriptor from which the data will be received. The socket
- * must be valid and appropriately configured (e.g., connected or bound).
- * @param[out] mem A pointer to the buffer where the received data will be stored.
- * @param[in] len The maximum number of bytes to receive. This defines the size of the `mem` buffer.
- * @param[in] flags Modifiers that control the behavior of the receive operation. Common
- * flags include:
- * - `MSG_PEEK`: Peek at the incoming data without removing it from the queue.
- * - `MSG_WAITALL`: Wait for the full request to be satisfied before returning.
- * - `MSG_DONTWAIT`: Perform a non-blocking receive operation.
- * @param[out] from A pointer to a `musl_sockaddr` structure that will hold the address of
- * the sender. This parameter can be `NULL` if the sender's address is not needed.
- * @param[in,out] fromlen A pointer to a `socklen_t` variable indicating the size of the `from` buffer.
- * On return, it will be updated with the actual size of the sender's address.
- * This parameter is ignored if `from` is `NULL`.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure:
- *
- * @note For stream-oriented sockets, this function behaves like `sys_recv()`, and the `from` and
- * `fromlen` parameters are ignored. For datagram-oriented sockets, the function fills `from`
- * with the address of the sender.
- *
- * @warning The `socket` must be valid and configured for receiving data. If the `mem` buffer is
- * smaller than the received data, excess data may be discarded. In non-blocking mode,
- * if no data is available, the function returns immediately.
- *
- * @see sys_sendto(), sys_recv()
- */
- sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags,
- struct musl_sockaddr *from, socklen_t *fromlen)
- {
- int flgs = 0;
- #ifdef ARCH_MM_MMU
- int ret = -1;
- void *kmem = RT_NULL;
- #endif
- flgs = netflags_muslc_2_lwip(flags);
- #ifdef ARCH_MM_MMU
- if (!len)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)mem, len))
- {
- return -EFAULT;
- }
- kmem = kmem_get(len);
- if (!kmem)
- {
- return -ENOMEM;
- }
- if (flags == 0x2)
- {
- flags = 0x1;
- }
- if (from)
- {
- struct sockaddr sa;
- ret = recvfrom(socket, kmem, len, flgs, &sa, fromlen);
- sockaddr_tomusl(&sa, from);
- }
- else
- {
- ret = recvfrom(socket, kmem, len, flgs, NULL, NULL);
- }
- if (ret > 0)
- {
- lwp_put_to_user(mem, kmem, len);
- }
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmem);
- return ret;
- #else
- int ret = -1;
- if (from)
- {
- struct sockaddr sa = {0};
- ret = recvfrom(socket, mem, len, flgs, &sa, fromlen);
- sockaddr_tomusl(&sa, from);
- }
- else
- {
- ret = recvfrom(socket, mem, len, flags, NULL, NULL);
- }
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Receives data from a connected socket.
- *
- * This system call is used to receive data from a socket that is in a connected state.
- * It supports various flags to modify the behavior of the receive operation.
- *
- * @param[in] socket The socket descriptor from which the data will be received.
- * The socket must be in a valid and connected state.
- * @param[out] mem A pointer to the buffer where the received data will be stored.
- * @param[in] len The maximum number of bytes to receive. This defines the size of the `mem` buffer.
- * @param[in] flags Modifiers that control the behavior of the receive operation. Common flags include:
- * - `MSG_PEEK`: Peek at the incoming data without removing it from the queue.
- * - `MSG_WAITALL`: Wait for the full request to be satisfied before returning.
- * - `MSG_DONTWAIT`: Perform a non-blocking receive operation.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note The function is designed for connected sockets, such as stream-oriented sockets (e.g., TCP).
- * For datagram-oriented sockets (e.g., UDP), use `sys_recvfrom()` to capture the sender's address if needed.
- *
- * @warning The `socket` must be valid and in a connected state. If the `mem` buffer is smaller than the
- * received data, excess data may be discarded. For non-blocking sockets, the function returns
- * immediately if no data is available.
- *
- * @see sys_send(), sys_recvfrom()
- */
- sysret_t sys_recv(int socket, void *mem, size_t len, int flags)
- {
- int flgs = 0;
- int ret;
- void *kmem = RT_NULL;
- if (!lwp_user_accessable((void *)mem, len))
- return -EFAULT;
- kmem = kmem_get(sizeof(*kmem));
- if (kmem == RT_NULL)
- {
- return -ENOMEM;
- }
- flgs = netflags_muslc_2_lwip(flags);
- ret = recvfrom(socket, kmem, len, flgs, NULL, NULL);
- lwp_put_to_user((void *)mem, kmem, len);
- kmem_put(kmem);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Sends a message from a socket using scatter-gather I/O.
- *
- * This system call sends data from multiple buffers specified in the `msghdr` structure. It is particularly
- * useful for advanced socket operations requiring ancillary data or scatter-gather I/O.
- *
- * @param[in] socket The socket descriptor through which the data will be sent. The socket must be
- * valid and, for connection-oriented sockets, in a connected state.
- * @param[in] msg A pointer to a `msghdr` structure that specifies the message to be sent. This structure includes:
- * - `msg_name`: Optional address of the target (used for connectionless sockets like UDP).
- * - `msg_namelen`: Length of the address in `msg_name`.
- * - `msg_iov`: An array of `iovec` structures pointing to the data buffers.
- * - `msg_iovlen`: The number of elements in the `msg_iov` array.
- * - `msg_control`: Optional ancillary data (e.g., file descriptors).
- * - `msg_controllen`: Length of the ancillary data.
- * - `msg_flags`: Flags for the message (e.g., end-of-record markers).
- * @param[in] flags Flags that modify the behavior of the send operation. Common flags include:
- * - `MSG_DONTWAIT`: Perform a non-blocking send operation.
- * - `MSG_EOR`: Indicates the end of a record.
- * - `MSG_NOSIGNAL`: Prevent the function from raising `SIGPIPE` on errors.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note This function is versatile and supports both connection-oriented (e.g., TCP) and
- * connectionless (e.g., UDP) sockets. For simpler use cases, consider using `sys_send()` or `sys_sendto()`.
- *
- * @warning The `socket` must be configured correctly for the intended communication. For non-blocking sockets,
- * the function may return immediately if the send buffer is full. Ancillary data in `msg_control`
- * must be formatted correctly to avoid undefined behavior.
- *
- * @see sys_send(), sys_sendto(), sys_recvmsg()
- */
- sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags)
- {
- int flgs, ret = -1;
- struct msghdr kmsg;
- #ifdef ARCH_MM_MMU
- void *msg_control;
- struct iovec *uiov, *kiov;
- #endif
- if (!msg)
- {
- return -EPERM;
- }
- flgs = netflags_muslc_2_lwip(flags);
- #ifdef ARCH_MM_MMU
- ret = copy_msghdr_from_user(&kmsg, (struct msghdr *)msg, &uiov, &msg_control);
- if (!ret)
- {
- kiov = kmsg.msg_iov;
- for (int i = 0; i < kmsg.msg_iovlen; ++i)
- {
- lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len);
- ++kiov;
- ++uiov;
- }
- lwp_get_from_user(kmsg.msg_control, msg_control, kmsg.msg_controllen);
- ret = sendmsg(socket, &kmsg, flgs);
- kmem_put(kmsg.msg_iov->iov_base);
- kmem_put(kmsg.msg_iov);
- }
- #else
- rt_memcpy(&kmsg, msg, sizeof(kmsg));
- ret = sendmsg(socket, &kmsg, flgs);
- if (!ret)
- {
- msg->msg_flags = kmsg.msg_flags;
- }
- #endif /* ARCH_MM_MMU */
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Sends data to a specific address using a socket.
- *
- * This system call is used to send data from a socket to a specified address. It is commonly
- * used with connectionless sockets (e.g., UDP) but can also be used with connection-oriented
- * sockets if the destination address needs to be overridden.
- *
- * @param[in] socket The socket descriptor used for sending data. It must be valid and
- * properly configured for communication.
- * @param[in] dataptr A pointer to the buffer containing the data to be sent.
- * @param[in] size The size, in bytes, of the data to be sent.
- * @param[in] flags Flags that modify the behavior of the send operation. Common flags include:
- * - `MSG_DONTWAIT`: Perform a non-blocking send operation.
- * - `MSG_NOSIGNAL`: Prevent the function from raising `SIGPIPE` on errors.
- * @param[in] to A pointer to a `musl_sockaddr` structure that specifies the destination address.
- * This parameter can be `NULL` if the socket is connection-oriented.
- * @param[in] tolen The length of the address structure pointed to by `to`.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note For connectionless sockets (e.g., UDP), `to` and `tolen` must specify a valid destination address.
- * For connection-oriented sockets (e.g., TCP), these parameters can be ignored if the connection
- * is already established.
- *
- * @warning Ensure that the buffer size (`size`) matches the expected size for the data protocol in use.
- * For non-blocking sockets, this function may return immediately if the send buffer is full.
- *
- * @see sys_send(), sys_sendmsg(), sys_recvfrom()
- */
- sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags,
- const struct musl_sockaddr *to, socklen_t tolen)
- {
- int flgs = 0;
- #ifdef ARCH_MM_MMU
- int ret = -1;
- void *kmem = RT_NULL;
- #endif
- flgs = netflags_muslc_2_lwip(flags);
- #ifdef ARCH_MM_MMU
- if (!size)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)dataptr, size))
- {
- return -EFAULT;
- }
- kmem = kmem_get(size);
- if (!kmem)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kmem, (void *)dataptr, size);
- if (to)
- {
- struct sockaddr sa;
- sockaddr_tolwip(to, &sa);
- ret = sendto(socket, kmem, size, flgs, &sa, tolen);
- }
- else
- {
- ret = sendto(socket, kmem, size, flgs, NULL, tolen);
- }
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmem);
- return ret;
- #else
- int ret;
- if (to)
- {
- struct sockaddr sa;
- sockaddr_tolwip(to, &sa);
- ret = sendto(socket, dataptr, size, flgs, &sa, tolen);
- }
- else
- {
- ret = sendto(socket, dataptr, size, flgs, NULL, tolen);
- }
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Sends data over a connected socket.
- *
- * This system call sends data from the specified buffer through a connected socket. It is typically
- * used with connection-oriented sockets (e.g., TCP) but can also work with connectionless sockets
- * (e.g., UDP) if a connection is established using `sys_connect()`.
- *
- * @param[in] socket The socket descriptor used for sending data. It must be a valid socket
- * and, for connection-oriented sockets, in a connected state.
- * @param[in] dataptr A pointer to the buffer containing the data to be sent.
- * @param[in] size The size, in bytes, of the data to be sent.
- * @param[in] flags Flags that modify the behavior of the send operation. Common flags include:
- * - `MSG_DONTWAIT`: Perform a non-blocking send operation.
- * - `MSG_NOSIGNAL`: Prevent the function from raising `SIGPIPE` on errors.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note For connection-oriented sockets, the socket must already be connected using `sys_connect()` or
- * `sys_accept()`. For connectionless sockets, use `sys_sendto()` to specify the destination address.
- *
- * @warning If the socket is in non-blocking mode and the send buffer is full, this function may return
- * immediately with an error. Ensure that the size of the data (`size`) matches the protocol's
- * expectations to avoid truncation or overflow issues.
- *
- * @see sys_sendto(), sys_sendmsg(), sys_recv()
- */
- sysret_t sys_send(int socket, const void *dataptr, size_t size, int flags)
- {
- int flgs = 0;
- int ret = 0;
- void *kdataptr = RT_NULL;
- if (!lwp_user_accessable((void *)dataptr, size))
- return -EFAULT;
- kdataptr = kmem_get(size);
- if (kdataptr == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kdataptr, (void *)dataptr, size) != size)
- {
- kmem_put(kdataptr);
- return -EINVAL;
- }
- flgs = netflags_muslc_2_lwip(flags);
- ret = sendto(socket, kdataptr, size, flgs, NULL, 0);
- kmem_put(kdataptr);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Creates a new socket for communication.
- *
- * This system call creates a new socket endpoint for communication and returns a file descriptor
- * that can be used for subsequent socket operations, such as binding, connecting, or data transfer.
- *
- * @param[in] domain Specifies the protocol family to be used for the socket. Common values include:
- * - `AF_INET`: IPv4 Internet protocols.
- * - `AF_INET6`: IPv6 Internet protocols.
- * - `AF_UNIX`: Local communication using UNIX domain sockets.
- * @param[in] type Specifies the type of socket to be created. Common values include:
- * - `SOCK_STREAM`: Provides sequenced, reliable, two-way, connection-based byte streams.
- * - `SOCK_DGRAM`: Supports datagrams (connectionless, unreliable messages of fixed maximum length).
- * - `SOCK_RAW`: Provides raw network protocol access.
- * @param[in] protocol Specifies the specific protocol to be used. Typically set to `0` to use the default
- * protocol for the specified domain and type.
- *
- * @return sysret_t Returns the socket file descriptor on success, or a negative error code on failure.
- *
- * @note The returned socket descriptor must be closed using `sys_close()` to release system resources.
- *
- * @warning Ensure the combination of `domain`, `type`, and `protocol` is valid. Invalid combinations
- * may result in errors. For example, specifying `AF_INET` with `SOCK_DGRAM` is valid for UDP,
- * but with `SOCK_STREAM` it is used for TCP.
- *
- * @see sys_bind(), sys_connect(), sys_accept(), sys_close()
- */
- sysret_t sys_socket(int domain, int type, int protocol)
- {
- int fd = -1;
- int nonblock = 0;
- /* not support SOCK_CLOEXEC type */
- if (type & SOCK_CLOEXEC)
- {
- type &= ~SOCK_CLOEXEC;
- }
- if (type & SOCK_NONBLOCK)
- {
- nonblock = 1;
- type &= ~SOCK_NONBLOCK;
- }
- fd = socket(domain, type, protocol);
- if (fd < 0)
- {
- goto out;
- }
- if (nonblock)
- {
- fcntl(fd, F_SETFL, O_NONBLOCK);
- }
- out:
- return (fd < 0 ? GET_ERRNO() : fd);
- }
- /**
- * @brief Creates a pair of connected sockets.
- *
- * This system call creates two connected sockets that can be used for bidirectional communication
- * between processes or threads. The sockets are returned as file descriptors in the `fd` array.
- *
- * @param[in] domain Specifies the protocol family to be used for the sockets. Common values include:
- * - `AF_UNIX`: Local communication using UNIX domain sockets.
- * @param[in] type Specifies the type of socket to be created. Common values include:
- * - `SOCK_STREAM`: Provides sequenced, reliable, two-way, connection-based byte streams.
- * - `SOCK_DGRAM`: Supports datagrams (connectionless, unreliable messages of fixed maximum length).
- * @param[in] protocol Specifies the specific protocol to be used. Typically set to `0` to use the default
- * protocol for the specified domain and type.
- * @param[out] fd An array of two integers where the connected socket descriptors will be stored.
- * After a successful call:
- * - `fd[0]`: The first socket descriptor.
- * - `fd[1]`: The second socket descriptor.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note The sockets in the pair are connected and can be used for inter-process communication
- * (IPC) or between threads in the same process.
- *
- * @warning Ensure the `domain`, `type`, and `protocol` combination is valid. This function is typically
- * supported only for `AF_UNIX` domain.
- *
- * @see sys_socket(), sys_close()
- */
- sysret_t sys_socketpair(int domain, int type, int protocol, int fd[2])
- {
- #ifdef RT_USING_SAL
- int ret = 0;
- int k_fd[2];
- if (!lwp_user_accessable((void *)fd, sizeof(int [2])))
- {
- return -EFAULT;
- }
- ret = socketpair(domain, type, protocol, k_fd);
- if (ret == 0)
- {
- lwp_put_to_user(fd, k_fd, sizeof(int [2]));
- }
- return ret;
- #else
- return -ELIBACC;
- #endif
- }
- /**
- * @brief Closes an open socket.
- *
- * This system call is used to close a previously opened socket. Once the socket is closed, it is no longer
- * valid for any further operations, such as sending, receiving, or other socket-related functions.
- *
- * @param[in] socket The socket descriptor to be closed. This descriptor must be a valid socket that was
- * previously created with `sys_socket()` or related functions.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note Once a socket is closed, any attempts to use the socket for communication will result in an error.
- * The system will release any resources associated with the socket.
- *
- * @warning Make sure that no data is being transferred or pending on the socket before closing it.
- * Closing an active socket might lead to data loss.
- *
- * @see sys_socket(), sys_shutdown()
- */
- sysret_t sys_closesocket(int socket)
- {
- return closesocket(socket);
- }
- #endif
- /**
- * @brief Finds a thread by its name.
- *
- * This system call is used to search for a thread based on its name. It returns a reference to the
- * thread if found, otherwise it returns `RT_NULL`. The name comparison is case-sensitive.
- *
- * @param[in] name The name of the thread to search for. This should be a valid string that
- * uniquely identifies the thread within the system.
- *
- * @return rt_thread_t The thread object corresponding to the given name, or `RT_NULL` if no
- * matching thread was found.
- *
- * @note The thread name is typically assigned when the thread is created, and it can be used to
- * identify threads in the system.
- *
- * @warning Ensure that the `name` string is correctly set and unique within the system to avoid
- * unexpected behavior.
- *
- * @see sys_thread_create(), sys_thread_delete()
- */
- rt_thread_t sys_thread_find(char *name)
- {
- int len = 0;
- char *kname = RT_NULL;
- rt_thread_t thread;
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- return RT_NULL;
- }
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- {
- return RT_NULL;
- }
- if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
- {
- kmem_put(kname);
- return RT_NULL;
- }
- thread = rt_thread_find(name);
- kmem_put(kname);
- return thread;
- }
- /**
- * @brief Gets the current system tick count.
- *
- * This system call returns the current value of the system tick counter, which is typically incremented
- * at a fixed interval (e.g., every millisecond or microsecond). The tick count can be used for timing
- * purposes, such as measuring the elapsed time or triggering time-based events.
- *
- * @return rt_tick_t The current value of the system tick counter.
- *
- * @note The system tick counter typically wraps around after reaching its maximum value, so the
- * returned tick value may reset after a certain period of time, depending on the configuration
- * of the system tick timer.
- *
- * @warning Be cautious when using the tick value for time-based calculations, as the counter may
- * overflow and wrap around. Ensure that the code handling the tick count properly accounts
- * for potential overflow.
- *
- * @see sys_tick_init(), sys_tick_delay()
- */
- rt_tick_t sys_tick_get(void)
- {
- return rt_tick_get();
- }
- /**
- * @brief Delays the current thread for a specified number of milliseconds.
- *
- * This system call puts the calling thread to sleep for a given number of milliseconds. It is a blocking
- * call, meaning the thread will not execute any further instructions until the specified delay has
- * passed. The delay is achieved by the system's timer mechanism.
- *
- * @param[in] ms The number of milliseconds to delay. The value must be a positive integer.
- *
- * @return sysret_t Returns `0` on success, or a negative error code on failure.
- *
- * @note This function is useful for introducing a fixed delay in time-sensitive applications or when
- * the thread needs to be paused before continuing execution.
- *
- * @warning Be cautious when using this function in real-time or time-critical applications, as
- * excessive delays may affect overall system performance or responsiveness.
- *
- * @see sys_thread_delay(), sys_thread_sleep()
- */
- sysret_t sys_thread_mdelay(rt_int32_t ms)
- {
- return rt_thread_mdelay(ms);
- }
- struct k_sigaction {
- void (*handler)(int);
- unsigned long flags;
- void (*restorer)(void);
- unsigned mask[2];
- };
- /**
- * @brief Changes the action taken by the system on receiving a signal.
- *
- * This system call allows a process to specify how signals should be handled. It allows you to set a
- * new action for a specific signal, retrieve the old action, and define the signal mask that should
- * be applied during the execution of the signal handler.
- *
- * @param[in] sig The signal number for which the action is to be set or retrieved.
- * Signal numbers are typically defined as constants (e.g., `SIGINT`, `SIGTERM`).
- * @param[in] act A pointer to a `k_sigaction` structure that specifies the new action for the signal.
- * If `act` is `NULL`, the signal's action is not changed.
- * @param[out] oact A pointer to a `k_sigaction` structure where the old action will be stored.
- * If `oact` is `NULL`, the old action is not retrieved.
- * @param[in] sigsetsize The size of the `sigset_t` structure used in `k_sigaction`. This is to ensure the
- * compatibility with the signal mask size.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note The `k_sigaction` structure allows you to specify the signal handler, signal mask, and flags for
- * the signal action. It is important to correctly configure the handler to prevent unexpected
- * behavior in the signal handling process.
- *
- * @warning Be cautious when modifying signal handling behavior, as incorrect configuration may result
- * in unhandled signals or undefined behavior. Signal handlers should be designed to perform
- * minimal, safe operations.
- *
- * @see sys_signal(), sys_sigprocmask()
- */
- sysret_t sys_sigaction(int sig, const struct k_sigaction *act,
- struct k_sigaction *oact, size_t sigsetsize)
- {
- int ret = -RT_EINVAL;
- struct rt_lwp *lwp;
- struct lwp_sigaction kact, *pkact = RT_NULL;
- struct lwp_sigaction koact, *pkoact = RT_NULL;
- if (!sigsetsize)
- {
- SET_ERRNO(EINVAL);
- goto out;
- }
- if (sigsetsize > sizeof(lwp_sigset_t))
- {
- sigsetsize = sizeof(lwp_sigset_t);
- }
- if (!act && !oact)
- {
- SET_ERRNO(EINVAL);
- goto out;
- }
- if (oact)
- {
- if (!lwp_user_accessable((void *)oact, sizeof(*oact)))
- {
- SET_ERRNO(EFAULT);
- goto out;
- }
- pkoact = &koact;
- }
- if (act)
- {
- if (!lwp_user_accessable((void *)act, sizeof(*act)))
- {
- SET_ERRNO(EFAULT);
- goto out;
- }
- kact.sa_flags = act->flags;
- kact.__sa_handler._sa_handler = act->handler;
- lwp_memcpy(&kact.sa_mask, &act->mask, sigsetsize);
- kact.sa_restorer = act->restorer;
- pkact = &kact;
- }
- lwp = lwp_self();
- RT_ASSERT(lwp);
- ret = lwp_signal_action(lwp, sig, pkact, pkoact);
- #ifdef ARCH_MM_MMU
- if (ret == 0 && oact)
- {
- lwp_put_to_user(&oact->handler, &pkoact->__sa_handler._sa_handler, sizeof(void (*)(int)));
- lwp_put_to_user(&oact->mask, &pkoact->sa_mask, sigsetsize);
- lwp_put_to_user(&oact->flags, &pkoact->sa_flags, sizeof(int));
- lwp_put_to_user(&oact->restorer, &pkoact->sa_restorer, sizeof(void (*)(void)));
- }
- #endif /* ARCH_MM_MMU */
- out:
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- static int mask_command_u2k[] = {
- [SIG_BLOCK] = LWP_SIG_MASK_CMD_BLOCK,
- [SIG_UNBLOCK] = LWP_SIG_MASK_CMD_UNBLOCK,
- [SIG_SETMASK] = LWP_SIG_MASK_CMD_SET_MASK,
- };
- /**
- * @brief Sets or retrieves the signal mask for the calling process.
- *
- * This system call allows the caller to block or unblock signals by modifying the signal mask. The signal
- * mask determines which signals are blocked and which signals can be delivered to the process. The
- * function can also be used to retrieve the current signal mask.
- *
- * @param[in] how The action to be taken on the signal mask. It can be one of the following values:
- * - `SIG_BLOCK`: Add the signals in `sigset` to the current mask.
- * - `SIG_UNBLOCK`: Remove the signals in `sigset` from the current mask.
- * - `SIG_SETMASK`: Set the signal mask to the value in `sigset`, replacing the current mask.
- * @param[in] sigset A pointer to a `sigset_t` structure that specifies the signals to be blocked or unblocked.
- * This parameter is ignored when `how` is `SIG_SETMASK`, in which case `sigset` is used
- * as the new signal mask.
- * @param[out] oset A pointer to a `sigset_t` structure where the previous signal mask will be stored.
- * If `oset` is `NULL`, the previous signal mask will not be returned.
- * @param[in] size The size of the `sigset_t` structure, ensuring compatibility with the signal mask.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note Modifying the signal mask prevents signals from being delivered to the process while they are blocked.
- * Once the signals are unblocked, they will be delivered to the process if they are pending.
- *
- * @warning Be careful when blocking signals, especially critical ones like `SIGKILL`, as it may interfere
- * with the normal operation of the system. Ensure that signal masks are managed carefully to avoid
- * missing important signals.
- *
- * @see sys_sigaction(), sys_sigpending()
- */
- sysret_t sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size)
- {
- int ret = -1;
- lwp_sigset_t *pnewset = RT_NULL, *poldset = RT_NULL;
- #ifdef ARCH_MM_MMU
- lwp_sigset_t newset, oldset;
- #endif /* ARCH_MM_MMU*/
- if (!size)
- {
- return -EINVAL;
- }
- if (!oset && !sigset)
- {
- return -EINVAL;
- }
- if (size > sizeof(lwp_sigset_t))
- {
- size = sizeof(lwp_sigset_t);
- }
- if (oset)
- {
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)oset, size))
- {
- return -EFAULT;
- }
- poldset = &oldset;
- #else
- if (!lwp_user_accessable((void *)oset, size))
- {
- return -EFAULT;
- }
- poldset = (lwp_sigset_t *)oset;
- #endif
- }
- if (sigset)
- {
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)sigset, size))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&newset, (void *)sigset, size);
- pnewset = &newset;
- #else
- if (!lwp_user_accessable((void *)sigset, size))
- {
- return -EFAULT;
- }
- pnewset = (lwp_sigset_t *)sigset;
- #endif /* ARCH_MM_MMU */
- }
- ret = lwp_thread_signal_mask(rt_thread_self(), mask_command_u2k[how], pnewset, poldset);
- #ifdef ARCH_MM_MMU
- if (ret < 0)
- {
- return ret;
- }
- if (oset)
- {
- lwp_put_to_user(oset, poldset, size);
- }
- #endif /* ARCH_MM_MMU */
- return (ret < 0 ? -EFAULT: ret);
- }
- /**
- * @brief Retrieves the set of signals that are pending for delivery to the calling process.
- *
- * This system call allows a process to query the set of signals that are pending, i.e., signals that have
- * been sent to the process but have not yet been delivered because the process is blocking those signals
- * or has not yet handled them. The function returns the set of signals that are waiting to be delivered.
- *
- * @param[out] sigset A pointer to a `sigset_t` structure where the set of pending signals will be stored.
- * The `sigset_t` structure will contain the signals that are pending for delivery.
- * @param[in] sigsize The size of the `sigset_t` structure, used to ensure compatibility with the signal set.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note The returned signal set will contain the signals that have been sent to the process but are blocked,
- * or that are waiting to be handled. These signals will be delivered once they are unblocked or the
- * process handles them.
- *
- * @warning Be cautious when querying pending signals, as unblocking too many signals at once may lead
- * to unexpected behavior or a flood of signal deliveries. It's recommended to carefully manage
- * the signals the process can accept at any given time.
- *
- * @see sys_sigaction(), sys_sigprocmask()
- */
- sysret_t sys_sigpending(sigset_t *sigset, size_t sigsize)
- {
- sysret_t ret = 0;
- lwp_sigset_t lwpset;
- /* Verify and Get sigset, timeout */
- if (!sigset || !lwp_user_accessable((void *)sigset, sigsize))
- {
- ret = -EFAULT;
- }
- else
- {
- /* Fit sigset size to lwp set */
- if (sizeof(lwpset) < sigsize)
- {
- LOG_I("%s: sigsize (%lx) extends lwp sigset chunk\n", __func__, sigsize);
- sigsize = sizeof(lwpset);
- }
- lwp_thread_signal_pending(rt_thread_self(), &lwpset);
- if (!lwp_put_to_user(sigset, &lwpset, sigsize))
- RT_ASSERT(0); /* should never happened */
- }
- return ret;
- }
- /**
- * @brief Waits for a signal to be delivered, with a timeout.
- *
- * This system call allows a process to wait for one of the signals specified in the `sigset` to be delivered.
- * The process will block until a signal in the set is received or the specified timeout period expires.
- * If the signal is received before the timeout, information about the signal will be returned in the `siginfo_t` structure.
- * If the timeout expires without any signal being delivered, the function will return with an appropriate error code.
- *
- * @param[in] sigset A pointer to a `sigset_t` structure that specifies the set of signals to wait for.
- * The function will block until a signal in this set is received, or the timeout expires.
- * @param[out] info A pointer to a `siginfo_t` structure where information about the delivered signal will be stored.
- * If no signal is received before the timeout, this structure will not be filled.
- * @param[in] timeout A pointer to a `timespec` structure that specifies the maximum amount of time to wait
- * for a signal to be delivered. If this value is `NULL`, the function will wait indefinitely.
- * @param[in] sigsize The size of the `sigset_t` structure, ensuring compatibility with the signal set.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note If the `timeout` is `NULL`, the function will block indefinitely until a signal is delivered.
- * If a signal is received, the corresponding information is returned in the `siginfo_t` structure.
- * The `sigset` should contain only the signals you are interested in.
- *
- * @warning If the timeout expires, no signal will be delivered, and the function will return a timeout error.
- * Make sure to handle the timeout case correctly to prevent any unexpected behavior.
- *
- * @see sys_sigaction(), sys_sigtimedwait()
- */
- sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct timespec *timeout, size_t sigsize)
- {
- int sig;
- size_t ret;
- lwp_sigset_t lwpset;
- siginfo_t kinfo;
- struct timespec ktimeout;
- struct timespec *ptimeout;
- /* for RT_ASSERT */
- RT_UNUSED(ret);
- /* Fit sigset size to lwp set */
- if (sizeof(lwpset) < sigsize)
- {
- LOG_I("%s: sigsize (%lx) extends lwp sigset chunk\n", __func__, sigsize);
- sigsize = sizeof(lwpset);
- }
- else
- {
- /* if sigset of user is smaller, clear extra space */
- memset(&lwpset, 0, sizeof(lwpset));
- }
- /* Verify and Get sigset, timeout */
- if (!sigset || !lwp_user_accessable((void *)sigset, sigsize))
- {
- return -EFAULT;
- }
- else
- {
- ret = lwp_get_from_user(&lwpset, (void *)sigset, sigsize);
- RT_ASSERT(ret == sigsize);
- }
- if (timeout)
- {
- if (!lwp_user_accessable((void *)timeout, sizeof(*timeout)))
- return -EFAULT;
- else
- {
- ret = lwp_get_from_user(&ktimeout, (void *)timeout, sizeof(*timeout));
- ptimeout = &ktimeout;
- RT_ASSERT(ret == sizeof(*timeout));
- }
- }
- else
- {
- ptimeout = RT_NULL;
- }
- sig = lwp_thread_signal_timedwait(rt_thread_self(), &lwpset, &kinfo, ptimeout);
- if (sig > 0 && info)
- {
- if (!lwp_user_accessable((void *)info, sizeof(*info)))
- return -EFAULT;
- else
- {
- ret = lwp_put_to_user(info, &kinfo, sizeof(*info));
- RT_ASSERT(ret == sizeof(*info));
- }
- }
- return sig;
- }
- /**
- * @brief Sends a signal to a specific thread.
- *
- * This system call allows a process to send a signal to a specific thread within the same process.
- * The signal specified by the `sig` parameter will be delivered to the thread with the ID `tid`.
- * This function is similar to `kill()`, but it targets a specific thread rather than a process.
- *
- * @param[in] tid The thread ID to which the signal will be sent. This ID identifies the target thread within the same process.
- * @param[in] sig The signal number to be sent to the specified thread. The signal can be any valid signal number.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note The `sig` parameter must be a valid signal number. It can range from `1` to `31`, or be one of the predefined signal constants like `SIGKILL`, `SIGTERM`, etc.
- * If the target thread does not exist or is not eligible to receive the signal, the function will fail.
- *
- * @warning If an invalid signal number is provided or the target thread does not exist, an error will be returned.
- * Be careful when sending signals, as some signals (e.g., `SIGKILL`) can immediately terminate the target thread.
- *
- * @see sys_kill(), sys_sigaction()
- */
- sysret_t sys_tkill(int tid, int sig)
- {
- #ifdef ARCH_MM_MMU
- rt_thread_t thread;
- sysret_t ret;
- /**
- * Brief: Match a tid and do the kill
- *
- * Note: Critical Section
- * - the thread (READ. may be released at the meantime; protected by locked)
- */
- thread = lwp_tid_get_thread_and_inc_ref(tid);
- ret = lwp_thread_signal_kill(thread, sig, SI_USER, 0);
- lwp_tid_dec_ref(thread);
- return ret;
- #else
- return lwp_thread_kill((rt_thread_t)tid, sig);
- #endif
- }
- /**
- * @brief Manipulates the signal mask for the current thread.
- *
- * This function allows a thread to modify its signal mask, which controls which signals are blocked (prevented from delivery).
- * The signal mask can be modified by adding, removing, or setting the signal set as a whole, depending on the `how` parameter.
- * The `sigset` specifies the signals to be manipulated, and the current signal mask before modification can be retrieved in `oset`.
- *
- * @param[in] how The operation to perform on the signal mask. It can be one of the following values:
- * - `SIG_BLOCK`: Add the signals in `sigset` to the current mask (block those signals).
- * - `SIG_UNBLOCK`: Remove the signals in `sigset` from the current mask (unblock those signals).
- * - `SIG_SETMASK`: Set the signal mask to the signals specified in `sigset` (replace the current mask).
- * @param[in] sigset A pointer to an `lwp_sigset_t` structure that specifies the set of signals to be manipulated.
- * Signals in this set will be added, removed, or set in the current thread's signal mask based on the `how` parameter.
- * @param[out] oset A pointer to an `lwp_sigset_t` structure where the previous signal mask will be stored.
- * This allows the caller to restore the previous mask if needed.
- * @param[in] size The size of the `lwp_sigset_t` structure. This ensures that the correct structure size is used during signal mask manipulation.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note The `sigset` structure should contain only valid signal numbers. If `how` is `SIG_SETMASK`, the entire signal mask will be replaced by the contents of `sigset`.
- * If `how` is `SIG_BLOCK` or `SIG_UNBLOCK`, the signals in `sigset` will be added or removed from the current mask, respectively.
- *
- * @warning Be cautious when modifying the signal mask, as blocking signals can cause the thread to miss important signals.
- * If a signal is blocked, it will not be delivered to the thread until it is unblocked, or the thread is explicitly made to handle it.
- *
- * @see sys_sigaction(), sys_thread_sigpending()
- */
- sysret_t sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset, size_t size)
- {
- int ret = -1;
- lwp_sigset_t *pnewset = RT_NULL, *poldset = RT_NULL;
- #ifdef ARCH_MM_MMU
- lwp_sigset_t newset, oldset;
- #endif /* ARCH_MM_MMU */
- if (!size)
- {
- return -EINVAL;
- }
- if (!oset && !sigset)
- {
- return -EINVAL;
- }
- if (size != sizeof(lwp_sigset_t))
- {
- return -EINVAL;
- }
- if (oset)
- {
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)oset, size))
- {
- return -EFAULT;
- }
- poldset = &oldset;
- #else
- if (!lwp_user_accessable((void *)oset, size))
- {
- return -EFAULT;
- }
- poldset = oset;
- #endif
- }
- if (sigset)
- {
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)sigset, size))
- {
- return -EFAULT;
- }
- lwp_get_from_user(&newset, (void *)sigset, sizeof(lwp_sigset_t));
- pnewset = &newset;
- #else
- if (!lwp_user_accessable((void *)sigset, size))
- {
- return -EFAULT;
- }
- pnewset = (lwp_sigset_t *)sigset;
- #endif
- }
- ret = lwp_thread_signal_mask(rt_thread_self(), mask_command_u2k[how], pnewset, poldset);
- if (ret < 0)
- {
- return ret;
- }
- #ifdef ARCH_MM_MMU
- if (oset)
- {
- lwp_put_to_user(oset, poldset, sizeof(lwp_sigset_t));
- }
- #endif
- return (ret < 0 ? -EFAULT: ret);
- }
- #ifndef ARCH_MM_MMU
- /**
- * @brief Sets the signal handler for a specific signal in the current thread.
- *
- * This function allows a thread to set a custom signal handler for a specific signal.
- * When the specified signal is received, the corresponding handler function (`func`) will be invoked.
- * The handler will be executed in the context of the current thread, allowing it to handle signals as needed.
- *
- * @param[in] sig The signal number for which the handler is being set. This should be a valid signal number.
- * @param[in] func The signal handler function to be set. This function will be called when the specified signal is received.
- * The signature of `func` should match the expected format for signal handlers.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note The `func` parameter must be a valid function pointer. It will be called when the signal specified by `sig` is received by the thread.
- * The handler function typically has the signature: `void handler(int sig)`, where `sig` is the signal number.
- *
- * @warning Setting a custom signal handler may override any default actions for that signal.
- * It is important to ensure that the handler function is properly designed to handle the signal appropriately.
- * For example, some signals may require special handling (e.g., `SIGKILL` cannot be caught).
- *
- * @see sys_signal(), sys_lwp_sigaction()
- */
- sysret_t sys_lwp_sighandler_set(int sig, lwp_sighandler_t func)
- {
- if (!lwp_user_accessable((void *)func, sizeof(lwp_sighandler_t)))
- {
- return -EFAULT;
- }
- lwp_sighandler_set(sig, func);
- return 0;
- }
- /**
- * @brief Sets the signal handler for a specific signal in the target thread.
- *
- * This function allows setting a custom signal handler for a specific signal within a particular thread.
- * When the specified signal is delivered to the thread, the corresponding handler function (`func`) will be invoked.
- * The handler is executed in the context of the thread that receives the signal.
- *
- * @param[in] sig The signal number for which the handler is being set. This should be a valid signal number.
- * @param[in] func The signal handler function to be set. This function will be called when the specified signal is delivered to the target thread.
- * The handler function should have the signature `void func(int sig)`.
- *
- * @return sysret_t Returns `0` on success or a negative error code on failure.
- *
- * @note The `func` parameter must be a valid function pointer, and it will be invoked when the signal specified by `sig` is delivered to the target thread.
- * The handler function typically has the signature: `void handler(int sig)`, where `sig` is the signal number.
- *
- * @warning Setting a custom signal handler may override any default actions for that signal.
- * It is important to ensure that the handler function is properly designed to handle the signal appropriately.
- * For example, some signals may require special handling (e.g., `SIGKILL` cannot be caught).
- *
- * @see sys_thread_sigprocmask(), sys_thread_sigaction(), sys_signal()
- */
- sysret_t sys_thread_sighandler_set(int sig, lwp_sighandler_t func)
- {
- if (!lwp_user_accessable((void *)func, sizeof(lwp_sighandler_t)))
- {
- return -EFAULT;
- }
- lwp_thread_sighandler_set(sig, func);
- return 0;
- }
- #endif /* not defined ARCH_MM_MMU */
- /**
- * @brief Waits for the termination of a child process.
- *
- * This function makes the calling process wait until one of its child processes terminates or until a
- * specified condition is met. The function retrieves information about the terminated child process,
- * including its exit status, and can also handle other process-related events, such as stopping or
- * continuing execution.
- *
- * @param[in] pid The process ID of the child process to wait for. If `pid` is:
- * - `-1`: Wait for any child process.
- * - `0`: Wait for any child process in the same process group.
- * - > 0: Wait for the child process with the specified process ID.
- * @param[out] status A pointer to an integer where the exit status of the terminated child process will be stored.
- * This value provides information about the child's termination status, such as normal exit,
- * signal termination, etc.
- * @param[in] options A bitmask of options that control the behavior of the function. It can include:
- * - `WNOHANG`: Return immediately if no child has exited.
- * - `WUNTRACED`: Report status of stopped child processes.
- * - Other flags can be defined depending on the implementation.
- *
- * @return sysret_t Returns the process ID of the child process that terminated on success, or a negative error code on failure.
- *
- * @note The `status` argument provides detailed information about the termination of the child process. To interpret this
- * status, macros such as `WIFEXITED()`, `WIFSIGNALED()`, and `WEXITSTATUS()` are commonly used.
- *
- * @warning This function should be used carefully when managing child processes, as not properly handling child processes
- * may lead to zombie processes.
- *
- * @see sys_wait(), sys_waitid()
- */
- sysret_t sys_waitpid(int32_t pid, int *status, int options)
- {
- int ret = -1;
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)status, sizeof(int)))
- {
- return -EFAULT;
- }
- else
- {
- ret = lwp_waitpid(pid, status, options, RT_NULL);
- }
- #else
- if (!lwp_user_accessable((void *)status, sizeof(int)))
- {
- return -EFAULT;
- }
- ret = waitpid(pid, status, options);
- #endif
- return ret;
- }
- #if defined(RT_USING_SAL) && defined(SAL_USING_POSIX)
- struct musl_addrinfo
- {
- int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- socklen_t ai_addrlen;
- struct musl_sockaddr *ai_addr;
- char *ai_canonname;
- struct musl_addrinfo *ai_next;
- };
- /**
- * @brief Resolves network addresses and service names into a list of address structures.
- *
- * This function provides a mechanism for resolving a host name and service name (or port number)
- * into a list of address structures suitable for use with socket-based communication. The function
- * can handle both IPv4 and IPv6 addresses and provides a flexible way to specify different types
- * of address and service resolution options.
- *
- * @param[in] nodename The host name to be resolved. This can be a DNS name or an IP address in string format.
- * If `nodename` is `NULL`, the function will resolve the local host.
- * @param[in] servname The service name (e.g., "http") or port number to be resolved. If `servname` is `NULL`,
- * the function will resolve the port number or address without any service association.
- * @param[in] hints A pointer to a `struct musl_addrinfo` that provides hints for the address resolution.
- * It can be used to specify criteria such as the desired address family (IPv4 or IPv6),
- * socket type, protocol, and flags for resolution.
- * @param[out] res A pointer to a `struct musl_addrinfo` that will be filled with the resolved address
- * information. The resulting linked list will contain one or more `struct musl_sockaddr`
- * structures, each representing a different address that can be used for communication.
- *
- * @return sysret_t Returns `0` on success, indicating that the address resolution was successful.
- * On failure, returns a negative error code.
- *
- * @note The `res` parameter points to a linked list of resolved address structures. Each node in the list
- * contains a different resolved address and can be used for socket connection purposes.
- * It is important to free the memory allocated for the list after it is no longer needed, using `freeaddrinfo()`.
- *
- * @warning The `hints` structure allows you to specify various options for the resolution. However, incorrect
- * hints may lead to unexpected or incorrect results. For example, if you request IPv6 addresses but
- * the host only supports IPv4, the function may not return the expected results.
- *
- * @see freeaddrinfo(), sys_socket(), sys_connect(), sys_gethostbyname(), sys_gethostbyaddr()
- */
- sysret_t sys_getaddrinfo(const char *nodename,
- const char *servname,
- const struct musl_addrinfo *hints,
- struct musl_addrinfo *res)
- {
- int ret = -1;
- struct addrinfo *k_res = NULL;
- char *k_nodename = NULL;
- char *k_servname = NULL;
- struct addrinfo *k_hints = NULL;
- #ifdef ARCH_MM_MMU
- int len = 0;
- #endif
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)res, sizeof(*res)))
- {
- SET_ERRNO(EFAULT);
- goto exit;
- }
- #endif
- if (nodename)
- {
- #ifdef ARCH_MM_MMU
- len = lwp_user_strlen(nodename);
- if (len <= 0)
- {
- SET_ERRNO(EFAULT);
- goto exit;
- }
- k_nodename = (char *)kmem_get(len + 1);
- if (!k_nodename)
- {
- SET_ERRNO(ENOMEM);
- goto exit;
- }
- if (lwp_get_from_user(k_nodename, (void *)nodename, len + 1) != len + 1)
- {
- SET_ERRNO(EFAULT);
- goto exit;
- }
- #else
- k_nodename = rt_strdup(nodename);
- if (!k_nodename)
- {
- SET_ERRNO(ENOMEM);
- goto exit;
- }
- #endif
- }
- if (servname)
- {
- #ifdef ARCH_MM_MMU
- len = lwp_user_strlen(servname);
- if (len <= 0)
- {
- SET_ERRNO(EFAULT);
- goto exit;
- }
- k_servname = (char *)kmem_get(len + 1);
- if (!k_servname)
- {
- SET_ERRNO(ENOMEM);
- goto exit;
- }
- if (lwp_get_from_user(k_servname, (void *)servname, len + 1) < 0)
- {
- SET_ERRNO(EFAULT);
- goto exit;
- }
- #else
- k_servname = rt_strdup(servname);
- if (!k_servname)
- {
- SET_ERRNO(ENOMEM);
- goto exit;
- }
- #endif
- }
- if (hints)
- {
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)hints, sizeof(*hints)))
- {
- SET_ERRNO(EFAULT);
- goto exit;
- }
- #endif
- k_hints = (struct addrinfo *) rt_malloc(sizeof *hints);
- if (!k_hints)
- {
- SET_ERRNO(ENOMEM);
- goto exit;
- }
- rt_memset(k_hints, 0x0, sizeof(struct addrinfo));
- k_hints->ai_flags = hints->ai_flags;
- k_hints->ai_family = hints->ai_family;
- k_hints->ai_socktype = hints->ai_socktype;
- k_hints->ai_protocol = hints->ai_protocol;
- k_hints->ai_addrlen = hints->ai_addrlen;
- }
- ret = sal_getaddrinfo(k_nodename, k_servname, k_hints, &k_res);
- if (ret == 0)
- {
- /* set sockaddr */
- sockaddr_tomusl(k_res->ai_addr, res->ai_addr);
- res->ai_addrlen = k_res->ai_addrlen;
- /* set up addrinfo */
- res->ai_family = k_res->ai_family;
- res->ai_flags = k_res->ai_flags;
- res->ai_next = NULL;
- if (hints != NULL)
- {
- /* copy socktype & protocol from hints if specified */
- res->ai_socktype = hints->ai_socktype;
- res->ai_protocol = hints->ai_protocol;
- }
- sal_freeaddrinfo(k_res);
- k_res = NULL;
- }
- exit:
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- #ifdef ARCH_MM_MMU
- if (k_nodename)
- {
- kmem_put(k_nodename);
- }
- #else
- if (k_nodename)
- {
- rt_free(k_nodename);
- }
- #endif
- #ifdef ARCH_MM_MMU
- if (k_servname)
- {
- kmem_put(k_servname);
- }
- #else
- if (k_servname)
- {
- rt_free(k_servname);
- }
- #endif
- if (k_hints)
- {
- rt_free(k_hints);
- }
- return ret;
- }
- #define HOSTENT_BUFSZ 512
- /**
- * @brief Resolves a host name to an address, with support for specifying the address family.
- *
- * This function performs a lookup of the specified host name, and resolves it to an address,
- * while allowing the caller to specify the desired address family (e.g., IPv4 or IPv6). It is
- * a reentrant version of `gethostbyname2`, meaning it is safe for use in multi-threaded applications.
- * The results are returned in a user-provided buffer to avoid memory allocation overhead.
- *
- * @param[in] name The host name to be resolved. This can be a DNS name or an IP address in string format.
- * @param[in] af The address family to use for the resolution. Common values are:
- * - `AF_INET` for IPv4 addresses.
- * - `AF_INET6` for IPv6 addresses.
- * @param[out] ret A pointer to a `struct hostent` where the resolved host information will be stored.
- * This includes the host name, alias names, address type, and the address itself.
- * @param[in] buf A buffer to store additional information required for the `struct hostent` structure.
- * This is needed to ensure the reentrant behavior and avoid memory allocation.
- * @param[in] buflen The size of the buffer provided.
- * @param[out] result A pointer to a `struct hostent*` that will point to the resolved host entry.
- * This will be set to the value of `ret` upon success.
- * @param[out] err A pointer to an integer where error codes will be stored. If the function fails,
- * `err` will contain a non-zero value corresponding to the error.
- *
- * @return sysret_t Returns `0` on success, indicating the resolution was successful.
- * On failure, returns a negative error code that indicates the failure reason.
- *
- * @note This function is reentrant and thread-safe, meaning it does not use static memory or global state.
- * It relies on the buffers provided by the caller to store the resolved data.
- *
- * @see gethostbyname2(), sys_gethostbyname(), sys_socket(), sys_connect(), sys_getaddrinfo()
- */
- sysret_t sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
- char *buf, size_t buflen,
- struct hostent **result, int *err)
- {
- int ret_val = -1;
- int sal_ret = -1 , sal_err = -1;
- struct hostent sal_he, sal_tmp;
- struct hostent *sal_result = NULL;
- char *sal_buf = NULL;
- char *k_name = NULL;
- int len = 0;
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)err, sizeof(*err)))
- {
- SET_ERRNO(EFAULT);
- goto __exit;
- }
- if (!lwp_user_accessable((void *)result, sizeof(*result))
- || !lwp_user_accessable((void *)ret, sizeof(*ret))
- || !lwp_user_accessable((void *)buf, buflen))
- {
- /* not all arguments given */
- *err = EFAULT;
- SET_ERRNO(EFAULT);
- goto __exit;
- }
- len = lwp_user_strlen(name);
- if (len <= 0)
- {
- *err = EFAULT;
- SET_ERRNO(EFAULT);
- goto __exit;
- }
- k_name = (char *)kmem_get(len + 1);
- if (!k_name)
- {
- SET_ERRNO(ENOMEM);
- goto __exit;
- }
- if (lwp_get_from_user(k_name, (void *)name, len + 1) < 0)
- {
- SET_ERRNO(EFAULT);
- goto __exit;
- }
- #else
- k_name = rt_strdup(name);
- if (k_name == NULL)
- {
- SET_ERRNO(ENOMEM);
- goto __exit;
- }
- #endif
- *result = ret;
- sal_buf = (char *)malloc(HOSTENT_BUFSZ);
- if (sal_buf == NULL)
- {
- SET_ERRNO(ENOMEM);
- goto __exit;
- }
- /* get host by name in SAL */
- sal_ret = sal_gethostbyname_r(k_name, &sal_he, sal_buf, HOSTENT_BUFSZ, &sal_result, &sal_err);
- if (sal_ret == 0)
- {
- int index = 0, cnt = 0;
- char *ptr = buf;
- /* get counter */
- index = 0;
- while (sal_he.h_addr_list[index] != NULL)
- {
- index++;
- }
- cnt = index + 1;
- #ifdef ARCH_MM_MMU
- /* update user space hostent */
- lwp_put_to_user(buf, k_name, buflen - (ptr - buf));
- lwp_memcpy(&sal_tmp, &sal_he, sizeof(sal_he));
- sal_tmp.h_name = ptr;
- ptr += rt_strlen(k_name);
- sal_tmp.h_addr_list = (char**)ptr;
- ptr += cnt * sizeof(char *);
- index = 0;
- while (sal_he.h_addr_list[index] != NULL)
- {
- sal_tmp.h_addr_list[index] = ptr;
- lwp_memcpy(ptr, sal_he.h_addr_list[index], sal_he.h_length);
- ptr += sal_he.h_length;
- index++;
- }
- sal_tmp.h_addr_list[index] = NULL;
- lwp_put_to_user(ret, &sal_tmp, sizeof(sal_tmp));
- #else
- /* update user space hostent */
- ret->h_addrtype = sal_he.h_addrtype;
- ret->h_length = sal_he.h_length;
- rt_strncpy(ptr, k_name, buflen - (ptr - buf));
- ret->h_name = ptr;
- ptr += strlen(k_name);
- ret->h_addr_list = (char**)ptr;
- ptr += cnt * sizeof(char *);
- index = 0;
- while (sal_he.h_addr_list[index] != NULL)
- {
- ret->h_addr_list[index] = ptr;
- lwp_memcpy(ptr, sal_he.h_addr_list[index], sal_he.h_length);
- ptr += sal_he.h_length;
- index++;
- }
- ret->h_addr_list[index] = NULL;
- #endif
- ret_val = 0;
- }
- else
- {
- SET_ERRNO(EINVAL);
- }
- __exit:
- if (ret_val < 0)
- {
- ret_val = GET_ERRNO();
- }
- /* release buffer */
- if (sal_buf)
- {
- free(sal_buf);
- }
- #ifdef ARCH_MM_MMU
- if (k_name)
- {
- kmem_put(k_name);
- }
- #else
- if (k_name)
- {
- free(k_name);
- }
- #endif
- return ret_val;
- }
- #endif
- /**
- * @brief Gets the current working directory.
- *
- * This function retrieves the absolute pathname of the current working directory
- * and stores it in the provided buffer. The buffer must be large enough to hold
- * the directory path, including the null-terminator. If the buffer is too small,
- * the function will return an error.
- *
- * @param[out] buf A pointer to a buffer where the current working directory
- * path will be stored. The buffer should be large enough
- * to hold the path, including the null-terminator.
- * @param[in] size The size of the buffer in bytes. The buffer must be large enough
- * to accommodate the full path.
- *
- * @return long On success, returns the number of bytes written to the buffer
- * (not including the null-terminator). If the buffer is not large
- * enough, returns a negative error code.
- *
- * @note The maximum path length depends on the system's configuration.
- * Ensure the buffer size is sufficient to hold the entire path.
- *
- * @see sys_chdir(), sys_getcwd_r(), sys_realpath()
- */
- long sys_getcwd(char *buf, size_t size)
- {
- char *tmp = RT_NULL;
- long ret = -1;
- if (!lwp_user_accessable((void *)buf, size))
- {
- return ret;
- }
- tmp = (char *)rt_malloc(size);
- if (!tmp)
- {
- return ret;
- }
- if (getcwd(tmp, size) != RT_NULL)
- {
- if (lwp_put_to_user(buf, tmp, size) > 0)
- {
- if (buf != RT_NULL)
- ret = strlen(buf);
- else
- ret = -EFAULT;
- }
- }
- rt_free(tmp);
- return ret;
- }
- /**
- * @brief Changes the current working directory.
- *
- * This function changes the current working directory of the calling process
- * to the directory specified by the given path. The path can be absolute or
- * relative. If the specified path does not exist or the process does not have
- * sufficient permissions, the function will return an error.
- *
- * @param[in] path The path to the new working directory. This can be either
- * an absolute or a relative path.
- *
- * @return sysret_t Returns `0` on success, indicating that the working
- * directory was successfully changed. On failure, returns a
- * negative error code indicating the reason for failure.
- *
- * @note If the specified path is a relative path, it is interpreted relative
- * to the current working directory.
- *
- * @see sys_getcwd(), sys_chdir() for changing directories, sys_opendir(), sys_stat()
- */
- sysret_t sys_chdir(const char *path)
- {
- #ifdef ARCH_MM_MMU
- int err = 0;
- int len = 0;
- int errcode;
- char *kpath = RT_NULL;
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kpath = (char *)kmem_get(len + 1);
- if (!kpath)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kpath, (void *)path, len + 1) != (len + 1))
- {
- kmem_put(kpath);
- return -EINVAL;
- }
- err = chdir(kpath);
- errcode = err != 0 ? GET_ERRNO() : 0;
- kmem_put(kpath);
- return errcode;
- #else
- int ret = chdir(path);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Changes the current working directory to the one associated with the specified file descriptor.
- *
- * This function changes the current working directory of the calling process
- * to the directory associated with the file descriptor `fd`. The file descriptor
- * should refer to an open directory. If the file descriptor does not refer to a
- * directory, or if the process lacks the necessary permissions, the function will
- * return an error.
- *
- * @param[in] fd The file descriptor referring to the directory to which the current
- * working directory should be changed.
- *
- * @return sysret_t Returns `0` on success, indicating the current working directory
- * was successfully changed. On failure, returns a negative error code.
- *
- * @note The file descriptor must refer to a directory. If it refers to a file or other
- * non-directory object, the operation will fail.
- *
- * @see sys_chdir(), sys_getcwd(), sys_opendir(), sys_open()
- */
- sysret_t sys_fchdir(int fd)
- {
- int errcode = -ENOSYS;
- #ifdef ARCH_MM_MMU
- #ifdef RT_USING_DFS_V2
- int err = -1;
- struct dfs_file *d;
- char *kpath;
- d = fd_get(fd);
- if (!d || !d->vnode)
- {
- return -EBADF;
- }
- kpath = dfs_dentry_full_path(d->dentry);
- if (!kpath)
- {
- return -EACCES;
- }
- err = chdir(kpath);
- errcode = err != 0 ? GET_ERRNO() : 0;
- kmem_put(kpath);
- #endif
- #endif
- return errcode;
- }
- /**
- * @brief Creates a new directory with the specified path and mode.
- *
- * This function creates a new directory with the specified path and mode.
- * The directory is created with the permissions specified by the `mode` parameter.
- * If the directory already exists, the function will return an error.
- *
- * @param[in] path The path of the directory to be created. This can be an absolute
- * or relative path. If the directory does not exist, it will be created.
- * @param[in] mode The permissions to be set for the new directory. This parameter
- * specifies the access permissions for the directory owner, group, and others.
- *
- * @return sysret_t Returns `0` on success, indicating that the directory was successfully
- * created. On failure, returns a negative error code indicating the reason for failure.
- *
- * @note The `mode` parameter specifies the permissions for the new directory. The permissions
- * are typically specified using the `S_IRWXU`, `S_IRWXG`, and `S_IRWXO` macros, which
- * define the read, write, and execute permissions for the owner, group, and others.
- *
- * @see sys_rmdir(), sys_chdir(), sys_mkdirat()
- */
- sysret_t sys_mkdir(const char *path, mode_t mode)
- {
- #ifdef ARCH_MM_MMU
- int err = 0;
- int len = 0;
- char *kpath = RT_NULL;
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kpath = (char *)kmem_get(len + 1);
- if (!kpath)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kpath, (void *)path, len + 1) != (len + 1))
- {
- kmem_put(kpath);
- return -EINVAL;
- }
- err = _SYS_WRAP(mkdir(kpath, mode));
- kmem_put(kpath);
- return err;
- #else
- int ret = mkdir(path, mode);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Removes the specified directory.
- *
- * This function removes the directory specified by the given path. The directory
- * must be empty for the operation to succeed. If the directory is not empty, the
- * function will return an error. If the directory does not exist or the process
- * lacks the necessary permissions, the function will also return an error.
- *
- * @param[in] path The path of the directory to be removed. This can be an absolute
- * or relative path. The directory must be empty for the operation to succeed.
- *
- * @return sysret_t Returns `0` on success, indicating that the directory was successfully
- * removed. On failure, returns a negative error code indicating the reason for failure.
- *
- * @note The directory must be empty for the operation to succeed. If the directory contains
- * files or subdirectories, the operation will fail. To remove a non-empty directory,
- * the contents must be deleted first.
- *
- * @see sys_mkdir(), sys_chdir(), sys_rmdirat()
- */
- sysret_t sys_rmdir(const char *path)
- {
- int err = 0;
- int ret = 0;
- #ifdef ARCH_MM_MMU
- int len = 0;
- char *kpath = RT_NULL;
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kpath = (char *)kmem_get(len + 1);
- if (!kpath)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kpath, (void *)path, len + 1) != (len + 1))
- {
- kmem_put(kpath);
- return -EINVAL;
- }
- ret = rmdir(kpath);
- if(ret < 0)
- {
- err = GET_ERRNO();
- }
- kmem_put(kpath);
- return (err < 0 ? err : ret);
- #else
- ret = rmdir(path);
- if(ret < 0)
- {
- err = GET_ERRNO();
- }
- return (err < 0 ? err : ret);
- #endif
- }
- /**
- * @brief Reads directory entries.
- *
- * This function reads the directory entries from the directory stream specified by the file descriptor `fd`.
- * It stores the directory entries in the buffer pointed to by `dirp`, up to the specified number of bytes (`nbytes`).
- * The entries are returned in a format compatible with the `struct libc_dirent` structure.
- *
- * @param[in] fd The file descriptor referring to an open directory. This descriptor must be obtained
- * from a call to `sys_open()` with the appropriate flags for directory reading.
- * @param[out] dirp A pointer to a buffer where the directory entries will be stored.
- * The buffer must be large enough to hold at least `nbytes` bytes of directory entries.
- * @param[in] nbytes The size of the buffer (`dirp`) in bytes. It limits the number of directory entries
- * that can be read in a single call. The function will return as many entries as possible
- * that fit within the buffer size.
- *
- * @return sysret_t Returns the number of bytes read on success, which may be less than `nbytes` if there
- * are fewer entries in the directory or if the buffer is too small.
- * On failure, returns a negative error code.
- *
- * @note If the function returns 0, it indicates the end of the directory stream. A negative return value
- * indicates an error. The caller can use the returned number of bytes to process the entries in `dirp`.
- *
- * @see sys_open(), sys_close(), sys_readdir(), sys_stat()
- */
- sysret_t sys_getdents(int fd, struct libc_dirent *dirp, size_t nbytes)
- {
- int ret = -1;
- struct dfs_file *file;
- size_t cnt = (nbytes / sizeof(struct libc_dirent));
- size_t rtt_nbytes = 0;
- struct dirent *rtt_dirp;
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)dirp, sizeof(struct libc_dirent)))
- {
- return -EFAULT;
- }
- #endif
- if (cnt == 0)
- {
- return -EINVAL;
- }
- rtt_nbytes = cnt * sizeof(struct dirent);
- rtt_dirp = (struct dirent *)rt_malloc(rtt_nbytes);
- if (!rtt_dirp)
- {
- return -ENOMEM;
- }
- file = fd_get(fd);
- ret = dfs_file_getdents(file, rtt_dirp, rtt_nbytes);
- if (ret > 0)
- {
- size_t i = 0;
- cnt = ret / sizeof(struct dirent);
- for (i = 0; i < cnt; i++)
- {
- dirp[i].d_ino = 0;
- dirp[i].d_off = i*sizeof(struct libc_dirent);
- dirp[i].d_type = rtt_dirp[i].d_type;
- dirp[i].d_reclen = sizeof(struct libc_dirent);
- strcpy(dirp[i].d_name, rtt_dirp[i].d_name);
- }
- ret = cnt * sizeof(struct libc_dirent);
- }
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- rt_free(rtt_dirp);
- return ret;
- }
- /**
- * @brief Retrieves the current value of the error code.
- *
- * This function returns the most recent error code set by a system call. The error code is typically set
- * when a system call fails. This function allows users to retrieve the last error that occurred, helping to
- * diagnose issues or handle errors in a more controlled manner.
- *
- * @return sysret_t The current error code. A value of `0` indicates no error, while a non-zero value
- * represents the most recent error. The error codes are system-specific and can
- * represent various failure conditions (e.g., `EINVAL`, `ENOMEM`, `EIO`).
- *
- * @note The error code returned is specific to the current thread or process and is typically updated
- * each time a system call fails. The error code is persistent until it is overwritten by the next
- * failed system call or explicitly reset.
- *
- * @see sys_set_errno(), sys_perror(), sys_strerror()
- */
- sysret_t sys_get_errno(void)
- {
- return rt_get_errno();
- }
- #ifdef ARCH_MM_MMU
- /**
- * @brief Sets the thread-specific data area.
- *
- * This function is used to associate a specific area of memory with the current thread. The area pointed to
- * by `p` is set as the thread's local storage. Thread-specific data is used to store data that is unique to
- * each thread, allowing different threads to maintain independent state information.
- *
- * @param[in] p A pointer to the memory area that is to be set as the thread's local storage. This area
- * will be used by the thread to store its specific data. The structure and size of the data
- * area depend on the implementation and use case.
- *
- * @return sysret_t Returns `0` on success. On failure, it returns a negative error code.
- *
- * @note This function is typically used to set up thread-specific storage for managing data that should
- * not be shared between threads. The data area is accessible only by the thread that set it, ensuring
- * thread safety for the stored information.
- *
- * @see sys_get_thread_area(), sys_thread_create(), sys_thread_self()
- */
- sysret_t sys_set_thread_area(void *p)
- {
- rt_thread_t thread;
- thread = rt_thread_self();
- thread->thread_idr = p;
- arch_set_thread_area(p);
- return 0;
- }
- /**
- * @brief Sets the address at which the thread ID is stored.
- *
- * This function sets the address of a variable that will store the thread ID for the calling thread.
- * The specified address `tidptr` will hold the thread's unique identifier. This can be useful for
- * managing thread-specific state or for synchronization mechanisms where the thread's ID needs to be
- * shared or checked by other parts of the system.
- *
- * @param[in] tidptr A pointer to an integer where the thread ID will be stored. This value will
- * hold the calling thread's ID, and it can be accessed to identify the thread
- * later. The value of the thread ID can be used in various thread management
- * operations.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function is typically used in systems that require associating a specific address with the
- * thread ID, often in real-time or embedded systems where managing and accessing thread IDs is
- * crucial for scheduling or resource allocation.
- *
- * @see sys_get_tid(), sys_thread_self(), sys_thread_create()
- */
- sysret_t sys_set_tid_address(int *tidptr)
- {
- rt_thread_t thread;
- #ifdef ARCH_MM_MMU
- if (!lwp_user_accessable((void *)tidptr, sizeof(int)))
- {
- return -EFAULT;
- }
- #endif
- thread = rt_thread_self();
- thread->clear_child_tid = tidptr;
- return thread->tid;
- }
- #endif /* ARCH_MM_MMU */
- /**
- * @brief Gets the thread ID of the calling thread.
- *
- * This function returns the unique thread identifier (thread ID) for the calling thread. The thread ID
- * can be used to uniquely identify the thread within the system and is typically used for debugging,
- * thread management, or scheduling purposes.
- *
- * @return sysret_t The thread ID of the calling thread. The value is typically a positive integer
- * representing the unique ID assigned to the thread. In case of failure, an error code
- * may be returned.
- *
- * @note The thread ID returned by this function is unique within the system, and it may be used to
- * reference or manipulate the specific thread associated with the ID.
- *
- * @see sys_set_tid_address(), sys_thread_self(), sys_thread_create()
- */
- sysret_t sys_gettid(void)
- {
- return rt_thread_self()->tid;
- }
- /**
- * @brief Checks the accessibility of a file or directory.
- *
- * This function checks whether the calling process has the specified access rights for the given file or directory.
- * The check is performed based on the provided `mode`, which can indicate whether read, write, or execute permissions
- * are required.
- *
- * @param[in] filename The path to the file or directory whose accessibility is being checked.
- * @param[in] mode The access mode to check for. This can be a combination of the following:
- * - `R_OK`: Check for read permission.
- * - `W_OK`: Check for write permission.
- * - `X_OK`: Check for execute permission.
- * - `F_OK`: Check if the file exists.
- *
- * @return sysret_t Returns `0` if the specified access is allowed. On failure, returns a negative error code.
- *
- * @note This function does not modify the file or directory, it only checks if the specified access rights are granted.
- *
- * @see sys_open(), sys_stat(), sys_fstat(), sys_chmod(), sys_chown()
- */
- sysret_t sys_access(const char *filename, int mode)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- rt_size_t len = 0;
- char *kfilename = RT_NULL;
- len = lwp_user_strlen(filename);
- if (len <= 0)
- {
- return -EINVAL;
- }
- kfilename = (char *)kmem_get(len + 1);
- if (!kfilename)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kfilename, (void *)filename, len + 1) != (len + 1))
- {
- kmem_put(kfilename);
- return -EFAULT;
- }
- ret = access(kfilename, mode);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kfilename);
- return ret;
- #else
- ret = access(filename, mode);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Creates a pipe, a unidirectional data channel.
- *
- * This function creates a pipe, which is a unidirectional data channel used for inter-process communication.
- * The pipe consists of two file descriptors: one for reading from the pipe and one for writing to the pipe.
- * The pipe is used for passing data between processes or threads, typically in a producer-consumer scenario.
- *
- * @param[out] fd An array of two integers where the file descriptors for the read and write ends of the pipe will be stored.
- * - `fd[0]`: The file descriptor for reading from the pipe.
- * - `fd[1]`: The file descriptor for writing to the pipe.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The pipe created by this function is typically used for simple communication between processes or threads.
- * The data written to `fd[1]` can be read from `fd[0]`. After usage, both file descriptors should be closed.
- *
- * @see sys_read(), sys_write(), sys_close(), sys_fork(), sys_execve()
- */
- sysret_t sys_pipe(int fd[2])
- {
- int ret;
- int kfd[2] = {0, 0};
- if (!lwp_user_accessable((void *)fd, sizeof(int[2])))
- {
- return -EFAULT;
- }
- ret = pipe(kfd);
- lwp_put_to_user((void *)fd, kfd, sizeof(int[2]));
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Waits for a process to change state.
- *
- * This function suspends the execution of the calling process until one of its child processes terminates
- * or a specified process (identified by `pid`) changes its state. The function returns the process ID of the child
- * process that terminated, and provides information about its exit status and resource usage.
- *
- * @param[in] pid The process ID of the child process to wait for. The behavior of this parameter can be one of the following:
- * - `pid > 0`: Wait for the child process with the specified PID.
- * - `pid == 0`: Wait for any child process in the same process group.
- * - `pid == -1`: Wait for any child process (default behavior).
- * - `pid < -1`: Wait for any child process in the specified process group.
- *
- * @param[out] status A pointer to an integer where the exit status of the terminated child process will be stored.
- * This status can be interpreted using macros such as `WIFEXITED` or `WIFSIGNALED`.
- *
- * @param[in] options Options for the wait operation, which can include:
- * - `WNOHANG`: Return immediately if no child has exited.
- * - `WUNTRACED`: Return if a child has stopped, but not yet terminated.
- *
- * @param[out] ru A pointer to a `struct rusage` where resource usage information of the child process will be stored.
- * This includes information such as CPU time consumed by the child process.
- *
- * @return sysret_t Returns the process ID of the terminated child on success. In case of failure, a negative error code is returned.
- *
- * @note This function is useful for monitoring and cleaning up child processes in parent-child relationships.
- * The `status` value can be further analyzed to determine if the child process terminated normally or due to a signal.
- *
- * @see sys_waitpid(), sys_fork(), sys_exit()
- */
- sysret_t sys_wait4(pid_t pid, int *status, int options, struct rusage *ru)
- {
- return lwp_waitpid(pid, status, options, ru);
- }
- /**
- * @brief Sets the time of a specified clock.
- *
- * This function sets the time of the specified clock (identified by `clk`) to the given value. The time is provided
- * as a `struct timespec` containing seconds and nanoseconds. This function can be used to set the system clock or
- * other specific clocks, such as monotonic or real-time clocks.
- *
- * @param[in] clk The clock ID for which to set the time. The clock can be one of the following:
- * - `CLOCK_REALTIME`: Set the system's real-time clock.
- * - `CLOCK_MONOTONIC`: Set the monotonic clock, which measures time since some unspecified starting point.
- * - `CLOCK_PROCESS_CPUTIME_ID`: Set the CPU time used by the process.
- * - `CLOCK_THREAD_CPUTIME_ID`: Set the CPU time used by the current thread.
- *
- * @param[in] ts A pointer to a `struct timespec` containing the new time to set for the specified clock.
- * - `ts->tv_sec`: Seconds since the epoch (for `CLOCK_REALTIME`) or since some unspecified start point (for other clocks).
- * - `ts->tv_nsec`: Nanoseconds within the current second.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function requires appropriate permissions for setting the system's clock. In some systems, only privileged users
- * may change the `CLOCK_REALTIME` clock.
- *
- * @see sys_clock_gettime(), sys_clock_getres()
- */
- sysret_t sys_clock_settime(clockid_t clk, const struct timespec *ts)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- size_t size = sizeof(struct timespec);
- struct timespec *kts = NULL;
- if (!lwp_user_accessable((void *)ts, size))
- {
- return -EFAULT;
- }
- kts = kmem_get(size);
- if (!kts)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kts, (void *)ts, size);
- ret = clock_settime(clk, kts);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kts);
- return ret;
- #else
- if (!lwp_user_accessable((void *)ts, sizeof(struct timespec)))
- {
- return -EFAULT;
- }
- ret = clock_settime(clk, ts);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Retrieves the current time of a specified clock.
- *
- * This function retrieves the current time of the specified clock (identified by `clk`) and stores it in the
- * `struct timespec` pointed to by `ts`. The time is expressed in seconds and nanoseconds. The clock can be
- * one of several types, such as real-time, monotonic, or process-specific clocks.
- *
- * @param[in] clk The clock ID for which to get the time. The clock can be one of the following:
- * - `CLOCK_REALTIME`: Get the system's real-time clock.
- * - `CLOCK_MONOTONIC`: Get the monotonic clock, which measures time since some unspecified starting point.
- * - `CLOCK_PROCESS_CPUTIME_ID`: Get the CPU time used by the process.
- * - `CLOCK_THREAD_CPUTIME_ID`: Get the CPU time used by the current thread.
- *
- * @param[out] ts A pointer to a `struct timespec` where the current time for the specified clock will be stored.
- * - `ts->tv_sec`: Seconds since the epoch (for `CLOCK_REALTIME`) or since some unspecified start point (for other clocks).
- * - `ts->tv_nsec`: Nanoseconds within the current second.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function requires appropriate permissions for retrieving certain clocks (e.g., `CLOCK_REALTIME`).
- *
- * @see sys_clock_settime(), sys_clock_getres()
- */
- sysret_t sys_clock_gettime(clockid_t clk, struct timespec *ts)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- size_t size = sizeof(struct timespec);
- struct timespec *kts = NULL;
- if (!lwp_user_accessable((void *)ts, size))
- {
- return -EFAULT;
- }
- kts = kmem_get(size);
- if (!kts)
- {
- return -ENOMEM;
- }
- ret = clock_gettime(clk, kts);
- if (ret != -1)
- lwp_put_to_user(ts, kts, size);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kts);
- return ret;
- #else
- if (!lwp_user_accessable((void *)ts, sizeof(struct timespec)))
- {
- return -EFAULT;
- }
- ret = clock_gettime(clk, ts);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Suspends the execution of the calling thread for the specified time duration.
- *
- * This function causes the calling thread to sleep for the specified time duration, which is provided as a
- * `struct timespec` containing seconds and nanoseconds. The sleep is done based on the specified clock (identified by `clk`).
- * If the `flags` parameter is set to `TIMER_ABSTIME`, the specified time represents an absolute time, otherwise,
- * it represents a relative time interval.
- *
- * @param[in] clk The clock ID for which to perform the sleep. The clock can be one of the following:
- * - `CLOCK_REALTIME`: Use the system's real-time clock.
- * - `CLOCK_MONOTONIC`: Use the monotonic clock, which measures time since some unspecified starting point.
- * - `CLOCK_PROCESS_CPUTIME_ID`: Use the CPU time used by the process.
- * - `CLOCK_THREAD_CPUTIME_ID`: Use the CPU time used by the current thread.
- *
- * @param[in] flags The sleep behavior flags. The possible flags are:
- * - `0`: The sleep duration is relative to the current time.
- * - `TIMER_ABSTIME`: The sleep duration is absolute (measured from the specified clock).
- *
- * @param[in] rqtp A pointer to a `struct timespec` containing the requested sleep time.
- * - `rqtp->tv_sec`: Seconds to sleep.
- * - `rqtp->tv_nsec`: Nanoseconds to sleep (0 ≤ `rqtp->tv_nsec` < 1 billion).
- *
- * @param[out] rmtp A pointer to a `struct timespec` where the remaining time will be stored if the sleep is interrupted.
- * If the sleep completes successfully, `rmtp` will not be modified.
- * - `rmtp->tv_sec`: Remaining seconds.
- * - `rmtp->tv_nsec`: Remaining nanoseconds.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function can be interrupted by signals. In that case, the remaining time is returned in `rmtp`.
- * If the sleep is not interrupted, the function returns `SYSRET_OK` when the requested time has passed.
- *
- * @see sys_clock_gettime(), sys_clock_settime(), sys_nanosleep()
- */
- sysret_t sys_clock_nanosleep(clockid_t clk, int flags, const struct timespec *rqtp, struct timespec *rmtp)
- {
- int ret = 0;
- LOG_D("sys_nanosleep\n");
- if (!lwp_user_accessable((void *)rqtp, sizeof *rqtp))
- return -EFAULT;
- #ifdef ARCH_MM_MMU
- struct timespec rqtp_k;
- struct timespec rmtp_k;
- lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
- ret = clock_nanosleep(clk, flags, &rqtp_k, &rmtp_k);
- if ((ret != -1 || rt_get_errno() == EINTR) && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
- {
- lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
- if(ret != 0)
- return -EINTR;
- }
- #else
- if (rmtp)
- {
- if (!lwp_user_accessable((void *)rmtp, sizeof *rmtp))
- return -EFAULT;
- ret = clock_nanosleep(clk, flags, rqtp, rmtp);
- }
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Get the resolution of the specified clock.
- *
- * This function retrieves the resolution of the specified clock, which is the smallest time interval that the clock can measure.
- * The resolution is returned in a `struct timespec` which contains seconds and nanoseconds.
- *
- * @param[in] clk The clock ID for which to get the resolution. The clock can be one of the following:
- * - `CLOCK_REALTIME`: System's real-time clock.
- * - `CLOCK_MONOTONIC`: Monotonic clock (measures time since an unspecified point).
- * - `CLOCK_PROCESS_CPUTIME_ID`: CPU time consumed by the current process.
- * - `CLOCK_THREAD_CPUTIME_ID`: CPU time consumed by the current thread.
- *
- * @param[out] ts A pointer to a `struct timespec` where the clock's resolution will be stored.
- * - `ts->tv_sec`: The number of seconds in the resolution.
- * - `ts->tv_nsec`: The number of nanoseconds in the resolution (0 ≤ `ts->tv_nsec` < 1 billion).
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The resolution may be zero for some clocks, depending on the system's configuration.
- * A clock's resolution determines the smallest unit of time the clock can measure.
- *
- * @see sys_clock_gettime(), sys_clock_settime(), sys_clock_nanosleep()
- */
- sysret_t sys_clock_getres(clockid_t clk, struct timespec *ts)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- struct timespec kts;
- size_t size = sizeof(struct timespec);
- if (!lwp_user_accessable((void *)ts, size))
- {
- return -EFAULT;
- }
- ret = clock_getres(clk, &kts);
- if (ret != -1)
- lwp_put_to_user(ts, &kts, size);
- #else
- if (!lwp_user_accessable((void *)ts, sizeof(struct timespec)))
- {
- return -EFAULT;
- }
- ret = clock_getres(clk, ts);
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Rename or move a file or directory.
- *
- * This function renames or moves a file or directory from `oldpath` to `newpath`.
- * If the `newpath` exists, it may be overwritten depending on the system's file system behavior and
- * the permissions of the files involved.
- *
- * @param[in] oldpath The current path of the file or directory to rename or move.
- * @param[in] newpath The new path or name to which the file or directory should be renamed or moved.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note If `oldpath` and `newpath` refer to different file systems, the behavior may vary,
- * as the operation might involve copying and removing files instead of simply renaming them.
- * The success of the operation also depends on the permissions of the source and destination.
- *
- * @see sys_unlink(), sys_mkdir(), sys_access()
- */
- sysret_t sys_rename(const char *oldpath, const char *newpath)
- {
- int ret = -1;
- #ifdef ARCH_MM_MMU
- int err;
- err = lwp_user_strlen(oldpath);
- if (err <= 0)
- {
- return -EFAULT;
- }
- err = lwp_user_strlen(newpath);
- if (err <= 0)
- {
- return -EFAULT;
- }
- #endif
- ret = rename(oldpath, newpath);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- typedef unsigned long long rlim_t;
- struct rlimit {
- rlim_t rlim_cur;
- rlim_t rlim_max;
- };
- #define RLIMIT_CPU 0
- #define RLIMIT_FSIZE 1
- #define RLIMIT_DATA 2
- #define RLIMIT_STACK 3
- #define RLIMIT_CORE 4
- #define RLIMIT_RSS 5
- #define RLIMIT_NPROC 6
- #define RLIMIT_NOFILE 7
- #define RLIMIT_MEMLOCK 8
- #define RLIMIT_AS 9
- sysret_t sys_prlimit64(pid_t pid,
- unsigned int resource,
- const struct rlimit *new_rlim,
- struct rlimit *old_rlim)
- {
- return -ENOSYS;
- }
- /**
- * @brief Get resource limits.
- *
- * This function retrieves the current resource limits for the specified resource type.
- * The resource limit specifies the maximum value for a particular resource that a process or thread can use.
- * The limits are returned in an array `rlim` where:
- * - `rlim[0]` represents the soft limit (the current value).
- * - `rlim[1]` represents the hard limit (the maximum allowable value).
- *
- * @param[in] resource The resource for which to get the limits. It can be one of the following:
- * - `RLIMIT_NOFILE`: Maximum number of file descriptors.
- *
- * @param[out] rlim An array to store the resource limits. The array should have at least 2 elements:
- * - `rlim[0]`: The soft limit for the resource.
- * - `rlim[1]`: The hard limit for the resource.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The limits returned by `sys_getrlimit` are subject to system constraints and may vary across different systems.
- *
- * @see sys_setrlimit(), sys_getrlimit64(), sys_getrusage()
- */
- sysret_t sys_getrlimit(unsigned int resource, unsigned long rlim[2])
- {
- int ret = -1;
- unsigned long krlim[2] = {0, 0};
- if (!lwp_user_accessable((void *)rlim, sizeof(unsigned long [2])))
- {
- return -EFAULT;
- }
- if (lwp_get_from_user(krlim, rlim, sizeof(unsigned long [2])) != sizeof(unsigned long [2]))
- {
- return -EINVAL;
- }
- switch (resource)
- {
- case RLIMIT_NOFILE:
- {
- struct dfs_fdtable *fdt = dfs_fdtable_get();
- dfs_file_lock();
- krlim[0] = fdt->maxfd;
- dfs_file_unlock();
- krlim[1] = DFS_FD_MAX;
- ret = 0;
- }
- break;
- default:
- return -EINVAL;
- break;
- }
- lwp_put_to_user((void *)rlim, krlim, sizeof(unsigned long [2]));
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- sysret_t sys_setrlimit(unsigned int resource, struct rlimit *rlim)
- {
- return -ENOSYS;
- }
- /**
- * @brief Get random data from the kernel's random number generator.
- *
- * This function retrieves cryptographically secure random data from the kernel's random number generator
- * and stores it in the buffer provided by the user. The data can be used for cryptographic operations or
- * other applications requiring randomization.
- *
- * @param[out] buf A pointer to the buffer where the random data will be stored. The buffer must be large
- * enough to hold the requested amount of random data.
- * @param[in] buflen The number of bytes of random data to retrieve. This value must be a positive integer.
- * @param[in] flags Optional flags to modify the behavior of the random data retrieval. Possible values may include:
- * - `GRND_RANDOM`: Requests random data from the system's non-blocking random source.
- * - `GRND_NONBLOCK`: Instructs the function to return immediately even if insufficient entropy is available.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note
- * - If the `GRND_NONBLOCK` flag is not set and there is insufficient entropy in the system's random pool,
- * this function may block until enough entropy is available.
- * - The function returns cryptographically secure random data, suitable for use in secure applications.
- *
- * @see sys_random(), sys_getentropy()
- */
- sysret_t sys_getrandom(void *buf, size_t buflen, unsigned int flags)
- {
- int ret = -1;
- int count = 0;
- void *kmem = RT_NULL;
- rt_device_t rd_dev = RT_NULL;
- if (flags & GRND_RANDOM)
- rd_dev = rt_device_find("random");
- else
- rd_dev = rt_device_find("urandom");
- if (rd_dev == RT_NULL)
- {
- return -EFAULT;
- }
- if (rt_device_open(rd_dev, RT_DEVICE_OFLAG_RDONLY) != RT_EOK)
- {
- return -EFAULT;
- }
- if (!lwp_user_accessable(buf, buflen))
- {
- rt_device_close(rd_dev);
- return -EFAULT;
- }
- #ifdef ARCH_MM_MMU
- kmem = kmem_get(buflen);
- if (!kmem)
- {
- rt_device_close(rd_dev);
- return -ENOMEM;
- }
- while (count < buflen)
- {
- ret = rt_device_read(rd_dev, count, (char *)kmem + count, buflen - count);
- if (ret <= 0)
- break;
- count += ret;
- }
- rt_device_close(rd_dev);
- ret = count;
- if (count > 0)
- {
- ret = lwp_put_to_user(buf, kmem, count);
- }
- kmem_put(kmem);
- #else
- while (count < buflen)
- {
- ret = rt_device_read(rd_dev, count, (char *)kmem + count, buflen - count);
- if (ret <= 0)
- break;
- count += ret;
- }
- rt_device_close(rd_dev);
- ret = count;
- #endif
- return ret;
- }
- /**
- * @brief Read the value of a symbolic link.
- *
- * This function reads the value of a symbolic link and stores it in the provided buffer. The value is the
- * path to which the symbolic link points. If the symbolic link is too long to fit in the provided buffer,
- * the function returns the number of bytes needed to store the entire path (not including the terminating null byte).
- *
- * @param[in] path The path of the symbolic link to read.
- * @param[out] buf A buffer where the symbolic link's target will be stored. The buffer must be large enough
- * to hold the path of the symbolic link.
- * @param[in] bufsz The size of the buffer `buf`. It specifies the maximum number of bytes to read.
- *
- * @return ssize_t The number of bytes written to `buf` (excluding the terminating null byte) on success.
- * On failure, it returns a negative error code:
- * - `-EINVAL`: Invalid path.
- * - `-ENOMEM`: Insufficient memory to read the link.
- * - `-EFAULT`: Invalid address for the `buf`.
- *
- * @note It will (silently) truncate the contents(to a length of bufsiz characters),
- * in case the buffer is too small to hold all of the contents.
- *
- * @see sys_symlink(), sys_lstat()
- */
- ssize_t sys_readlink(char* path, char *buf, size_t bufsz)
- {
- size_t len, copy_len;
- int err, rtn;
- char *copy_path;
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- if (!lwp_user_accessable(buf, bufsz))
- {
- return -EINVAL;
- }
- copy_path = (char*)rt_malloc(len + 1);
- if (!copy_path)
- {
- return -ENOMEM;
- }
- copy_len = lwp_get_from_user(copy_path, path, len);
- copy_path[copy_len] = '\0';
- char *link_fn = (char *)rt_malloc(DFS_PATH_MAX);
- if (link_fn)
- {
- err = dfs_file_readlink(copy_path, link_fn, DFS_PATH_MAX);
- if (err > 0)
- {
- buf[bufsz > err ? err : bufsz] = '\0';
- rtn = lwp_put_to_user(buf, link_fn, bufsz > err ? err : bufsz);
- }
- else
- {
- rtn = -EIO;
- }
- rt_free(link_fn);
- }
- else
- {
- rtn = -ENOMEM;
- }
- rt_free(copy_path);
- return rtn;
- }
- /**
- * @brief Set the CPU affinity mask of a process.
- *
- * This function sets the CPU affinity mask for a specified process. The affinity mask determines which CPUs the
- * process is allowed to execute on. The process will be restricted to the CPUs specified in the mask.
- *
- * @param[in] pid The process ID of the process whose CPU affinity is to be set. If the `pid` is `0`, the
- * affinity of the calling process will be modified.
- * @param[in] size The size (in bytes) of the CPU set, typically `sizeof(cpu_set_t)`.
- * @param[in] set A pointer to the CPU set. The CPU set is a bitmask representing which CPUs the process
- * is allowed to run on. The bitmask must have enough bits to cover the number of CPUs on the system.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The CPU set is represented as a bitmask where each bit corresponds to a CPU. If the bit is set, the process
- * can execute on that CPU. The number of CPUs is platform-dependent, and the size of `set` must be large enough
- * to hold a bit for each CPU.
- *
- * @see sys_sched_getaffinity(), sys_setcpu()
- */
- sysret_t sys_sched_setaffinity(pid_t pid, size_t size, void *set)
- {
- void *kset = RT_NULL;
- if (size <= 0 || size > sizeof(cpu_set_t))
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)set, size))
- return -EFAULT;
- kset = kmem_get(size);
- if (kset == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kset, set, size) != size)
- {
- kmem_put(kset);
- return -EINVAL;
- }
- for (int i = 0;i < size * 8; i++)
- {
- if (CPU_ISSET_S(i, size, kset))
- {
- kmem_put(kset);
- /**
- * yes it's tricky.
- * But when we talk about 'pid' from GNU libc, it's the 'task-id'
- * aka 'thread->tid' known in kernel.
- */
- return lwp_setaffinity(pid, i);
- }
- }
- kmem_put(kset);
- return -1;
- }
- /**
- * @brief Get the CPU affinity mask of a process.
- *
- * This function retrieves the CPU affinity mask for a specified process. The affinity mask indicates which CPUs the
- * process is allowed to execute on. The process can run on any of the CPUs represented by the bits set in the mask.
- *
- * @param[in] pid The process ID of the process whose CPU affinity is to be retrieved. If `pid` is `0`, the
- * affinity mask of the calling process will be retrieved.
- * @param[in] size The size (in bytes) of the CPU set, typically `sizeof(cpu_set_t)`.
- * @param[out] set A pointer to a buffer where the CPU affinity mask will be stored. The mask is represented
- * as a bitmask, where each bit corresponds to a CPU. The bit is set if the process can run on that CPU.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The CPU set is represented as a bitmask where each bit corresponds to a CPU. If the bit is set, the process
- * can execute on that CPU. The number of CPUs is platform-dependent, and the size of `set` must be large enough
- * to hold a bit for each CPU.
- *
- * @see sys_sched_setaffinity(), sys_getcpu()
- */
- sysret_t sys_sched_getaffinity(const pid_t pid, size_t size, void *set)
- {
- #ifdef ARCH_MM_MMU
- LWP_DEF_RETURN_CODE(rc);
- void *mask;
- struct rt_lwp *lwp;
- if (size <= 0 || size > sizeof(cpu_set_t))
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable(set, size))
- {
- return -EFAULT;
- }
- mask = kmem_get(size);
- if (!mask)
- {
- return -ENOMEM;
- }
- CPU_ZERO_S(size, mask);
- lwp_pid_lock_take();
- lwp = lwp_from_pid_locked(pid);
- if (!lwp)
- {
- rc = -ESRCH;
- }
- else
- {
- #ifdef RT_USING_SMP
- if (lwp->bind_cpu == RT_CPUS_NR) /* not bind */
- {
- for(int i = 0; i < RT_CPUS_NR; i++)
- {
- CPU_SET_S(i, size, mask);
- }
- }
- else /* set bind cpu */
- {
- /* TODO: only single-core bindings are now supported of rt-smart */
- CPU_SET_S(lwp->bind_cpu, size, mask);
- }
- #else
- CPU_SET_S(0, size, mask);
- #endif
- if (lwp_put_to_user(set, mask, size) != size)
- rc = -EFAULT;
- else
- rc = size;
- }
- lwp_pid_lock_release();
- kmem_put(mask);
- LWP_RETURN(rc);
- #else
- return -1;
- #endif
- }
- /**
- * @brief Retrieve system information.
- *
- * This function provides details about the current state of the system, such as uptime, memory usage,
- * load average, and other key statistics. The information is stored in a structure pointed to by `info`.
- *
- * @param[out] info A pointer to a buffer where system information will be stored. The structure should
- * be compatible with the format expected by the system, typically `struct sysinfo`.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The structure of `info` must be predefined and consistent with the system's expectations.
- * This function does not allocate memory for `info`; the caller must provide sufficient
- * memory for the structure.
- */
- sysret_t sys_sysinfo(void *info)
- {
- #ifdef ARCH_MM_MMU
- struct sysinfo kinfo = {0};
- rt_size_t total_pages = 0, free_pages = 0;
- if (!lwp_user_accessable(info, sizeof(struct sysinfo)))
- {
- return -EFAULT;
- }
- kinfo.uptime = rt_tick_get_millisecond() / 1000;
- /* TODO: 1, 5, and 15 minute load averages */
- kinfo.loads[0] = kinfo.loads[1] = kinfo.loads[2] = rt_object_get_length(RT_Object_Class_Thread);
- rt_page_get_info(&total_pages, &free_pages);
- kinfo.totalram = total_pages;
- kinfo.freeram = free_pages;
- /* TODO: implementation procfs, here is counter the lwp number */
- struct lwp_avl_struct *pids = lwp_get_pid_ary();
- for (int index = 0; index < RT_LWP_MAX_NR; index++)
- {
- struct rt_lwp *lwp = (struct rt_lwp *)pids[index].data;
- if (lwp)
- {
- kinfo.procs++;
- }
- }
- rt_page_high_get_info(&total_pages, &free_pages);
- kinfo.totalhigh = total_pages;
- kinfo.freehigh = free_pages;
- kinfo.mem_unit = ARCH_PAGE_SIZE;
- if (lwp_put_to_user(info, &kinfo, sizeof(struct sysinfo)) != sizeof(struct sysinfo))
- {
- return -EFAULT;
- }
- return 0;
- #else
- return -1;
- #endif
- }
- /**
- * @brief Set scheduling parameters for a specific thread.
- *
- * This function allows setting the scheduling parameters for a thread identified by its thread ID (`tid`).
- * The parameters are provided via the `param` argument, which should be a structure compatible with the
- * system's scheduling policies.
- *
- * @param[in] tid The thread ID of the target thread for which the scheduling parameters are to be set.
- * @param[in] param A pointer to a structure containing the new scheduling parameters. The structure
- * typically includes fields like priority and policy.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The caller must have appropriate permissions to change the scheduling parameters of the specified thread.
- * The exact structure and fields of `param` depend on the system's implementation and scheduling policies.
- */
- sysret_t sys_sched_setparam(pid_t tid, void *param)
- {
- struct sched_param *sched_param = RT_NULL;
- rt_thread_t thread;
- int ret = -1;
- if (!lwp_user_accessable(param, sizeof(struct sched_param)))
- {
- return -EFAULT;
- }
- sched_param = kmem_get(sizeof(struct sched_param));
- if (sched_param == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(sched_param, param, sizeof(struct sched_param)) != sizeof(struct sched_param))
- {
- kmem_put(sched_param);
- return -EINVAL;
- }
- thread = lwp_tid_get_thread_and_inc_ref(tid);
- if (thread)
- {
- ret = rt_thread_control(thread, RT_THREAD_CTRL_RESET_PRIORITY, (void *)&sched_param->sched_priority);
- }
- lwp_tid_dec_ref(thread);
- kmem_put(sched_param);
- return ret;
- }
- /**
- * @brief Relinquish the processor voluntarily.
- *
- * This function causes the calling thread to yield the processor, allowing other threads
- * that are ready to run to execute. The thread will be placed back into the scheduler's
- * ready queue and may be rescheduled according to its priority and the system's scheduling policy.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function is typically used in cooperative multitasking scenarios or when a thread
- * explicitly determines it no longer needs the processor at the moment.
- */
- sysret_t sys_sched_yield(void)
- {
- rt_thread_yield();
- return 0;
- }
- /**
- * @brief Retrieve the scheduling parameters of a specific thread.
- *
- * This function retrieves the scheduling parameters of the thread identified by the thread ID (`tid`).
- * The retrieved parameters are stored in the structure pointed to by the `param` argument.
- *
- * @param[in] tid The thread ID of the target thread whose scheduling parameters are to be retrieved.
- * @param[out] param A pointer to a structure where the scheduling parameters will be stored. The structure
- * typically includes fields like priority and policy.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The caller must have appropriate permissions to query the scheduling parameters of the specified thread.
- * The exact structure and fields of `param` depend on the system's implementation and scheduling policies.
- */
- sysret_t sys_sched_getparam(const pid_t tid, void *param)
- {
- struct sched_param *sched_param = RT_NULL;
- rt_thread_t thread;
- int ret = -1;
- if (!lwp_user_accessable(param, sizeof(struct sched_param)))
- {
- return -EFAULT;
- }
- sched_param = kmem_get(sizeof(struct sched_param));
- if (sched_param == RT_NULL)
- {
- return -ENOMEM;
- }
- thread = lwp_tid_get_thread_and_inc_ref(tid);
- if (thread)
- {
- sched_param->sched_priority = RT_SCHED_PRIV(thread).current_priority;
- ret = 0;
- }
- lwp_tid_dec_ref(thread);
- lwp_put_to_user((void *)param, sched_param, sizeof(struct sched_param));
- kmem_put(sched_param);
- return ret;
- }
- /**
- * @brief Get the maximum priority for a given scheduling policy.
- *
- * This function retrieves the maximum priority value that can be used with the specified
- * scheduling policy.
- *
- * @param[in] policy The scheduling policy for which to retrieve the maximum priority.
- *
- * @return sysret_t Returns the maximum priority value on success. On failure, returns a
- * negative error code.
- *
- * @note The valid priority range depends on the system's configuration and the selected
- * scheduling policy. The returned value represents the highest priority that can
- * be assigned to a thread using the given policy.
- */
- sysret_t sys_sched_get_priority_max(int policy)
- {
- if(policy < 0)
- {
- SET_ERRNO(EINVAL);
- return -rt_get_errno();
- }
- return RT_THREAD_PRIORITY_MAX;
- }
- /**
- * @brief Get the minimum priority for a given scheduling policy.
- *
- * This function retrieves the minimum priority value that can be used with the specified
- * scheduling policy.
- *
- * @param[in] policy The scheduling policy for which to retrieve the minimum priority.
- *
- * @return sysret_t Returns the minimum priority value on success. On failure, returns a
- * negative error code.
- *
- * @note The valid priority range depends on the system's configuration and the selected
- * scheduling policy. The returned value represents the lowest priority that can
- * be assigned to a thread using the given policy.
- */
- sysret_t sys_sched_get_priority_min(int policy)
- {
- if(policy < 0)
- {
- SET_ERRNO(EINVAL);
- return -rt_get_errno();
- }
- return 0;
- }
- /**
- * @brief Set the scheduling policy and parameters for a thread.
- *
- * This function sets the scheduling policy and associated parameters for the specified thread.
- * It allows controlling the scheduling behavior of threads.
- *
- * @param[in] tid The thread ID of the target thread.
- * @param[in] policy The scheduling policy to be applied. Common values include:
- * - `SCHED_FIFO`: First-in, first-out scheduling.
- * - `SCHED_RR`: Round-robin scheduling.
- * - `SCHED_OTHER`: Default or standard scheduling.
- * @param[in] param Pointer to a structure containing scheduling parameters, such as priority.
- * The structure type depends on the system implementation.
- *
- * @return sysret_t Returns 0 on success. On failure, returns a negative error code.
- *
- * @note This function requires appropriate permissions to modify the scheduling settings
- * of another thread. For most systems, elevated privileges may be required.
- * Ensure the `param` structure is properly initialized for the given `policy`.
- */
- sysret_t sys_sched_setscheduler(int tid, int policy, void *param)
- {
- sysret_t ret;
- struct sched_param *sched_param = RT_NULL;
- rt_thread_t thread = RT_NULL;
- if (!lwp_user_accessable(param, sizeof(struct sched_param)))
- {
- return -EFAULT;
- }
- sched_param = kmem_get(sizeof(struct sched_param));
- if (sched_param == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(sched_param, param, sizeof(struct sched_param)) != sizeof(struct sched_param))
- {
- kmem_put(sched_param);
- return -EINVAL;
- }
- thread = lwp_tid_get_thread_and_inc_ref(tid);
- ret = rt_thread_control(thread, RT_THREAD_CTRL_RESET_PRIORITY, (void *)&sched_param->sched_priority);
- lwp_tid_dec_ref(thread);
- kmem_put(sched_param);
- return ret;
- }
- /**
- * @brief Get the scheduling policy of a thread.
- *
- * This function retrieves the current scheduling policy of the specified thread.
- *
- * @param[in] tid The thread ID of the target thread.
- *
- * @return sysret_t Returns the scheduling policy of the thread on success. On failure,
- * returns a negative error code.
- *
- * @note The caller must have appropriate permissions to query the scheduling policy
- * of the specified thread.
- */
- sysret_t sys_sched_getscheduler(int tid)
- {
- rt_thread_t thread = RT_NULL;
- int rtn;
- thread = lwp_tid_get_thread_and_inc_ref(tid);
- lwp_tid_dec_ref(thread);
- if (thread)
- {
- rtn = SCHED_RR;
- }
- else
- {
- rtn = -ESRCH;
- }
- return rtn;
- }
- /**
- * @brief Flush the file descriptors' data to disk.
- *
- * This function flushes all modified data of the file associated with the specified
- * file descriptor to disk, ensuring that any changes made to the file are committed
- * to permanent storage.
- *
- * @param[in] fd The file descriptor associated with the file to be flushed. It should
- * refer to an open file.
- *
- * @return sysret_t Returns `0` (0) on success. On failure, returns a negative
- * error code.
- *
- * @note The `fsync` function ensures that all data written to the file is physically
- * stored on disk, but it does not guarantee that all file metadata is flushed.
- * To flush both data and metadata, `fdatasync` can be used.
- */
- sysret_t sys_fsync(int fd)
- {
- int res = fsync(fd);
- if (res < 0)
- res = rt_get_errno();
- return res;
- }
- /**
- * @brief Open a message queue.
- *
- * This function opens a message queue for communication between processes.
- * It can create a new message queue or open an existing one, depending on the specified
- * flags.
- *
- * @param[in] name The name of the message queue. The name should be a null-terminated
- * string and is subject to system-specific naming conventions.
- * @param[in] flags Flags that control the behavior of the message queue. Common flags include:
- * - `O_CREAT`: Create the message queue if it does not exist.
- * - `O_EXCL`: Fail if the message queue already exists.
- * - `O_RDONLY`: Open the queue for reading.
- * - `O_WRONLY`: Open the queue for writing.
- * - `O_RDWR`: Open the queue for both reading and writing.
- * @param[in] mode The mode to be applied when creating the message queue, which defines
- * the permissions for the message queue (e.g., read, write).
- * @param[in] attr A pointer to a `struct mq_attr` that defines the attributes of the
- * message queue, such as the maximum number of messages and the size of
- * each message. If `NULL`, default values are used.
- *
- * @return mqd_t Returns a non-negative file descriptor for the message queue on success.
- * On failure, returns `-1` and sets `errno` to indicate the error.
- *
- * @note If the message queue is created, its attributes (such as the maximum number of
- * messages and message size) must be defined in the `mq_attr` structure. If the
- * `O_CREAT` flag is not specified and the queue does not exist, the function will
- * return `-1`.
- */
- mqd_t sys_mq_open(const char *name, int flags, mode_t mode, struct mq_attr *attr)
- {
- mqd_t mqdes;
- sysret_t ret = 0;
- #ifdef ARCH_MM_MMU
- char *kname = RT_NULL;
- rt_size_t len = 0;
- struct mq_attr attr_k;
- len = lwp_user_strlen(name);
- if (!len)
- return (mqd_t)-EINVAL;
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- return (mqd_t)-ENOMEM;
- if (attr == NULL)
- {
- attr_k.mq_maxmsg = 10;
- attr_k.mq_msgsize = 8192;
- attr_k.mq_flags = 0;
- attr = &attr_k;
- }
- else
- {
- if (!lwp_get_from_user(&attr_k, (void *)attr, sizeof(struct mq_attr)))
- return -EINVAL;
- }
- lwp_get_from_user(kname, (void *)name, len + 1);
- mqdes = mq_open(kname, flags, mode, &attr_k);
- if (mqdes == -1)
- {
- ret = GET_ERRNO();
- }
- lwp_put_to_user(attr, &attr_k, sizeof(struct mq_attr));
- kmem_put(kname);
- #else
- mqdes = mq_open(name, flags, mode, attr);
- #endif
- if (mqdes == -1)
- return (mqd_t)ret;
- else
- return mqdes;
- }
- /**
- * @brief Remove a message queue.
- *
- * This function removes a message queue identified by its name. If the message queue
- * is open by any process, it will be removed only when all the processes close their
- * file descriptors associated with the message queue.
- *
- * @param[in] name The name of the message queue to be removed. It should be a null-terminated
- * string that conforms to system-specific naming conventions.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative
- * error code.
- *
- * @note After a successful call, the message queue is removed from the system. However,
- * the removal will not take effect until all processes close their file descriptors
- * associated with the queue. The function will fail if the message queue is still
- * open by other processes.
- */
- sysret_t sys_mq_unlink(const char *name)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- char *kname = RT_NULL;
- rt_size_t len = 0;
- len = lwp_user_strlen(name);
- if (!len)
- return -EINVAL;
- kname = (char *)kmem_get(len + 1);
- if (!kname)
- return -ENOMEM;
- lwp_get_from_user(kname, (void *)name, len + 1);
- ret = mq_unlink(kname);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kname);
- return ret;
- #else
- ret = mq_unlink(name);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Send a message to a message queue with a timeout.
- *
- * This function sends a message to the specified message queue, but it allows the sender
- * to specify a timeout. If the message queue is full, the function will block until either
- * space becomes available or the specified timeout expires. If the timeout expires without
- * space being available, the function returns an error.
- *
- * @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
- * @param[in] msg A pointer to the message to be sent.
- * @param[in] len The length of the message to send.
- * @param[in] prio The priority of the message (higher values indicate higher priority).
- * @param[in] at A pointer to a `timespec` structure that specifies the absolute timeout.
- * If the timeout expires before the message can be sent, the function returns
- * an error.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error
- * code.
- *
- * @note The function uses the `timespec` structure to specify the absolute timeout. The
- * `at` parameter should indicate the time at which the operation should time out.
- * If the timeout is `NULL`, the function will not apply any timeout (it will block
- * indefinitely until the message is sent).
- *
- * @see sys_mq_send
- */
- sysret_t sys_mq_timedsend(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec *at)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- char *kmsg = RT_NULL;
- struct timespec at_k;
- kmsg = (char *)kmem_get(len + 1);
- if (!kmsg)
- return -ENOMEM;
- lwp_get_from_user(&at_k, (void *)at, sizeof(struct timespec));
- lwp_get_from_user(kmsg, (void *)msg, len + 1);
- ret = mq_timedsend(mqd, kmsg, len, prio, &at_k);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmsg);
- return ret;
- #else
- ret = mq_timedsend(mqd, msg, len, prio, at);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Receive a message from a message queue with a timeout.
- *
- * This function attempts to receive a message from the specified message queue, but it
- * allows the receiver to specify a timeout. If the queue is empty, the function will block
- * until either a message becomes available or the specified timeout expires. If the timeout
- * expires without receiving a message, the function returns an error.
- *
- * @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
- * @param[out] msg A pointer to the buffer where the received message will be stored.
- * @param[in] len The maximum length of the buffer to store the received message.
- * @param[out] prio A pointer to an unsigned integer that will be set to the priority
- * of the received message.
- * @param[in] at A pointer to a `timespec` structure that specifies the absolute timeout.
- * If the timeout expires before a message is received, the function will
- * return an error.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The function uses the `timespec` structure to specify the absolute timeout. The
- * `at` parameter should indicate the time at which the operation should time out.
- * If the timeout is `NULL`, the function will block indefinitely until a message is
- * received.
- *
- * @see sys_mq_receive
- */
- sysret_t sys_mq_timedreceive(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec *restrict at)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- char *restrict kmsg = RT_NULL;
- struct timespec at_k;
- kmsg = (char *restrict)kmem_get(len + 1);
- if (!kmsg)
- return -ENOMEM;
- lwp_get_from_user(kmsg, (void *)msg, len + 1);
- if (at == RT_NULL)
- {
- ret = mq_timedreceive(mqd, kmsg, len, prio, RT_NULL);
- }
- else
- {
- if (!lwp_get_from_user(&at_k, (void *)at, sizeof(struct timespec)))
- return -EINVAL;
- ret = mq_timedreceive(mqd, kmsg, len, prio, &at_k);
- }
- if (ret > 0)
- lwp_put_to_user(msg, kmsg, len + 1);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmsg);
- return ret;
- #else
- ret = mq_timedreceive(mqd, msg, len, prio, at);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Set up asynchronous notification for a message queue.
- *
- * This function configures asynchronous notification for a message queue. When a message
- * is available in the queue, the system can notify the calling process through a signal
- * or another method specified in the `sigevent` structure. This is typically used to allow
- * a process to be notified when a message arrives without having to block in the receive call.
- *
- * @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
- * @param[in] sev A pointer to a `sigevent` structure that specifies the notification
- * mechanism to be used when a message is received. It could include
- * signals or other notification types such as event flags or message passing.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function enables asynchronous notification, but the specific behavior depends
- * on the configuration specified in the `sev` parameter, which could involve signals
- * or other forms of notification.
- *
- * @see sys_mq_send, sys_mq_timedreceive
- */
- sysret_t sys_mq_notify(mqd_t mqd, const struct sigevent *sev)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- struct sigevent sev_k;
- lwp_get_from_user(&sev_k, (void *)sev, sizeof(struct timespec));
- ret = mq_notify(mqd, &sev_k);
- #else
- ret = mq_notify(mqd, sev);
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Get or set attributes of a message queue.
- *
- * This function allows you to get or set the attributes of an existing message queue.
- * If the `new` attribute structure is non-NULL, it updates the message queue with the new
- * attributes. Otherwise, If the `old` attribute structure is non-NULL, it will return the current
- * attributes of the message queue.
- *
- * @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
- * @param[in] new A pointer to a `mq_attr` structure containing the new attributes to set.
- * If `NULL`, the function will not modify the message queue attributes.
- * @param[out] old A pointer to a `mq_attr` structure where the current message queue
- * attributes will be returned. If `NULL`, the current attributes will not
- * be returned.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The `mq_attr` structure contains parameters like the maximum number of messages,
- * the maximum message size, and other attributes that control the behavior of the
- * message queue.
- *
- * @see sys_mq_open, sys_mq_notify
- */
- sysret_t sys_mq_getsetattr(mqd_t mqd, const struct mq_attr *restrict new, struct mq_attr *restrict old)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- size_t size = sizeof(struct mq_attr);
- struct mq_attr *restrict knew = NULL;
- struct mq_attr *restrict kold = NULL;
- if (new != RT_NULL)
- {
- if (!lwp_user_accessable((void *)new, size))
- return -EFAULT;
- knew = kmem_get(size);
- if (!knew)
- return -ENOMEM;
- lwp_get_from_user(knew, (void *)new, size);
- }
- if (!lwp_user_accessable((void *)old, size))
- return -EFAULT;
- kold = kmem_get(size);
- if (!kold)
- return -ENOMEM;
- lwp_get_from_user(kold, (void *)old, size);
- ret = mq_setattr(mqd, knew, kold);
- if (ret != -1)
- lwp_put_to_user(old, kold, size);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kold);
- if (new != RT_NULL)
- kmem_put(knew);
- return ret;
- #else
- ret = mq_setattr(mqd, new, old);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- /**
- * @brief Close a message queue descriptor.
- *
- * This function closes a message queue descriptor. After calling this function, the
- * descriptor can no longer be used to interact with the message queue. Any resources
- * associated with the descriptor are released. If the message queue was opened with the
- * `O_CLOEXEC` flag, it will be automatically closed when the calling process executes
- * an `exec` system call.
- *
- * @param[in] mqd The message queue descriptor to be closed. It was previously returned
- * by `sys_mq_open`.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @see sys_mq_open, sys_mq_unlink
- */
- sysret_t sys_mq_close(mqd_t mqd)
- {
- int ret = 0;
- #ifdef ARCH_MM_MMU
- ret = mq_close(mqd);
- #else
- ret = mq_close(mqd);
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- #define ICACHE (1<<0)
- #define DCACHE (1<<1)
- #define BCACHE (ICACHE|DCACHE)
- /**
- * @brief Flush the cache for a specified memory region.
- *
- * This function flushes the cache for a specified memory region. It is commonly used
- * to ensure that the contents of a memory region are written back to the main memory
- * or that stale cache entries are invalidated. The cache operation can be controlled
- * by the `cache` parameter to determine whether to clean or invalidate the cache.
- *
- * @param[in] addr The starting address of the memory region to flush.
- * @param[in] size The size of the memory region to flush, in bytes.
- * @param[in] cache A flag to specify the cache operation:
- * - `CACHE_CLEAN`: Clean the cache (write back to memory).
- * - `CACHE_INVALIDATE`: Invalidate the cache (discard cached data).
- * - `CACHE_FLUSH`: Both clean and invalidate the cache.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function is typically used in low-level operations or in systems where
- * cache coherence between memory and cache is critical.
- */
- rt_weak sysret_t sys_cacheflush(void *addr, int size, int cache)
- {
- if (!lwp_user_accessable(addr, size))
- return -EFAULT;
- if (((size_t)addr < (size_t)addr + size) &&
- ((size_t)addr >= USER_VADDR_START) &&
- ((size_t)addr + size < USER_VADDR_TOP))
- {
- if ((cache & DCACHE))
- {
- rt_hw_cpu_dcache_clean_and_invalidate(addr, size);
- }
- if ((cache & ICACHE))
- {
- rt_hw_cpu_icache_invalidate(addr, size);
- }
- return 0;
- }
- return -EFAULT;
- }
- /**
- * @brief Get system information.
- *
- * This function retrieves information about the current system, such as the system name,
- * version, release, architecture, and other details. The information is stored in the
- * `utsname` structure pointed to by the `uts` parameter.
- *
- * @param[out] uts A pointer to a `utsname` structure where the system information will
- * be stored. The structure includes fields such as:
- * - `sysname`: Operating system name.
- * - `nodename`: Network node hostname.
- * - `release`: Operating system release version.
- * - `version`: Operating system version.
- * - `machine`: Hardware identifier (architecture).
- *
- * @return sysret_t Returns `SYSRET_OK` (0) on success. On failure, returns a negative error code.
- *
- * @note This function provides details about the system environment, which may be useful
- * for applications needing to adapt to different system configurations.
- *
- * @see sys_gethostname, sys_uname
- */
- sysret_t sys_uname(struct utsname *uts)
- {
- struct utsname utsbuff = {0};
- int ret = 0;
- const char *machine;
- if (!lwp_user_accessable((void *)uts, sizeof(struct utsname)))
- {
- return -EFAULT;
- }
- rt_strncpy(utsbuff.sysname, "RT-Thread", sizeof(utsbuff.sysname));
- utsbuff.nodename[0] = '\0';
- ret = rt_snprintf(utsbuff.release, sizeof(utsbuff.release), "%u.%u.%u",
- RT_VERSION_MAJOR, RT_VERSION_MINOR, RT_VERSION_PATCH);
- if (ret < 0)
- {
- return -EIO;
- }
- ret = rt_snprintf(utsbuff.version, sizeof(utsbuff.version), "RT-Thread %u.%u.%u %s %s",
- RT_VERSION_MAJOR, RT_VERSION_MINOR, RT_VERSION_PATCH, __DATE__, __TIME__);
- if (ret < 0)
- {
- return -EIO;
- }
- machine = rt_hw_cpu_arch();
- rt_strncpy(utsbuff.machine, machine, sizeof(utsbuff.machine));
- utsbuff.domainname[0] = '\0';
- lwp_put_to_user(uts, &utsbuff, sizeof utsbuff);
- return 0;
- }
- /**
- * @brief Get filesystem statistics.
- *
- * This function retrieves statistics about the filesystem at the specified path,
- * storing the results in the provided `statfs` structure. It can be used to obtain
- * information such as the total number of blocks, free blocks, available inodes, etc.
- *
- * @param[in] path The path to the filesystem to query. If the path is the root directory
- * (`"/"`), it returns statistics for the root filesystem.
- * @param[out] buf A pointer to a `statfs` structure where the filesystem statistics will
- * be stored. This structure includes information such as:
- * - `f_type`: The type of the filesystem.
- * - `f_bsize`: The optimal block size for I/O operations.
- * - `f_blocks`: Total number of blocks in the filesystem.
- * - `f_bfree`: Number of free blocks.
- * - `f_bavail`: Number of free blocks available to non-superuser.
- * - `f_files`: Total number of file nodes (inodes).
- * - `f_ffree`: Number of free inodes.
- * - `f_favail`: Number of inodes available to non-superuser.
- * - `f_flag`: Flags describing the filesystem.
- * - `f_namelen`: Maximum length of a filename.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function is useful for determining the available space and file system
- * characteristics of a mounted filesystem.
- *
- * @see sys_fstatfs
- */
- sysret_t sys_statfs(const char *path, struct statfs *buf)
- {
- int ret = 0;
- size_t len;
- size_t copy_len;
- char *copy_path;
- struct statfs statfsbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
- {
- return -EFAULT;
- }
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- copy_path = (char*)rt_malloc(len + 1);
- if (!copy_path)
- {
- return -ENOMEM;
- }
- copy_len = lwp_get_from_user(copy_path, (void*)path, len);
- if (copy_len == 0)
- {
- rt_free(copy_path);
- return -EFAULT;
- }
- copy_path[copy_len] = '\0';
- ret = _SYS_WRAP(statfs(copy_path, &statfsbuff));
- rt_free(copy_path);
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
- }
- return ret;
- }
- /**
- * @brief Get extended filesystem statistics (64-bit).
- *
- * This function retrieves extended statistics about the filesystem at the specified path,
- * using 64-bit values for larger filesystems or filesystems with a large number of blocks or inodes.
- * The information is stored in the provided `statfs` structure, which includes details such as total
- * blocks, free blocks, available inodes, etc.
- *
- * @param[in] path The path to the filesystem to query. Typically, this would be the root directory
- * (`"/"`) for the root filesystem, or any other directory on the filesystem.
- * @param[in] sz The size of the `statfs` structure. This parameter allows for future extensions
- * of the `statfs` structure without breaking compatibility with older applications.
- * @param[out] buf A pointer to a `statfs` structure where the extended filesystem statistics
- * will be stored. This structure includes information such as:
- * - `f_bsize`: The optimal block size for I/O operations.
- * - `f_blocks`: Total number of blocks in the filesystem.
- * - `f_bfree`: Number of free blocks.
- * - `f_bavail`: Number of free blocks available to non-superuser.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function is particularly useful for querying large filesystems or filesystems with
- * 64-bit addresses or data values, and is an extended version of the standard `sys_statfs`.
- *
- * @see sys_statfs
- */
- sysret_t sys_statfs64(const char *path, size_t sz, struct statfs *buf)
- {
- int ret = 0;
- size_t len;
- size_t copy_len;
- char *copy_path;
- struct statfs statfsbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
- {
- return -EFAULT;
- }
- if (sz != sizeof(struct statfs))
- {
- return -EINVAL;
- }
- len = lwp_user_strlen(path);
- if (len <= 0)
- {
- return -EFAULT;
- }
- copy_path = (char*)rt_malloc(len + 1);
- if (!copy_path)
- {
- return -ENOMEM;
- }
- copy_len = lwp_get_from_user(copy_path, (void*)path, len);
- if (copy_len == 0)
- {
- rt_free(copy_path);
- return -EFAULT;
- }
- copy_path[copy_len] = '\0';
- ret = _SYS_WRAP(statfs(copy_path, &statfsbuff));
- rt_free(copy_path);
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
- }
- return ret;
- }
- /**
- * @brief Get filesystem statistics for a file descriptor.
- *
- * This function retrieves statistics about the filesystem containing the file referred to by the
- * file descriptor `fd`. The information is stored in the provided `statfs` structure, which includes
- * details such as total blocks, free blocks, available inodes, etc.
- *
- * @param[in] fd The file descriptor referring to an open file. The file descriptor must be
- * valid and represent a file on a mounted filesystem.
- * @param[out] buf A pointer to a `statfs` structure where the filesystem statistics will be
- * stored. This structure includes information such as:
- * - `f_bsize`: The optimal block size for I/O operations.
- * - `f_blocks`: Total number of blocks in the filesystem.
- * - `f_bfree`: Number of free blocks.
- * - `f_bavail`: Number of free blocks available to non-superuser.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note This function is useful for obtaining filesystem information about a specific file
- * represented by its file descriptor, rather than querying the filesystem associated with
- * a specific path.
- *
- * @see sys_statfs
- */
- sysret_t sys_fstatfs(int fd, struct statfs *buf)
- {
- int ret = 0;
- struct statfs statfsbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
- {
- return -EFAULT;
- }
- ret = _SYS_WRAP(fstatfs(fd, &statfsbuff));
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
- }
- return ret;
- }
- /**
- * @brief Get 64-bit filesystem statistics for a file descriptor.
- *
- * This function retrieves 64-bit statistics about the filesystem containing the file referred to by
- * the file descriptor `fd`. The statistics are stored in the provided `statfs` structure, which
- * includes details such as total blocks, free blocks, available inodes, etc. The function differs
- * from `sys_fstatfs` in that it supports 64-bit values for filesystem sizes and counts.
- *
- * @param[in] fd The file descriptor referring to an open file. The file descriptor must be
- * valid and represent a file on a mounted filesystem.
- * @param[in] sz The size of the `statfs` structure (typically used to ensure compatibility with
- * different versions of the structure).
- * @param[out] buf A pointer to a `statfs` structure where the filesystem statistics will be
- * stored. This structure includes information such as:
- * - `f_bsize`: The optimal block size for I/O operations.
- * - `f_blocks`: Total number of blocks in the filesystem (64-bit).
- * - `f_bfree`: Number of free blocks (64-bit).
- * - `f_bavail`: Number of free blocks available to non-superuser (64-bit).
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- * @note This function is particularly useful for systems supporting 64-bit filesystem statistics.
- * It provides extended accuracy for large filesystems, including those with very large
- * numbers of blocks or inodes.
- *
- * @see sys_fstatfs
- */
- sysret_t sys_fstatfs64(int fd, size_t sz, struct statfs *buf)
- {
- int ret = 0;
- struct statfs statfsbuff = {0};
- if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
- {
- return -EFAULT;
- }
- if (sz != sizeof(struct statfs))
- {
- return -EINVAL;
- }
- ret = _SYS_WRAP(fstatfs(fd, &statfsbuff));
- if (ret == 0)
- {
- lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
- }
- return ret;
- }
- static char *_cp_from_usr_string(char *dst, char *src, size_t length)
- {
- char *rc;
- size_t copied_bytes;
- if (length)
- {
- copied_bytes = lwp_get_from_user(dst, src, length);
- dst[copied_bytes] = '\0';
- rc = dst;
- }
- else
- {
- rc = RT_NULL;
- }
- return rc;
- }
- /**
- * @brief Mount a filesystem.
- *
- * This function mounts a filesystem onto a specified directory. It allows for mounting various
- * types of filesystems, including but not limited to `ext4`, `nfs`, and `tmpfs`. The function
- * allows the specification of the source device, the target mount point, and additional parameters
- * such as filesystem type, mount flags, and extra data.
- *
- * @param[in] source The source of the filesystem, which can be a device (e.g., `/dev/sda1`)
- * or a network resource (e.g., a NFS share). For certain filesystems like
- * `tmpfs`, this can be `NULL`.
- * @param[in] target The target directory where the filesystem will be mounted.
- * This should be an existing empty directory.
- * @param[in] filesystemtype The type of filesystem to mount, e.g., `ext4`, `tmpfs`, `nfs`, etc.
- * @param[in] mountflags Flags that control the mount operation, such as `MS_RDONLY` for read-only
- * mounts or `MS_NODEV` to prevent device files from being created.
- * @param[in] data Optional data that is passed to the filesystem's mount handler. This
- * may be used for setting up specific parameters for the filesystem type.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note Mounting a filesystem on an existing mount point can replace the existing filesystem at that
- * location. Make sure the target directory is empty before mounting to avoid any conflicts.
- */
- sysret_t sys_mount(char *source, char *target, char *filesystemtype,
- unsigned long mountflags, void *data)
- {
- char *kbuffer, *ksource, *ktarget, *kfs;
- size_t len_source, len_target, len_fs;
- char *tmp = NULL;
- int ret = 0;
- struct stat buf = {0};
- char *dev_fullpath = RT_NULL;
- len_source = source ? lwp_user_strlen(source) : 0;
- if (len_source < 0)
- return -EINVAL;
- len_target = target ? lwp_user_strlen(target) : 0;
- if (len_target <= 0)
- return -EINVAL;
- len_fs = filesystemtype ? lwp_user_strlen(filesystemtype) : 0;
- if (len_fs < 0)
- return -EINVAL;
- kbuffer = (char *)rt_malloc(len_source + 1 + len_target + 1 + len_fs + 1);
- if (!kbuffer)
- {
- return -ENOMEM;
- }
- /* get parameters from user space */
- ksource = kbuffer;
- ktarget = ksource + len_source + 1;
- kfs = ktarget + len_target + 1;
- ksource = _cp_from_usr_string(ksource, source, len_source);
- ktarget = _cp_from_usr_string(ktarget, target, len_target);
- kfs = _cp_from_usr_string(kfs, filesystemtype, len_fs);
- if (mountflags & MS_REMOUNT)
- {
- ret = dfs_remount(ktarget, mountflags, data);
- }
- else
- {
- if (strcmp(kfs, "nfs") == 0)
- {
- tmp = ksource;
- ksource = NULL;
- }
- if (strcmp(kfs, "tmp") == 0)
- {
- ksource = NULL;
- }
- if (ksource && !dfs_file_stat(ksource, &buf) && S_ISBLK(buf.st_mode))
- {
- dev_fullpath = dfs_normalize_path(RT_NULL, ksource);
- RT_ASSERT(rt_strncmp(dev_fullpath, "/dev/", sizeof("/dev/") - 1) == 0);
- ret = dfs_mount(dev_fullpath + sizeof("/dev/") - 1, ktarget, kfs, 0, tmp);
- }
- else
- {
- ret = dfs_mount(ksource, ktarget, kfs, 0, tmp);
- }
- if (ret < 0)
- {
- ret = -rt_get_errno();
- }
- }
- rt_free(kbuffer);
- rt_free(dev_fullpath);
- return ret;
- }
- /**
- * @brief Unmount a filesystem.
- *
- * This function unmounts a previously mounted filesystem from a specified target directory or file.
- * It removes the filesystem from the system, making the resources associated with it available for
- * other uses. It can also support additional flags to control the unmounting behavior.
- *
- * @param[in] __special_file The target directory or mount point from which the filesystem is to be
- * unmounted. This should be a valid mount point that was previously mounted.
- * @param[in] __flags Flags that control the unmounting behavior. Common flags include:
- * - `MNT_FORCE`: Forces the unmount even if the filesystem is busy.
- * - `MNT_DETACH`: Detaches the filesystem, allowing it to be unmounted
- * asynchronously.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note The `MNT_FORCE` flag should be used with caution, as it may result in data loss or corruption
- * if there are pending writes or active processes using the filesystem.
- *
- * @see sys_mount
- */
- sysret_t sys_umount2(char *__special_file, int __flags)
- {
- char *copy_special_file;
- size_t len_special_file, copy_len_special_file;
- int ret = 0;
- len_special_file = lwp_user_strlen(__special_file);
- if (len_special_file <= 0)
- {
- return -EFAULT;
- }
- copy_special_file = (char*)rt_malloc(len_special_file + 1);
- if (!copy_special_file)
- {
- return -ENOMEM;
- }
- copy_len_special_file = lwp_get_from_user(copy_special_file, __special_file, len_special_file);
- copy_special_file[copy_len_special_file] = '\0';
- ret = dfs_unmount(copy_special_file);
- rt_free(copy_special_file);
- return ret;
- }
- /**
- * @brief Create a new hard link to an existing file.
- *
- * This function creates a new hard link to an existing file, making the file accessible from
- * multiple filenames. The new link points to the same inode as the existing file, meaning
- * both names refer to the same underlying data. The link count for the file is incremented.
- *
- * @param[in] existing The path to the existing file. It must be an absolute or relative path
- * to a file that already exists.
- * @param[in] new The path to the new link to be created. This can be a new filename or
- * an existing directory where the link will be placed.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note Hard links share the same inode number, meaning changes to the data of the file via one
- * link will be reflected in all hard links. Deleting any of the links will not remove the
- * file data until all links are deleted.
- */
- sysret_t sys_link(const char *existing, const char *new)
- {
- int ret = -1;
- int err = 0;
- #ifdef RT_USING_DFS_V2
- #ifdef ARCH_MM_MMU
- int len = 0;
- char *kexisting = RT_NULL;
- char *knew = RT_NULL;
- len = lwp_user_strlen(existing);
- if (len <= 0)
- {
- return -EFAULT;
- }
- kexisting = (char *)kmem_get(len + 1);
- if (!kexisting)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kexisting, (void *)existing, len + 1) != (len + 1))
- {
- kmem_put(kexisting);
- return -EINVAL;
- }
- len = lwp_user_strlen(new);
- if (len <= 0)
- {
- kmem_put(kexisting);
- return -EFAULT;
- }
- knew = (char *)kmem_get(len + 1);
- if (!knew)
- {
- kmem_put(kexisting);
- return -ENOMEM;
- }
- if (lwp_get_from_user(knew, (void *)new, len + 1) != (len + 1))
- {
- kmem_put(knew);
- kmem_put(kexisting);
- return -EINVAL;
- }
- ret = dfs_file_link(kexisting, knew);
- if(ret < 0)
- {
- err = GET_ERRNO();
- }
- kmem_put(knew);
- kmem_put(kexisting);
- #else
- ret = dfs_file_link(existing, new);
- #endif
- #else
- SET_ERRNO(EFAULT);
- err = GET_ERRNO();
- #endif
- return (err < 0 ? err : ret);
- }
- /**
- * @brief Create a symbolic link to an existing file or directory.
- *
- * This function creates a new symbolic link, which is a special file that contains a reference
- * to another file or directory. The symbolic link allows for easy redirection or aliasing of
- * file paths. Unlike a hard link, a symbolic link can point to a file or directory across
- * different file systems.
- *
- * @param[in] existing The path to the existing file or directory that the symbolic link
- * will refer to. It must be an absolute or relative path.
- * @param[in] new The path to the new symbolic link to be created. This must be a valid
- * path where the link will be placed.
- *
- * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
- *
- * @note A symbolic link is distinct from a hard link in that it points to the path of the target
- * file or directory, rather than directly to the inode. If the target file or directory is
- * removed or moved, the symbolic link will become "broken" and will not resolve to a valid
- * location.
- */
- sysret_t sys_symlink(const char *existing, const char *new)
- {
- int ret = -1;
- int err = 0 ;
- #ifdef ARCH_MM_MMU
- ret = lwp_user_strlen(existing);
- if (ret <= 0)
- {
- return -EFAULT;
- }
- ret = lwp_user_strlen(new);
- if (ret <= 0)
- {
- return -EFAULT;
- }
- #endif
- #ifdef RT_USING_DFS_V2
- ret = dfs_file_symlink(existing, new);
- if(ret < 0)
- {
- err = GET_ERRNO();
- }
- #else
- SET_ERRNO(EFAULT);
- #endif
- return (err < 0 ? err : ret);
- }
- /**
- * @brief Create an event file descriptor.
- *
- * This function creates an eventfd, which is a file descriptor used for event notification.
- * Eventfd is a simple mechanism to notify threads or processes about certain events using
- * an integer counter. It is typically used for inter-process communication (IPC) or
- * synchronization purposes, where one thread or process increments the counter to signal
- * another thread or process.
- *
- * @param[in] count Initial value for the eventfd counter. It can be set to a non-zero
- * value to initialize the counter to that value.
- * @param[in] flags Flags that control the behavior of the eventfd. Valid flags include:
- * - `EFD_CLOEXEC`: Set the close-on-exec flag for the eventfd.
- * - `EFD_NONBLOCK`: Set the non-blocking flag for the eventfd.
- *
- * @return sysret_t On success, returns a valid file descriptor referring to the eventfd. On
- * failure, returns a negative error code.
- *
- * @note Eventfd can be used for both counting and signaling purposes. It provides
- * efficient signaling between threads or processes.
- */
- sysret_t sys_eventfd2(unsigned int count, int flags)
- {
- int ret;
- ret = eventfd(count, flags);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Create an epoll instance.
- *
- * This function creates an epoll instance, which is used for monitoring multiple file descriptors
- * to see if I/O is possible on them. It allows a program to efficiently wait for events such as
- * data being available for reading or space becoming available for writing. Epoll provides a scalable
- * mechanism for managing large numbers of file descriptors.
- *
- * @param[in] flags Flags that control the behavior of the epoll instance. The valid flags include:
- * - `EPOLL_CLOEXEC`: Set the close-on-exec flag for the epoll instance.
- * - `EPOLL_NONBLOCK`: Set the non-blocking flag for the epoll instance.
- *
- * @return sysret_t On success, returns a file descriptor for the epoll instance. On failure,
- * returns a negative error code.
- *
- * @note The `sys_epoll_create1` function is similar to `sys_epoll_create`, but it allows for
- * additional control over the epoll instance creation via flags.
- */
- sysret_t sys_epoll_create1(int flags)
- {
- int ret;
- ret = epoll_create(flags);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Control an epoll instance.
- *
- * This function performs control operations on an epoll instance, such as adding, modifying,
- * or removing file descriptors from the epoll instance's interest list.
- *
- * @param[in] fd The file descriptor of the epoll instance created using `sys_epoll_create` or `sys_epoll_create1`.
- * @param[in] op The operation to perform on the epoll instance. It can be one of the following:
- * - `EPOLL_CTL_ADD`: Add the specified file descriptor to the epoll interest list.
- * - `EPOLL_CTL_MOD`: Modify the event mask of an existing file descriptor in the epoll interest list.
- * - `EPOLL_CTL_DEL`: Remove the specified file descriptor from the epoll interest list.
- * @param[in] fd2 The file descriptor to be added, modified, or removed from the epoll interest list.
- * @param[in] ev A pointer to an `epoll_event` structure that describes the event to be associated with `fd2`.
- * This parameter is required for `EPOLL_CTL_ADD` and `EPOLL_CTL_MOD`, but not for `EPOLL_CTL_DEL`.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note This function is typically used to manage the set of file descriptors monitored by an epoll instance.
- */
- sysret_t sys_epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
- {
- int ret = 0;
- struct epoll_event *kev = RT_NULL;
- if (ev)
- {
- if (!lwp_user_accessable((void *)ev, sizeof(struct epoll_event)))
- return -EFAULT;
- kev = kmem_get(sizeof(struct epoll_event));
- if (kev == RT_NULL)
- {
- return -ENOMEM;
- }
- if (lwp_get_from_user(kev, ev, sizeof(struct epoll_event)) != sizeof(struct epoll_event))
- {
- kmem_put(kev);
- return -EINVAL;
- }
- ret = epoll_ctl(fd, op, fd2, kev);
- kmem_put(kev);
- }
- else
- {
- ret = epoll_ctl(fd, op, fd2, RT_NULL);
- }
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Wait for events on an epoll file descriptor, with the ability to block for specific signals.
- *
- * This function waits for events on an epoll file descriptor. It blocks until one or more events
- * are available or a timeout occurs. In addition to waiting for events, it can also block for specific signals
- * as specified by the `sigs` argument.
- *
- * @param[in] fd The file descriptor of the epoll instance, created using `sys_epoll_create` or `sys_epoll_create1`.
- * @param[out] ev A pointer to an array of `epoll_event` structures that will receive the events that have occurred.
- * @param[in] cnt The maximum number of events to return. This specifies the size of the `ev` array.
- * @param[in] to The timeout in milliseconds. A negative value means no timeout, and `0` means non-blocking.
- * @param[in] sigs A pointer to a signal set (`sigset_t`) that specifies the signals to block during the wait.
- * If `NULL`, no signals are blocked.
- * @param[in] sigsetsize The size of the signal set (`sigs`) in bytes. This should be the size of `sigset_t` if `sigs` is not `NULL`.
- *
- * @return sysret_t On success, returns the number of events returned (may be `0` if the timeout expires with no events).
- * On failure, returns a negative error code.
- *
- * @note This function is similar to `sys_epoll_wait`, but it also allows for signal handling, blocking the calling thread
- * from receiving signals specified in the `sigs` set while waiting for events.
- */
- sysret_t sys_epoll_pwait(int fd,
- struct epoll_event *ev,
- int cnt,
- int to,
- const sigset_t *sigs,
- unsigned long sigsetsize)
- {
- int ret = 0;
- struct epoll_event *kev = RT_NULL;
- sigset_t *ksigs = RT_NULL;
- if (!lwp_user_accessable((void *)ev, cnt * sizeof(struct epoll_event)))
- return -EFAULT;
- kev = kmem_get(cnt * sizeof(struct epoll_event));
- if (kev == RT_NULL)
- {
- return -ENOMEM;
- }
- if (sigs != RT_NULL)
- {
- if (!lwp_user_accessable((void *)sigs, sizeof(sigset_t)))
- {
- kmem_put(kev);
- return -EFAULT;
- }
- ksigs = kmem_get(sizeof(sigset_t));
- if (ksigs == RT_NULL)
- {
- kmem_put(kev);
- return -ENOMEM;
- }
- if (lwp_get_from_user(ksigs, (void *)sigs, sizeof(sigset_t)) != sizeof(sigset_t))
- {
- kmem_put(kev);
- kmem_put(ksigs);
- return -EINVAL;
- }
- }
- ret = epoll_pwait(fd, kev, cnt, to, ksigs);
- if (ret > 0)
- {
- lwp_put_to_user((void *)ev, kev, ret * sizeof(struct epoll_event));
- }
- if (sigs != RT_NULL)
- kmem_put(ksigs);
- kmem_put(kev);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Truncate a file to a specified length.
- *
- * This function resizes the file associated with the given file descriptor `fd` to the specified length.
- * If the current size of the file is greater than the specified length, the file is truncated. If the file is smaller,
- * it is extended, and the new space is initialized to zero.
- *
- * @param[in] fd The file descriptor referring to the file to truncate. This must be a valid open file descriptor.
- * @param[in] length The new length of the file. The file will be truncated or extended to this size.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note The file descriptor `fd` must be opened with write permissions for this operation to succeed.
- */
- sysret_t sys_ftruncate(int fd, size_t length)
- {
- int ret;
- ret = ftruncate(fd, length);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Set file access and modification times.
- *
- * This function updates the access and modification times of a file or directory referenced by `__fd` or `__path`.
- * If `__fd` is a valid file descriptor, the times will be applied to the file or directory it refers to.
- * If `__fd` is `AT_FDCWD`, the times will be applied to the file or directory specified by `__path`.
- * The `__times` argument consists of two `timespec` values: the first represents the access time,
- * and the second represents the modification time. If `__times` is `NULL`, the current time is used.
- *
- * @param[in] __fd The file descriptor of the file or directory to modify, or `AT_FDCWD` to modify using `__path`.
- * @param[in] __path The path to the file or directory to modify. Ignored if `__fd` is not `AT_FDCWD`.
- * @param[in] __times An array of two `timespec` structures. The first element is the access time, and the second is the modification time.
- * If `__times` is `NULL`, the current time is used for both access and modification times.
- * @param[in] __flags Flags to modify behavior. Supported flags include:
- * - `AT_SYMLINK_NOFOLLOW`: Do not follow symbolic links.
- * - `AT_NO_AUTOMOUNT`: Do not trigger automounting.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note This function modifies both access and modification times of files, and may affect file system timestamps.
- */
- sysret_t sys_utimensat(int __fd, const char *__path, const struct timespec __times[2], int __flags)
- {
- #ifdef RT_USING_DFS_V2
- #ifdef ARCH_MM_MMU
- int ret = -1;
- rt_size_t len = 0;
- char *kpath = RT_NULL;
- len = lwp_user_strlen(__path);
- if (len <= 0)
- {
- return -EINVAL;
- }
- kpath = (char *)kmem_get(len + 1);
- if (!kpath)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kpath, (void *)__path, len + 1);
- ret = utimensat(__fd, kpath, __times, __flags);
- kmem_put(kpath);
- return ret;
- #else
- if (!lwp_user_accessable((void *)__path, 1))
- {
- return -EFAULT;
- }
- int ret = utimensat(__fd, __path, __times, __flags);
- return ret;
- #endif
- #else
- return -1;
- #endif
- }
- /**
- * @brief Change file permissions.
- *
- * This function changes the permissions of a file or directory specified by the `pathname`.
- * The new permissions are specified using the `mode` argument, which is a bitwise OR of permission bits.
- * The permissions apply to the file owner, group, and others, depending on the value of `mode`.
- *
- * @param[in] pathname The path to the file or directory whose permissions are to be changed.
- * @param[in] mode The new permissions to set, represented as a bitwise OR of permission flags.
- * For example, `S_IRUSR`, `S_IWUSR`, `S_IRGRP`, etc.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note If the file or directory is a symbolic link, this function will modify the permissions of the symbolic link itself,
- * not the target file or directory.
- */
- sysret_t sys_chmod(const char *pathname, mode_t mode)
- {
- char *copy_file;
- size_t len_file, copy_len_file;
- struct dfs_attr attr = {0};
- int ret = 0;
- len_file = lwp_user_strlen(pathname);
- if (len_file <= 0)
- {
- return -EFAULT;
- }
- copy_file = (char*)rt_malloc(len_file + 1);
- if (!copy_file)
- {
- return -ENOMEM;
- }
- copy_len_file = lwp_get_from_user(copy_file, (void *)pathname, len_file);
- attr.st_mode = mode;
- attr.ia_valid |= ATTR_MODE_SET;
- copy_file[copy_len_file] = '\0';
- ret = dfs_file_setattr(copy_file, &attr);
- rt_free(copy_file);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Change the ownership of a file or directory.
- *
- * This function changes the owner and/or group of the file or directory specified by `pathname`.
- * The `owner` and `group` parameters represent the new owner and group IDs, respectively. If either
- * parameter is set to `-1`, that aspect (owner or group) will remain unchanged.
- *
- * @param[in] pathname The path to the file or directory whose ownership is to be changed.
- * @param[in] owner The new owner ID. If set to `-1`, the owner's ID is not changed.
- * @param[in] group The new group ID. If set to `-1`, the group's ID is not changed.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note The caller must have the appropriate permissions (i.e., be the superuser or the file owner)
- * to change the ownership of a file or directory.
- */
- sysret_t sys_chown(const char *pathname, uid_t owner, gid_t group)
- {
- char *copy_file;
- size_t len_file, copy_len_file;
- struct dfs_attr attr = {0};
- int ret = 0;
- len_file = lwp_user_strlen(pathname);
- if (len_file <= 0)
- {
- return -EFAULT;
- }
- copy_file = (char*)rt_malloc(len_file + 1);
- if (!copy_file)
- {
- return -ENOMEM;
- }
- copy_len_file = lwp_get_from_user(copy_file, (void *)pathname, len_file);
- if(owner >= 0)
- {
- attr.st_uid = owner;
- attr.ia_valid |= ATTR_UID_SET;
- }
- if(group >= 0)
- {
- attr.st_gid = group;
- attr.ia_valid |= ATTR_GID_SET;
- }
- copy_file[copy_len_file] = '\0';
- ret = dfs_file_setattr(copy_file, &attr);
- rt_free(copy_file);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- #ifndef LWP_USING_RUNTIME
- sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void))
- {
- /* if no LWP_USING_RUNTIME configured */
- return -ENOSYS;
- }
- #endif
- /**
- * @brief Reboot the system.
- *
- * This function initiates a system reboot with a specific reboot type and optional arguments.
- * The reboot process is performed by passing `magic` and `magic2` as security keys to validate the
- * reboot request, along with the desired reboot type (`type`) and optional argument (`arg`) that
- * may contain additional parameters depending on the reboot type.
- *
- * @param[in] magic A magic number for security validation, typically used to verify that the caller
- * has sufficient privileges (e.g., root).
- * @param[in] magic2 A second magic number for additional security verification, used in combination
- * with `magic` to validate the reboot request.
- * @param[in] type The type of reboot to perform, such as `RB_AUTOBOOT`, `RB_HALT`, `RB_RESTART`,
- * etc. The exact values may depend on the platform.
- * @param[in] arg An optional argument for the reboot process. This can provide additional data,
- * such as a specific shutdown procedure, depending on the type of reboot.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note This operation is typically available to the system administrator (root) and should be used
- * with caution as it can cause the system to restart or shut down.
- */
- sysret_t sys_reboot(int magic, int magic2, int type, void *arg)
- {
- sysret_t rc;
- switch (type)
- {
- /* Hardware reset */
- case RB_AUTOBOOT:
- rc = lwp_teardown(lwp_self(), rt_hw_cpu_reset);
- break;
- /* Stop system and switch power off */
- case RB_POWER_OFF:
- rc = lwp_teardown(lwp_self(), rt_hw_cpu_shutdown);
- break;
- default:
- rc = -ENOSYS;
- }
- return rc;
- }
- /**
- * @brief Read data from a file descriptor at a specific offset.
- *
- * This function reads data from a file descriptor `fd` into the buffer `buf`, starting from the
- * specified byte `offset`. Unlike a regular `read` call, `sys_pread64` allows the file pointer to
- * remain unchanged after the read, as the operation directly accesses the file at the provided
- * offset.
- *
- * @param[in] fd The file descriptor from which to read. It must be a valid open file descriptor.
- * @param[out] buf A pointer to the buffer where the read data will be stored.
- * @param[in] size The number of bytes to read from the file.
- * @param[in] offset The offset in bytes from the beginning of the file to start reading from.
- *
- * @return ssize_t On success, returns the number of bytes read (which may be less than `size` if
- * the end of the file is reached). On error, returns a negative error code.
- *
- * @note This function is particularly useful for random access to files, allowing for efficient
- * reads from arbitrary positions without affecting the current file pointer.
- */
- ssize_t sys_pread64(int fd, void *buf, int size, size_t offset)
- #ifdef RT_USING_DFS_V2
- {
- ssize_t pread(int fd, void *buf, size_t len, size_t offset);
- #ifdef ARCH_MM_MMU
- ssize_t ret = -1;
- void *kmem = RT_NULL;
- if (!size)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)buf, size))
- {
- return -EFAULT;
- }
- kmem = kmem_get(size);
- if (!kmem)
- {
- return -ENOMEM;
- }
- ret = pread(fd, kmem, size, offset);
- if (ret > 0)
- {
- lwp_put_to_user(buf, kmem, ret);
- }
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmem);
- return ret;
- #else
- if (!lwp_user_accessable((void *)buf, size))
- {
- return -EFAULT;
- }
- ssize_t ret = pread(fd, kmem, size, offset);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- #else
- {
- ssize_t ret = -ENOSYS;
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- #endif
- /**
- * @brief Write data to a file descriptor at a specific offset.
- *
- * This function writes data from the buffer `buf` to the file descriptor `fd`, starting at the
- * specified byte `offset`. Unlike a regular `write` call, `sys_pwrite64` allows the file pointer to
- * remain unchanged after the write, as the operation directly writes the data to the file at the
- * provided offset.
- *
- * @param[in] fd The file descriptor to which the data will be written. It must be a valid open
- * file descriptor.
- * @param[in] buf A pointer to the buffer containing the data to be written.
- * @param[in] size The number of bytes to write to the file.
- * @param[in] offset The offset in bytes from the beginning of the file to start writing to.
- *
- * @return ssize_t On success, returns the number of bytes written (which may be less than `size` if
- * the write operation is partial). On error, returns a negative error code.
- *
- * @note This function is particularly useful for random access to files, allowing for efficient
- * writes to arbitrary positions without affecting the current file pointer.
- */
- ssize_t sys_pwrite64(int fd, void *buf, int size, size_t offset)
- #ifdef RT_USING_DFS_V2
- {
- ssize_t pwrite(int fd, const void *buf, size_t len, size_t offset);
- #ifdef ARCH_MM_MMU
- ssize_t ret = -1;
- void *kmem = RT_NULL;
- if (!size)
- {
- return -EINVAL;
- }
- if (!lwp_user_accessable((void *)buf, size))
- {
- return -EFAULT;
- }
- kmem = kmem_get(size);
- if (!kmem)
- {
- return -ENOMEM;
- }
- lwp_get_from_user(kmem, (void *)buf, size);
- ret = pwrite(fd, kmem, size, offset);
- if (ret < 0)
- {
- ret = GET_ERRNO();
- }
- kmem_put(kmem);
- return ret;
- #else
- if (!lwp_user_accessable((void *)buf, size))
- {
- return -EFAULT;
- }
- ssize_t ret = pwrite(fd, kmem, size, offset);
- return (ret < 0 ? GET_ERRNO() : ret);
- #endif
- }
- #else
- {
- ssize_t ret = -ENOSYS;
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- #endif
- /**
- * @brief Create a timer file descriptor.
- *
- * This function creates a timer that can be used to notify a process after a specified
- * amount of time has passed. The timer is represented by a file descriptor, which can be
- * used with functions such as `read` and `poll` to monitor and retrieve notifications
- * about timer expirations.
- *
- * @param[in] clockid The clock to use for the timer. Possible values include:
- * - `CLOCK_REALTIME`: The system's real-time clock.
- * - `CLOCK_MONOTONIC`: A clock that cannot be set and is not affected by
- * changes in the system time.
- * @param[in] flags Flags that modify the behavior of the timer. The commonly used values are:
- * - `TFD_CLOEXEC`: Set the close-on-exec flag for the file descriptor.
- * - `TFD_NONBLOCK`: Set the non-blocking flag for the file descriptor.
- *
- * @return sysret_t On success, returns a non-negative file descriptor that refers to the timer.
- * On failure, returns a negative error code.
- *
- * @note The timer created by this function can be used to create periodic or one-shot timers.
- * The timer can be configured using `timerfd_settime` and notifications can be retrieved
- * by reading from the returned file descriptor.
- */
- sysret_t sys_timerfd_create(int clockid, int flags)
- {
- int ret;
- ret = timerfd_create(clockid, flags);
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Set or modify the expiration time for a timer.
- *
- * This function is used to arm or re-arm a timer associated with a file descriptor created
- * by `sys_timerfd_create`. It allows setting a new expiration time and can also return
- * the previous timer configuration.
- *
- * @param[in] fd The file descriptor referring to the timer, which was created using
- * `sys_timerfd_create`.
- * @param[in] flags Flags that modify the behavior of the timer. The commonly used values are:
- * - `TFD_TIMER_ABSTIME`: If set, the `new` expiration time is an absolute time.
- * - `TFD_TIMER_RELATIVE`: The default behavior, where `new` expiration time is
- * a relative time from now.
- * @param[in] new A pointer to a `struct itimerspec` specifying the new expiration time.
- * It contains two fields:
- * - `it_value`: The initial expiration time of the timer.
- * - `it_interval`: The period of periodic timers (if zero, the timer is one-shot).
- * @param[out] old A pointer to a `struct itimerspec` where the previous timer configuration
- * will be stored. This can be `NULL` if the previous configuration is not needed.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note This function allows for both one-shot and periodic timers. If the timer is periodic,
- * it will continue triggering at intervals specified in `it_interval` until canceled or modified.
- * When a timer expires, the associated file descriptor becomes readable, and the application
- * can retrieve the expiration event by reading from the file descriptor.
- */
- sysret_t sys_timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itimerspec *old)
- {
- int ret = -1;
- struct itimerspec *knew = RT_NULL;
- struct itimerspec *kold = RT_NULL;
- if (new == RT_NULL)
- return -EINVAL;
- if (!lwp_user_accessable((void *)new, sizeof(struct itimerspec)))
- {
- return -EFAULT;
- }
- knew = kmem_get(sizeof(struct itimerspec));
- if (knew)
- {
- lwp_get_from_user(knew, (void*)new, sizeof(struct itimerspec));
- if (old)
- {
- if (!lwp_user_accessable((void *)old, sizeof(struct itimerspec)))
- {
- kmem_put(knew);
- return -EFAULT;
- }
- kold = kmem_get(sizeof(struct itimerspec));
- if (kold == RT_NULL)
- {
- kmem_put(knew);
- return -ENOMEM;
- }
- }
- ret = timerfd_settime(fd, flags, knew, kold);
- if (old)
- {
- lwp_put_to_user(old, kold, sizeof(*kold));
- kmem_put(kold);
- }
- kmem_put(knew);
- }
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Retrieve the current configuration of a timer.
- *
- * This function is used to obtain the current expiration time and interval of a timer associated
- * with a file descriptor created by `sys_timerfd_create`. It allows querying the current state
- * of the timer, including the time remaining until the next expiration and the period (for periodic timers).
- *
- * @param[in] fd The file descriptor referring to the timer, which was created using
- * `sys_timerfd_create`.
- * @param[out] cur A pointer to a `struct itimerspec` where the current timer configuration will
- * be stored. This structure contains:
- * - `it_value`: The time remaining until the timer expires.
- * - `it_interval`: The period for periodic timers (zero for one-shot timers).
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note The timer's `it_value` field will contain the time remaining until the next expiration.
- * If the timer is periodic, the `it_interval` field will contain the period for the next expiration.
- * If the timer has expired and there is no further interval (for one-shot timers), `it_value` will
- * contain a value of `0`.
- */
- sysret_t sys_timerfd_gettime(int fd, struct itimerspec *cur)
- {
- int ret = -1;
- struct itimerspec *kcur;
- if (cur == RT_NULL)
- return -EINVAL;
- if (!lwp_user_accessable((void *)cur, sizeof(struct itimerspec)))
- {
- return -EFAULT;
- }
- kcur = kmem_get(sizeof(struct itimerspec));
- if (kcur)
- {
- lwp_get_from_user(kcur, cur, sizeof(struct itimerspec));
- ret = timerfd_gettime(fd, kcur);
- lwp_put_to_user(cur, kcur, sizeof(struct itimerspec));
- kmem_put(kcur);
- }
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- /**
- * @brief Create a file descriptor for receiving signals.
- *
- * This function creates a file descriptor that can be used to receive signals, similar to how a
- * regular file descriptor is used. The signals specified in the provided signal mask are blocked
- * for the calling thread, and any matching signals will be reported through the file descriptor.
- * This allows signals to be handled in a more controlled, non-interrupt-driven way by using
- * standard I/O operations (e.g., `read()` or `select()`) on the file descriptor.
- *
- * @param[in] fd A file descriptor associated with the process, typically obtained from
- * `sys_signalfd()` or a similar mechanism. If `fd` is `-1`, a new file descriptor
- * will be created.
- * @param[in] mask A pointer to the signal mask (`sigset_t`) that specifies the signals that
- * should be received by the file descriptor. Only signals in the mask will be
- * reported.
- * @param[in] flags Additional flags to control the behavior of the signalfd. Common flags
- * include `O_NONBLOCK` for non-blocking operation.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note The caller must call `read()` on the resulting file descriptor to actually receive signals.
- * Each read returns a `struct signalfd_siginfo` containing the signal number, and additional
- * information, such as the signal source and sender.
- *
- * @see sys_read(), sigprocmask(), sigaction(), sigsuspend().
- */
- sysret_t sys_signalfd(int fd, const sigset_t *mask, int flags)
- {
- int ret = 0;
- sigset_t *kmask = RT_NULL;
- #ifdef RT_USING_MUSLLIBC
- if (mask == RT_NULL)
- return -EINVAL;
- if (!lwp_user_accessable((void *)mask, sizeof(struct itimerspec)))
- {
- return -EFAULT;
- }
- kmask = kmem_get(sizeof(struct itimerspec));
- if (kmask)
- {
- if (lwp_get_from_user(kmask, (void *)mask, sizeof(struct itimerspec)) != sizeof(struct itimerspec))
- {
- kmem_put(kmask);
- return -EFAULT;
- }
- ret = signalfd(fd, mask, flags);
- kmem_put(kmask);
- }
- #endif
- return (ret < 0 ? GET_ERRNO() : ret);
- }
- sysret_t sys_memfd_create()
- {
- return 0;
- }
- /**
- * @brief Set the value of an interval timer.
- *
- * This function is used to set the value of a specified timer that generates periodic signals
- * after the specified intervals. The timer can be configured to generate a signal when it expires,
- * and it can be used for tasks like scheduling periodic events.
- *
- * @param[in] which Specifies which timer to set. Possible values include:
- * - `ITIMER_REAL`: Timer that decrements in real time and sends `SIGALRM` when expired.
- * - `ITIMER_VIRTUAL`: Timer that decrements only while the process is executing.
- * - `ITIMER_PROF`: Timer that decrements while the process is executing or when it is
- * executing in the kernel.
- * @param[in] new A pointer to a `struct itimerspec` containing the new value for the timer.
- * The `itimerspec` structure contains two `timespec` fields: `it_value` for the initial
- * expiration time and `it_interval` for the interval between successive expirations.
- * @param[out] old A pointer to a `struct itimerspec` where the previous timer values (before the
- * timer is set) will be stored.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note If the specified timer is already active, it will be updated with the new values. The timer
- * will start at the `it_value` time and will repeat at the interval specified in `it_interval`.
- * If `it_interval` is set to `0`, the timer will not repeat and will only expire once.
- *
- * @see sys_getitimer(), sigaction(), alarm(), setitimer().
- */
- sysret_t sys_setitimer(int which, const struct itimerspec *restrict new, struct itimerspec *restrict old)
- {
- sysret_t rc = 0;
- rt_lwp_t lwp = lwp_self();
- struct itimerspec new_value_k;
- struct itimerspec old_value_k;
- if (lwp_get_from_user(&new_value_k, (void *)new, sizeof(*new)) != sizeof(*new))
- {
- return -EFAULT;
- }
- rc = lwp_signal_setitimer(lwp, which, &new_value_k, &old_value_k);
- if (old && lwp_put_to_user(old, (void *)&old_value_k, sizeof old_value_k) != sizeof old_value_k)
- return -EFAULT;
- return rc;
- }
- /**
- * @brief Set the robust list for the current thread.
- *
- * The `sys_set_robust_list` function sets the robust list for the calling thread. The robust list is
- * a list of `struct robust_list_head` elements that contain information about mutexes or other
- * resources that need to be cleaned up if the thread dies unexpectedly.
- *
- * This function is typically used for thread safety in multi-threaded programs, where robust mutexes
- * can be used to avoid leaving resources in an inconsistent state when a thread is terminated
- * without properly unlocking locks or releasing resources.
- *
- * @param[in] head A pointer to the robust list to be set. This list contains `struct robust_list_head`
- * entries which are used by the kernel to maintain information about robust mutexes.
- * @param[in] len The length of the robust list (the number of entries in the list). This should correspond
- * to the size of the list in memory, generally expressed in bytes.
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note The robust list should be set during the initialization of a thread or task, and it may be
- * used by the kernel to track which mutexes need to be cleaned up in case of failure.
- * The list may be manipulated using related functions such as `sys_get_robust_list`.
- *
- * @see sys_get_robust_list(), robust_mutex, pthread_mutex, set_robust_list.
- */
- sysret_t sys_set_robust_list(struct robust_list_head *head, size_t len)
- {
- if (len != sizeof(*head))
- return -EINVAL;
- rt_thread_self()->robust_list = head;
- return 0;
- }
- /**
- * @brief Get the robust list for the specified thread.
- *
- * The `sys_get_robust_list` function retrieves the robust list associated with the given thread.
- * The robust list contains `struct robust_list_head` entries used by the kernel to manage
- * robust mutexes and other resources that need to be cleaned up if the thread terminates unexpectedly.
- *
- * This function is primarily used to retrieve the robust list for a specific thread, so that
- * the caller can inspect or manipulate the robust list to handle clean-up operations in case
- * the thread exits while holding resources.
- *
- * @param[in] tid The thread ID of the thread whose robust list is to be retrieved.
- *
- * @param[out] head_ptr A pointer to a pointer to `struct robust_list_head`. On success,
- * this will point to the robust list for the specified thread.
- *
- * @param[out] len_ptr A pointer to a variable that will hold the length of the robust list
- * (i.e., the number of entries in the list).
- *
- * @return sysret_t On success, returns `0`. On failure, returns a negative error code.
- *
- * @note The robust list is used to track mutexes and other resources that need to be cleaned up
- * if a thread terminates without releasing the resources properly. It is typically used by
- * the kernel for thread safety and resource management in multi-threaded programs.
- *
- * @see sys_set_robust_list(), robust_mutex, pthread_mutex, get_robust_list.
- */
- sysret_t sys_get_robust_list(int tid, struct robust_list_head **head_ptr, size_t *len_ptr)
- {
- rt_thread_t thread;
- size_t len;
- struct robust_list_head *head;
- if (!lwp_user_accessable((void *)head_ptr, sizeof(struct robust_list_head *)))
- {
- return -EFAULT;
- }
- if (!lwp_user_accessable((void *)len_ptr, sizeof(size_t)))
- {
- return -EFAULT;
- }
- if (tid == 0)
- {
- thread = rt_thread_self();
- head = thread->robust_list;
- }
- else
- {
- thread = lwp_tid_get_thread_and_inc_ref(tid);
- if (thread)
- {
- head = thread->robust_list;
- lwp_tid_dec_ref(thread);
- }
- else
- {
- return -ESRCH;
- }
- }
- len = sizeof(*(head));
- if (!lwp_put_to_user(len_ptr, &len, sizeof(size_t)))
- return -EFAULT;
- if (!lwp_put_to_user(head_ptr, &head, sizeof(struct robust_list_head *)))
- return -EFAULT;
- return 0;
- }
- const static struct rt_syscall_def func_table[] =
- {
- SYSCALL_SIGN(sys_exit), /* 01 */
- SYSCALL_SIGN(sys_read),
- SYSCALL_SIGN(sys_write),
- SYSCALL_SIGN(sys_lseek),
- SYSCALL_SIGN(sys_open), /* 05 */
- SYSCALL_SIGN(sys_close),
- SYSCALL_SIGN(sys_ioctl),
- SYSCALL_SIGN(sys_fstat),
- SYSCALL_SIGN(sys_poll),
- SYSCALL_SIGN(sys_nanosleep), /* 10 */
- SYSCALL_SIGN(sys_gettimeofday),
- SYSCALL_SIGN(sys_settimeofday),
- SYSCALL_SIGN(sys_exec),
- SYSCALL_SIGN(sys_kill),
- SYSCALL_SIGN(sys_getpid), /* 15 */
- SYSCALL_SIGN(sys_getpriority),
- SYSCALL_SIGN(sys_setpriority),
- SYSCALL_SIGN(sys_sem_create),
- SYSCALL_SIGN(sys_sem_delete),
- SYSCALL_SIGN(sys_sem_take), /* 20 */
- SYSCALL_SIGN(sys_sem_release),
- SYSCALL_SIGN(sys_mutex_create),
- SYSCALL_SIGN(sys_mutex_delete),
- SYSCALL_SIGN(sys_mutex_take),
- SYSCALL_SIGN(sys_mutex_release), /* 25 */
- SYSCALL_SIGN(sys_event_create),
- SYSCALL_SIGN(sys_event_delete),
- SYSCALL_SIGN(sys_event_send),
- SYSCALL_SIGN(sys_event_recv),
- SYSCALL_SIGN(sys_mb_create), /* 30 */
- SYSCALL_SIGN(sys_mb_delete),
- SYSCALL_SIGN(sys_mb_send),
- SYSCALL_SIGN(sys_mb_send_wait),
- SYSCALL_SIGN(sys_mb_recv),
- SYSCALL_SIGN(sys_mq_create), /* 35 */
- SYSCALL_SIGN(sys_mq_delete),
- SYSCALL_SIGN(sys_mq_send),
- SYSCALL_SIGN(sys_mq_urgent),
- SYSCALL_SIGN(sys_mq_recv),
- SYSCALL_SIGN(sys_thread_create), /* 40 */
- SYSCALL_SIGN(sys_thread_delete),
- SYSCALL_SIGN(sys_thread_startup),
- SYSCALL_SIGN(sys_thread_self),
- SYSCALL_SIGN(sys_channel_open),
- SYSCALL_SIGN(sys_channel_close), /* 45 */
- SYSCALL_SIGN(sys_channel_send),
- SYSCALL_SIGN(sys_channel_send_recv_timeout),
- SYSCALL_SIGN(sys_channel_reply),
- SYSCALL_SIGN(sys_channel_recv_timeout),
- SYSCALL_SIGN(sys_enter_critical), /* 50 */
- SYSCALL_SIGN(sys_exit_critical),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_brk)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_mmap2)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_munmap)),
- #ifdef ARCH_MM_MMU
- SYSCALL_USPACE(SYSCALL_SIGN(sys_shmget)), /* 55 */
- SYSCALL_USPACE(SYSCALL_SIGN(sys_shmrm)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_shmat)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_shmdt)),
- #else
- #ifdef RT_LWP_USING_SHM
- SYSCALL_SIGN(sys_shm_alloc), /* 55 */
- SYSCALL_SIGN(sys_shm_free),
- SYSCALL_SIGN(sys_shm_retain),
- SYSCALL_SIGN(sys_notimpl),
- #else
- SYSCALL_SIGN(sys_notimpl), /* 55 */
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_notimpl),
- #endif /* RT_LWP_USING_SHM */
- #endif /* ARCH_MM_MMU */
- SYSCALL_SIGN(sys_device_init),
- SYSCALL_SIGN(sys_device_register), /* 60 */
- SYSCALL_SIGN(sys_device_control),
- SYSCALL_SIGN(sys_device_find),
- SYSCALL_SIGN(sys_device_open),
- SYSCALL_SIGN(sys_device_close),
- SYSCALL_SIGN(sys_device_read), /* 65 */
- SYSCALL_SIGN(sys_device_write),
- SYSCALL_SIGN(sys_stat),
- SYSCALL_SIGN(sys_thread_find),
- SYSCALL_NET(SYSCALL_SIGN(sys_accept)),
- SYSCALL_NET(SYSCALL_SIGN(sys_bind)), /* 70 */
- SYSCALL_NET(SYSCALL_SIGN(sys_shutdown)),
- SYSCALL_NET(SYSCALL_SIGN(sys_getpeername)),
- SYSCALL_NET(SYSCALL_SIGN(sys_getsockname)),
- SYSCALL_NET(SYSCALL_SIGN(sys_getsockopt)),
- SYSCALL_NET(SYSCALL_SIGN(sys_setsockopt)), /* 75 */
- SYSCALL_NET(SYSCALL_SIGN(sys_connect)),
- SYSCALL_NET(SYSCALL_SIGN(sys_listen)),
- SYSCALL_NET(SYSCALL_SIGN(sys_recv)),
- SYSCALL_NET(SYSCALL_SIGN(sys_recvfrom)),
- SYSCALL_NET(SYSCALL_SIGN(sys_send)), /* 80 */
- SYSCALL_NET(SYSCALL_SIGN(sys_sendto)),
- SYSCALL_NET(SYSCALL_SIGN(sys_socket)),
- SYSCALL_NET(SYSCALL_SIGN(sys_closesocket)),
- SYSCALL_NET(SYSCALL_SIGN(sys_getaddrinfo)),
- SYSCALL_NET(SYSCALL_SIGN(sys_gethostbyname2_r)), /* 85 */
- SYSCALL_NET(SYSCALL_SIGN(sys_sendmsg)),
- SYSCALL_NET(SYSCALL_SIGN(sys_recvmsg)),
- SYSCALL_SIGN(sys_notimpl), /* network */
- SYSCALL_SIGN(sys_notimpl), /* network */
- SYSCALL_SIGN(sys_notimpl), /* network, 90 */
- SYSCALL_SIGN(sys_notimpl), /* network */
- SYSCALL_SIGN(sys_notimpl), /* network */
- SYSCALL_SIGN(sys_notimpl), /* network */
- #ifdef RT_USING_DFS
- SYSCALL_SIGN(sys_select),
- #else
- SYSCALL_SIGN(sys_notimpl),
- #endif
- SYSCALL_SIGN(sys_notimpl), /* SYSCALL_SIGN(sys_hw_interrupt_disable), 95 */
- SYSCALL_SIGN(sys_notimpl), /* SYSCALL_SIGN(sys_hw_interrupt_enable) */
- SYSCALL_SIGN(sys_tick_get),
- SYSCALL_SIGN(sys_exit_group),
- SYSCALL_SIGN(sys_notimpl), /* rt_delayed_work_init */
- SYSCALL_SIGN(sys_notimpl), /* rt_work_submit, 100 */
- SYSCALL_SIGN(sys_notimpl), /* rt_wqueue_wakeup */
- SYSCALL_SIGN(sys_thread_mdelay),
- SYSCALL_SIGN(sys_sigaction),
- SYSCALL_SIGN(sys_sigprocmask),
- SYSCALL_SIGN(sys_tkill), /* 105 */
- SYSCALL_SIGN(sys_thread_sigprocmask),
- #ifdef ARCH_MM_MMU
- SYSCALL_SIGN(sys_cacheflush),
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_notimpl),
- #else
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_lwp_sighandler_set),
- SYSCALL_SIGN(sys_thread_sighandler_set),
- #endif
- SYSCALL_SIGN(sys_waitpid), /* 110 */
- SYSCALL_SIGN(sys_rt_timer_create),
- SYSCALL_SIGN(sys_rt_timer_delete),
- SYSCALL_SIGN(sys_rt_timer_start),
- SYSCALL_SIGN(sys_rt_timer_stop),
- SYSCALL_SIGN(sys_rt_timer_control), /* 115 */
- SYSCALL_SIGN(sys_getcwd),
- SYSCALL_SIGN(sys_chdir),
- SYSCALL_SIGN(sys_unlink),
- SYSCALL_SIGN(sys_mkdir),
- SYSCALL_SIGN(sys_rmdir), /* 120 */
- SYSCALL_SIGN(sys_getdents),
- SYSCALL_SIGN(sys_get_errno),
- #ifdef ARCH_MM_MMU
- SYSCALL_SIGN(sys_set_thread_area),
- SYSCALL_SIGN(sys_set_tid_address),
- #else
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_notimpl),
- #endif
- SYSCALL_SIGN(sys_access), /* 125 */
- SYSCALL_SIGN(sys_pipe),
- SYSCALL_SIGN(sys_clock_settime),
- SYSCALL_SIGN(sys_clock_gettime),
- SYSCALL_SIGN(sys_clock_getres),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_clone)), /* 130 */
- SYSCALL_USPACE(SYSCALL_SIGN(sys_futex)),
- SYSCALL_SIGN(sys_notimpl), /* discarded: sys_pmutex */
- SYSCALL_SIGN(sys_dup),
- SYSCALL_SIGN(sys_dup2),
- SYSCALL_SIGN(sys_rename), /* 135 */
- SYSCALL_USPACE(SYSCALL_SIGN(sys_fork)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_execve)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_vfork)),
- SYSCALL_SIGN(sys_gettid),
- SYSCALL_SIGN(sys_prlimit64), /* 140 */
- SYSCALL_SIGN(sys_getrlimit),
- SYSCALL_SIGN(sys_setrlimit),
- SYSCALL_SIGN(sys_setsid),
- SYSCALL_SIGN(sys_getrandom),
- SYSCALL_SIGN(sys_readlink), /* 145 */
- SYSCALL_USPACE(SYSCALL_SIGN(sys_mremap)),
- SYSCALL_USPACE(SYSCALL_SIGN(sys_madvise)),
- SYSCALL_SIGN(sys_sched_setparam),
- SYSCALL_SIGN(sys_sched_getparam),
- SYSCALL_SIGN(sys_sched_get_priority_max), /* 150 */
- SYSCALL_SIGN(sys_sched_get_priority_min),
- SYSCALL_SIGN(sys_sched_setscheduler),
- SYSCALL_SIGN(sys_sched_getscheduler),
- SYSCALL_SIGN(sys_sched_setaffinity),
- SYSCALL_SIGN(sys_fsync), /* 155 */
- SYSCALL_SIGN(sys_clock_nanosleep),
- SYSCALL_SIGN(sys_timer_create),
- SYSCALL_SIGN(sys_timer_delete),
- SYSCALL_SIGN(sys_timer_settime),
- SYSCALL_SIGN(sys_timer_gettime), /* 160 */
- SYSCALL_SIGN(sys_timer_getoverrun),
- SYSCALL_SIGN(sys_mq_open),
- SYSCALL_SIGN(sys_mq_unlink),
- SYSCALL_SIGN(sys_mq_timedsend),
- SYSCALL_SIGN(sys_mq_timedreceive), /* 165 */
- SYSCALL_SIGN(sys_mq_notify),
- SYSCALL_SIGN(sys_mq_getsetattr),
- SYSCALL_SIGN(sys_mq_close),
- SYSCALL_SIGN(sys_lstat),
- SYSCALL_SIGN(sys_uname), /* 170 */
- SYSCALL_SIGN(sys_statfs),
- SYSCALL_SIGN(sys_statfs64),
- SYSCALL_SIGN(sys_fstatfs),
- SYSCALL_SIGN(sys_fstatfs64),
- SYSCALL_SIGN(sys_openat), /* 175 */
- SYSCALL_SIGN(sys_mount),
- SYSCALL_SIGN(sys_umount2),
- SYSCALL_SIGN(sys_link),
- SYSCALL_SIGN(sys_symlink),
- SYSCALL_SIGN(sys_sched_getaffinity), /* 180 */
- SYSCALL_SIGN(sys_sysinfo),
- SYSCALL_SIGN(sys_chmod),
- SYSCALL_SIGN(sys_reboot),
- SYSCALL_SIGN(sys_sched_yield),
- SYSCALL_SIGN(sys_pread64), /* 185 */
- SYSCALL_SIGN(sys_pwrite64),
- SYSCALL_SIGN(sys_sigpending),
- SYSCALL_SIGN(sys_sigtimedwait),
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_notimpl), /* 190 */
- SYSCALL_SIGN(sys_eventfd2),
- SYSCALL_SIGN(sys_epoll_create1),
- SYSCALL_SIGN(sys_epoll_ctl),
- SYSCALL_SIGN(sys_epoll_pwait),
- SYSCALL_SIGN(sys_notimpl), /* 195 */
- SYSCALL_SIGN(sys_timerfd_create),
- SYSCALL_SIGN(sys_timerfd_settime),
- SYSCALL_SIGN(sys_timerfd_gettime),
- SYSCALL_SIGN(sys_signalfd),
- SYSCALL_SIGN(sys_memfd_create), /* 200 */
- SYSCALL_SIGN(sys_ftruncate),
- SYSCALL_SIGN(sys_setitimer),
- SYSCALL_SIGN(sys_utimensat),
- #ifdef RT_USING_POSIX_SOCKET
- SYSCALL_SIGN(sys_syslog),
- SYSCALL_SIGN(sys_socketpair), /* 205 */
- #else
- SYSCALL_SIGN(sys_notimpl),
- SYSCALL_SIGN(sys_notimpl), /* 205 */
- #endif
- SYSCALL_SIGN(sys_wait4),
- SYSCALL_SIGN(sys_set_robust_list),
- SYSCALL_SIGN(sys_get_robust_list),
- SYSCALL_SIGN(sys_setpgid),
- SYSCALL_SIGN(sys_getpgid), /* 210 */
- SYSCALL_SIGN(sys_getsid),
- SYSCALL_SIGN(sys_getppid),
- SYSCALL_SIGN(sys_fchdir),
- SYSCALL_SIGN(sys_chown),
- };
- const void *lwp_get_sys_api(rt_uint32_t number)
- {
- const void *func = (const void *)sys_notimpl;
- if (number == 0xff)
- {
- func = (void *)sys_log;
- }
- else
- {
- number -= 1;
- if (number < sizeof(func_table) / sizeof(func_table[0]))
- {
- func = func_table[number].func;
- }
- else
- {
- if (__sys_log_enable)
- {
- LOG_I("Unimplement syscall %d", number);
- }
- }
- }
- return func;
- }
- const char *lwp_get_syscall_name(rt_uint32_t number)
- {
- const char *name = "sys_notimpl";
- if (number == 0xff)
- {
- name = "sys_log";
- }
- else
- {
- number -= 1;
- if (number < sizeof(func_table) / sizeof(func_table[0]))
- {
- name = (char*)func_table[number].name;
- }
- else
- {
- if (__sys_log_enable)
- {
- LOG_I("Unimplement syscall %d", number);
- }
- }
- }
- /* skip sys_ */
- return name;
- }
|