From 75c2c9c9e87b32c92fc2184f5ae076034e2dc6f8 Mon Sep 17 00:00:00 2001 From: huangyuchen Date: Fri, 2 Jun 2023 17:54:09 +0800 Subject: [PATCH] Add guidances for newly implement functionality of `c_utils`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. guidance of rust Crate `utils_rust`,including modules `ashmem`,`directory_ex` and `file_ex`. 2. guidance of mapped file. 3. guidance of event handling system. Issue:I7C0ZL Test:NA Signed-off-by: huangyuchen Change-Id: I88903b3a4ad308b07b9963e8d9112b8a3698c5b1 --- README_zh.md | 18 +- docs/figs/io_event_reactor_structrues.png | Bin 0 -> 51914 bytes docs/zh-cn/c_utils_guide_event.md | 262 +++++++++++++++++++++ docs/zh-cn/c_utils_guide_mapped_file.md | 194 +++++++++++++++ docs/zh-cn/c_utils_guide_rust_ashmem.md | 103 ++++++++ docs/zh-cn/c_utils_guide_rust_directory.md | 49 ++++ docs/zh-cn/c_utils_guide_rust_file.md | 40 ++++ 7 files changed, 665 insertions(+), 1 deletion(-) create mode 100644 docs/figs/io_event_reactor_structrues.png create mode 100644 docs/zh-cn/c_utils_guide_event.md create mode 100644 docs/zh-cn/c_utils_guide_mapped_file.md create mode 100644 docs/zh-cn/c_utils_guide_rust_ashmem.md create mode 100644 docs/zh-cn/c_utils_guide_rust_directory.md create mode 100644 docs/zh-cn/c_utils_guide_rust_file.md diff --git a/README_zh.md b/README_zh.md index f9d4f87..8268824 100644 --- a/README_zh.md +++ b/README_zh.md @@ -37,6 +37,11 @@ commonlibrary/c_utils ./build.sh --product-name rk3568 --build-target commonlibrary/c_utils/base:utils ``` +### 编译Rust动态库 +``` +./build.sh --product-name rk3568 --build-target commonlibrary/c_utils/base:utils_rust +``` + ### 编译静态库 ``` ./build.sh --product-name rk3568 --build-target commonlibrary/c_utils/base:utilsbase @@ -55,6 +60,8 @@ ohos_shared_library("xxxxx") { "c_utils:utils", # 静态库依赖(可选) "c_utils:utilsbase", + # Rust动态库依赖(可选) + "c_utils:utils_rust", ] ... @@ -63,11 +70,15 @@ ohos_shared_library("xxxxx") { ## 使用说明 +### [Rust-匿名共享内存](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c_utils_guide_rust_ashmem.md) +### [Rust-文件与目录](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c_utils_guide_rust_directory.md) + ### [使用匿名共享内存](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-ashmem.md) ### [使用智能指针管理动态分配内存对象](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-refbase.md) ### [使用Parcel作为数据容器](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-parcel.md) ### [定时器](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c_utils_timer.md) - +### [文件映射](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c_utils_mapped_file.md) +### [事件处理系统](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c_utils_event.md) ### [读写锁](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-rwlock.md) ### [增强信号量功能](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-semaphore.md) ### [强化线程能力](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-thread.md) @@ -89,6 +100,11 @@ ohos_shared_library("xxxxx") { ### [管理、传递文件描述符](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-uniquefd.md) ## Changelog +**2023/06/14** +1. 添加文件映射、事件处理系统的开发指导文档。 +2. Refbase维测增强部分已更新至文档。 +3. 添加Rust相关功能的开发指导文档并提供编译命令。 + **2023/01/31** 1. 添加docs目录,提供c_utils内各主要功能的开发指导文档。 2. 在源码头文件中添加注释。 diff --git a/docs/figs/io_event_reactor_structrues.png b/docs/figs/io_event_reactor_structrues.png new file mode 100644 index 0000000000000000000000000000000000000000..1d2bf029709c097a01f7fc025f377e4c2dbd480b GIT binary patch literal 51914 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 u$>ZO&d% zP3}84HM%-~Wg0Sv8N~o?jJOg&;j;G1bS;NA9UQr%Zu@T}06W4IRehs@`jBe2q z7Y;<446cz-u!j#_A;EaqQ=gojI^oiit{g=n8Z&plF#MOrb&U7lgUZEzqiEHHRAs5# zonmgwW&1XYKA*|9ZHbMBgd90p{kvNX`%{2MHX2McN1wRjtbE(CBw# z{)NDB4|xlUTV3%>G};~Co6T(LvMFZT#kQZ?4AVwkaA#)?N)yk{-MgEj=BZw%i2{}Q zBsqB+SH^{6v0=tk6|=anl1YOWu&XWu^YJweco={?dhwiwQd;-(vz zo8JufZ|#)sa9ncv&wbKEAaqikL=`H52ok_Xv1>$T%UvT!0+?iI0EY+X$&`;TZ|OXk zIJ)h@qWh!Ll4h9x3xTDbc#NW`s=_~#643di`Is?UVfnP|Uc+4bmAG2bF2E$--J?R| z2Ua_@<(kvSkJr#z11BkQ;-VT*2rJPL-a}8X5xyTGUssmAZI1`$DlIc!IK`D8PgM=j zK~bnV=^3uT;kRnA={+~KL_5Y!X!Bq(jqk30v%TCNrlz91XyolPeL0{;qZW%O6w#m7 z=j^`EVDONU#bCK6omqYJD%mkA!yuTFRy`!%aXZ(pdbQJsxGKJKoTzosf`e ztX=B?b_R?eAC}Nh#E__L)Y#xcH=uA5B3_s$ve*QBq-gc4pU`MajAU(~l^tzqxf#jJ zPaq#8uWT-eZZ{*->~&c@)qcZoVl7)SK2Y0+XjB&*G1z$f%PH=Tqx!y5k8sS9K|pRi z2-=&eu( z56JP?Uqa=TD|o-QL3R>3DnT5-p;esNk}D7Ch@uSlHfSV1C}>V-v1whN2+4jfM)42pn-O==_BX*MRw&l%5LLVxnP0!Pc)Z>GW$iyI3z`7=N$V5id;81DkKyk+OzO3fp7HS->gTsfU6(Ciq0jm3*&TqoFv{rihghqe z{e#<#DJ{XHAItGpkIh^6zWQcq%Ov|%ngoy($=wj%NlaI}jdM>_f)>{$tmfaj5HxFbAP-e47(0{9HU&Ol-jf=Alew3gX%adGIZJA_TV$CMfsMWhjS zlRGrLUDoBx!_4RZ6=w15>PFqo!Ht*mJ#hca#)Bfhn8{=FAG<=M>14+_ zSTK+R^oKq@J3AX2vs^?WUe&oGn*;n$zgqXV~oGd{C#k%Z$FrqC zbChdcUR8_LAuu#XawFBd#N2i6=Mwe`O(d|8tPYKEi^(hM4|1+}O~xXlWLlp^lofJIvb?l+ID zNB`Exe_|WA1JGyU!Dh|?6d#8oBU{Ko9einqsb66;rp}nL9v~D)+7Tolbe1NA2fJPK zTWpCc#J?VP1JExm@Ezy_iOB(O1GuWn(Rwo8tMaX$i*^&p$GTI84sOVzf;Fn=FfVg( zo46%SJiAKa-eTKe|+ z&s)%(8!N$bYS*cA6h+6MK|$JB3(TS8zkL2YIH$X1up6MmH|=-RRhMvj2`Ph8Yq+%3 zR4cS<$2g82f#$_;Hr@Ma`A(g{J4M0T8Aofo#ZT1TB#&7q}q+|&LrOO3ZRp0j>bfLpX0VM80u+>mBOu z9evpc4AU9AJ9Xe^g5b39e~HwROJg(xT7h6IHIC@wLT3kQXk*x&vd$wSzFCHVaZ~cI? zgp8mV?LN64mrxxZ8<5#GH?`Km8kS*Gzx7WZ!7~7VIary*lL;=QZo4Chk=DqK*LZn( z)eB2V)N^K(gLvv;2xCPSh4dQjiVgho`@%xv`Zg4-)f-Xx)Qf@5hd}qxa70V9$>5oV z&DZiAEs;>Tmllw`yV`qeDr*}D+hOD35*u8Mlc8AulUcY{UR@t&VcI^0Pl~RX9BM}2D zqE2}=xJ7+P11T%%=t0IeAlS6uczurr*Okop{fzwFAf)B3=K9E^F1ld0S5eA9HoVoN zqrWm8qKbml;L_<)vGHcSbgbr$F{utDob;Lj;2N38&A8-MTeLW{u;sL%J-at9cVD)A zc{FVfVPG|x4j{nbFBm6b3;~`IG7z-*P_pKXsGce~E5lW{s+!)$sShM^W$W27Eid{_m!~pJnq7nh^9q{| zYMxB&@ZiXo{yVs1D&2~|@zHI)sk<+i7o{}OnO+ku@{}1fL?a`q%l0dK$Z)jsQ=gF( z8R#B!x3wZ{qo8Ez(%!3CszdMC&z*bpmFJ`_+v}e-$W+fw3T!FSJ`{=EWk>kH^g2r` z%8M72eO@5{0!WBi$;4f6&9^1KP7U>%Jo`V(JvvUDm-W1N3hGYIK~s)@20eB1=*jWm zTC%9|@)cr2R}RHHXKgn?NIKR(@L*9`l<&@n&~YBtgUs_Y;+tkrPfVk(gP-v78aH-q zhq+Oh^F;s1JiJ3N9W+eRIZj~e_QBwlYicS;J-eH)%uUuiclN9%rT>j~)80*aO~EIyuygCLiptKbG3mUDlP_F8t)2@=fCXuxTe;G#>IQ~Z2U zy_z)-@h8lw8Ubatf4dm(6wbob2Dd(T=}0<&HVtdPMHGM^-jonWz@^`nESxhs(#>NR zLom@D=(m0QDg&sLcX(kk0VH%xS^KoQ_}k+99dx{#+2?D3b!S0iKku7o|Mk&Jy-xUD zMJ6EQQU1~ibgkV0+UG8I1WJ2Al`KR(gPX!Jrd2O(kLo(>MQG{zVF+Y<&06Rsc4Y#d#sET6lnN_#mBEC z9JEq`S5>Us`w>?9&%=jXi9W+}37e$K0C0xz;b~lh+qmQ*Ur#2ml~?>NYbYKy)2iY` zUx@sIyFDM=+;!=~h2Z^{+dKbx_Hj~DdkQX@A|xvCzDc~zeIwKDUZ^vY;4t*%4(w`7 zt=om^`y?_K@cCOd5r4gO@8ndQjD~IV6EreV z=8in$G6QFbJCSM)^UP<|8SBv($VPccJ#rFLolp{%mzD%v`%QPRp!9bctOTtWK9w1F+7gn1YA)IQY);p;xAy&B@0{hb zfW(&i0`u*{Qt7%EevJI5#UTRFc}T@xOG1d)yJzi^y1lJ>PZBZ345u+?{EJ5=5G2Z> z`CZ>8zDvFM3mmM3cs>Vle0DXul;A>XygMhDfSodLrtY@E>-5u?R%KsWgwy5p95K@f%6T|(Z@bss5--7{ z)e>1T+X0Hxy%+4+>naM3+pam60t%CsU(5Kqbxcw6%CXCX?6S+POkKTZBQ@N?A+OZWPV^zi9*2xpE9*aZ2Xn_ zr)O{`IQRJ8#iKoyF22HjUIVR|Q1sv7 z1D@VE98ULKFqi0H(yRyRivWGKTMtMO2?>AOPm(6YoxqW`Yslyxi95t4NNKn5m1nzS zx&Z-p#DZSRZ4o&8V9sEleN2UtT-qrl-O|<$fNgTCNp)EjRkUl-n|DNOT+|tH&-!#R z)ZN;H2V1atlTSN=?_gMy`65_~HS)sRla$?IMxgyTTb|i?cZXSK`bFYI!`UJNTTyV8 z56Cv#w?aJSHYm6I_F7OM%IQRc_G<(q!BLxxk5~jw{$8e~BEDBC%Re)2)8@^!Lw1kb z^Y1jefDggL@kbyn5MQhaG_YU)xFi~7N|G>}}e6P7m zbHj!fQ=)GG%&H9y3+B5!IY{T&2&%*zViLQ}K}n&CWH*ZSPqvt@@(g0@Ps2QZv)cP9 zUpkE_I$5hYKf{y~8@(z;YCW-`#GQzYoOEU-hbKd6t{K|v={W_Z-}$DY5OXaDZ==MM z{{9REuLf+M5YD8^3k$$jwsp*@wW`!`P=cM+xP8tQiMU1fj`fJZ-L~b|uGeI62kP zCZ+M!{+ldZYeBd>bu2q-K6+!@(|3vOf*35#3_Mh_=li?cCR3$h|@JT5s&N zNo(_pm8%MDR;A_DeHYRDRDP0UT2jKK;_#%B)303e3!?8?o}=1o7x)JVn(`-?r9}v? z1%JJCB*dHCX7Ad#ZrzE%&K)}ZiB$p-kQx``kYU5jeGD;Q$lMEDP@T|J#QB=mZ>l|Q zos{`;41gvsqzj*$<6^id&98kWo z$zyz+?B?9n(&8qud_$orDQwVy*AW$hj9h0(7f@J7F8tfmX3c7kLUadL z{}#r*`llV+3gzn^(*^QXANKR0}*LHiRY|(H!+cOVo)ZB)}vES_yWYQP8qcp6FbKS*-BeLaR&K~d7CiL z{00UK!)Yh%hx#nbfg!T+#&$PylRg8sHTd&>;eCL|tkX%d7`Z8Tq!a^)b_@*NN5;ss zvPV^oeWJQV!C!l8v{N%XpZ6+XhkUu_zs*-V?W(=1`+!V$8!$#3&D!7451j!z=s zFGIVky-mqo$tsd0%PKM&xt5y5U>f$ZP(;IPT#XnL^;e+6s%l(nPD3X;oevI%(*Awc z#z!Z^UwdWB^X`^csAssz&2@Rjr7j&h49;nJhu#pINbBYq z`Hc~JJ)rKcJTqu789*oL3ym7B2kM@JGRR=M*lSf5^mP)yxhb{ z!mv_YeCmumA}j5ZK7KAws<-TfP^f&2D=C^o!*};aY9O}DE?uqzri+D4roDPQrC%k6 zO|^ORI_n2LdOCGUhks0EJn;woXLq=mDMH~52k!fy6o@`GawBr3_-<0IJb$v|P< zAvS=XYKVfacW-ee;uSPYx<$DDg|Bb}Y?F0s*H-07QX|xWU2q~tf8Gmcx_E%;6M;ST z>@OwU%*n|iofW5b9oC!Jr74UF;+j2sb`OIh6Z{=w_heui2L+Q3ro`)XkG-3Z<5?2- zNLxR3r&Fg+i$ho8oR=ZRSpM>-&Y82>w53Z!h89I5mUHB(s&y(`< za=qk($k3E2+?ndHI_)}Tl=rjiU-Q8^5#|U*tPsx?6cg^@$cTjC`z{5KOf5Hkxuk!= zasGT)w<%QqJ+!s2!l;S$T!9x~?*oqo?hAsdB<9b+D|W<0ke~Qw_cqtWw&J+eI_a~zClpi8 z<(VjKWqZg{h9o*d?LrKzc=bipSy;zID^?Ox=MsH{w<~V%%XyoF zJ~dSl|Y^p+2i`_{%3pgkIt0aM_A*pP#Vseu$%@PUTb6i6uAND!t82e*!1^7i(@(U84 zPE|Gg1zI8XX{*J5Z0KTj#D5+JPT+3c+qj+`C;9yOrz;N4sT_ENxe9l`dHIsDjT166 z#sa3xaZDghOBq~Tt#Y^oBuN&?n5g-IDCZQin|_kCyr_t&z)WjIr2?4%v>U(t^gWNj zN8k$khCi!Oy}I-d<;#d6`Hk)ZT|f{_T%Ur6MkX;|*?w%*=WLgOxIz?Z+9Xj(Vvr+l z%y?HO=3n-&;)=*#e}5_$l=1ZGM@trgXhQViciM`6X&OYA$-ULBf-py9`c#y)$NafQ zW^+Fwe~9~2mE2gUlX8*)(Qt z4bL-9sbA_lYiVUq02-;TNP578u%MBdda>YU*Zyo}gnIkTBZq|xb&y2pdUaq=uEDd1 zRb4f<4yc-kz#U!Db;d5$h!D^s7|J#>p?j0b9m&lwfvlVNLpsXJJC zI?l}luIlGA4c1@+cCc9+2N)|mht7~+>z@_v+3lSjy-6z0k=-jPVx$syeB3WiHq~9$-<}Mg$f+G)}i5_(ohL}5?3y|54$PFHK zxO6G<;>F&|?9+M~=}?YAgn0pp)PNvlj9T1ptBC6LP6}zboL7f!pf=;1P!i3t2IB0F zq9(M-WV_c%v9ZTuiuNxA(flybpd${i`ZJu=$9d-g28Z}|S(N&TqmrXf8! zOSH<-5kHght%Qd#!aS~B4krFO;2nENEF=jkC3_{rDX|J}+$>XR5k&z`EP&`495qk} zu$PE~5k}fR(ze5tCkqE|*vDTL1qxic5JRl$b%PFHfzy!WAU8L&Tolh&?%%IRa^CMF zMtE3M+WYgDBrji?vLz^}Wxo|oXd2~`0XoB{60qp}>!QoumA@(&xyQQ7T`j|Oz{)Hm zw!KM{GKEu$Lw6byk?O@#vO}}Z*@+5OP~Hm*U)7c@V*q=62Xm}RP8Zp7z&!_*XJA>T zEFr6qy(b{txJ6HX?Spg^b=R#{Sd7GqG98&pp-+|ZkzB2Iye$odSJ>S zmCiRjTpiR^SR7F+^1Ur0wEMxkuu$YE7KtNLQ_=TBe?8k`p18Sn%pdyu0w#@=FE`vH2;Fy3 zC9;Ny%Rn&Y_h`xTw8nE7cvShNQQft}uG{ws_ut3m`fBCi{Y^_;0I6Clx?BHuYVEF; z!Go2-P#QZ#oIDiSn#>TBV*l2yA*{CceB|*-*k}^67qQ>7zl49PS*w=W$C>I+wSEx^WkNlir!O_$1c*&xS`8Ieah6<^OUsa1TCC8larZgv-ll5e+NJ5vaG`! zuVeHANO&a>3tAe-@+js?Z9i}zb$V&Q-i*){UhdviU8b#KbcpU5=}rA;NBq+WJvtd^ zn-}?Te9sJh!$uVqSA-Mg>qJ$uW*Lu`7x8E-*Qv}f=0>xi;aZTsib2r=?*Q91~pJ~objU;G`qwjjOLPgkHI~}u0M>b;!5!|Hs=7- zsFi2bsPmGV@Y5$(`8LX#<*_(}$cJ?#@o-fH-*42gA+r@kUh#_-z^qQ4AAfH8pA^tW zm7^DCcL_Y_kkQXka3{Ttiik+D5Bw6~?;kA#VG+~PYf`zkkP}wq=_1a{U)EOZ zh*xDee&rsiK4j?7HEslLn)t4um{V0FgKYLr;&F_O;a3yq5_sQS^n`@PFr|pG0n;Fw zvP)=1vR8tH)>2#ThWKQXZyMPrQd3LXTi`Mu{2l0pYk+p08fcRcHp&`!3k&%c2?apI zgAMo^#R7^KDNdN=f>%UEYYm}H(GYP$yA#-=NF0(@75=~qVo4|y!qRg?lgfz2X$&;g z?kmxghqzMlb*$$tgXGRfeYy5E^Fj9AsGL1bkD%sQ3&ju2^jZidW_4_VagZbveB1fG zjH^*D?&;@ZAnpqgiRO09>A787rGf;0*c-1;(r3-P2$AxDyz>M^6TJ6Mt-h ze%sESe}=e*noj88^mjocMi@m3Dnax6_SL`?k{wPe4PkSSCxplTxg9#)MLP@i{KwU2|kIK3H^CeH3O8-E#^Xmx15U7${P?BY7A~tw? zTl10b1a)dyyAOWw-{wDKvo)d~*VN(wd1(2O%vsBgl@+S2uWe>13W!oV%>uI6fPAGX z;Kk@mg?7jlJ{Yb2uJDp)3|0Ao>pBzr>lGO!xgZVXTtz_^Kl^dN{qzT`MUOxMAa2sw zi)6!y)3)?Iyz(C^!~e7H({PqbNaipxJBSwo^f`GR+|Gj;Y>MB z+J*?}CDV{77&)UQ;_V70(|e|)Jj0N44RhxvRJ5`iAz*LV1x8fIO@Km($3NnKs2Umu zR9pW4E;T}iT(a+-$fRZ!5kpbRN+cYb(PpY@#F55kF%V&J4La@0#aXW^(+wz}AGPC9 zM6tig-`}4OT1H{9(>Hl~dMc{QIWRtSZk{EJGPPYw7Rz1TX>#b?z37CNp^OX90CcWZ zvnClVl{1~t*?3$)f;t^9(2KWkJ0fhF#t#o(q(k%-nFl@RobFoqbSHN+|G;kKPi{0` zwEwq&tfzxqjF@yD^`nX=`F;U&!uq~0rg#V6ZH-Rx1gG*a3_{cKD179?9%f{;cG9AS z-A8xYwXpxudwIw6n;j_~S9xt~X=xNJs`CBktZ{JAVb?JyU+Vm7Y&{`U=htHAWcLhx zW9!NM(MuQRibL}Ims#WJALkz{RE>K+$fa~i83*P%0@=cy^6LS75)VGaCUcgS&EL0j z{WjnrFFqiTTC!x1@$^FkoAmj3vo*(yeR1T$RbQ8hAp)=f{dT366P1~$-5KpV{8I6# zV*MZRN!IE%T3uUkKc_7>u2#2hU2u%qj#eC=6q!lO^6+~K-6W$9aYr7aJclH`&hG+% zxU=UQ0)pBnzbSt`P~Bhq@3BaOo{Z@ImlieETsn)1^nBTW1a?xeldq-&L69P$F_HIaOssE^chj+BM{F)P z#1YFSgWKRaOcd&@8t-p+4wUIc&Yt6Z`t3KLG-)gMD3dzs1O1`~m(iUtsZ}MF-?G&C z|KPTd*!}liZ)|K$LDImu8d5p+S0ej!yMq76mzuu0)*7(AnRhZ@ybu@$!w@y17$$&^ z%#-l%jxIJt318T+iG-`=LJLvtROS4RbiP+gEq(dZeZ%Vcdk^!hNbR~t+9hg(>zv9W zY9*adfFBBIA`RAaUKv+v4(Y^25RA!DaYX}RT#Y|aNqXa7tgK`>sk)^z3ZpEuWyJv4 z8q8TgbIgHzJ}0BA`n}wU&Hq5FoDZ=&uYx`C(={<%(gix0`H>r;^&(PK)x=;eN-R%L zX>yn){-HRkLPJJz!tE9gy&Sfl#z?HnXzTk*B&9fL2xn(7?m9O~XUz`h@MRgxY#zPj zo40NWI0k__ckCsnIa|Jz6VM}0AiQkRL|j2t4jwtOS5{clJjWkps^eKUOn~3dOW!|x zVx7NCtde9Mp{IMqbSwD*NYv((!0%zc zKQ?VA%aN;3eEGhq5PmY!2>^w}_Zi9nZe`hBI0pemPUW;?fEfdwZQiOIB}bTB-Ob0d z^#O5bD|F-FUgNv(TErAw!Y;GZ?nexd`iXIQm0u_BajEl61J6fm9%)CNCOt3UL`Z8; z9FGSqQiU46dPK^TFo%|vIHKhnNUO6%bkHI4Po8PCE%Y>^e2M}k_=e;0??8l#BB}=F z%}UyxAWig)V$m1u!YW~&Z|I&3j$kn!mcRh4bD_iv8<=Gphj_ z5)Bn-U|2_MPW2td)>~Lt(prx@Gv;J+$Yf5mmlqKUge-L-dvt%%$t?ib&<3Nw#nDIf zy5Ip`1zaz608G6N-Vz~!;aDvb&K%y?%%2S{qk_m>{#Epr)U9G=L0v5+1A*oCEk=!x zp0VirBa_o(k)z}93l;>K&>}QlNmRg++$8MDnH#IGtzP#UqDe(zOVoIulKjre5TH?+ z!c}0OJjTz-pC(=V>mhM3INI{&jNlaI$K+g}$e_ld z1AP-aG=`_3rmCta2oUSZM6%1st(T(ETfi;MauWV@DM|D)K#QFFUb*Kx@_g5C+*m`h zMkoYPg~@)G=q`LUJgg&yuUGtU-|_h!|LZjEu>Mz{xH$ zCG_ZzbJI5gYnhf`{6Kjh&bpnmtGiX`aARZtKFqLBa~L>qH5H~CbTVGBVV0KrOqf46 z?i^S4hk}BJfKA%^`i;@V?PYihc7&#SiC!ghht8PcC*eq_ov(xL(2h-qO8+-PGo{6+ z<*)BH1)bd{EvOjc=)q)Q`7%@heuVG@_P*Fy_mj(c^Hy4M1N*m!zLYQLXN-B|)IGCo zRQ!6p%)ih-Ur2g96J{;DWZ##_r!ha)Sc@rKrK3AEbk;x`_U_$$tG3K(qc1e3@(|@e zNXoOI8!e)HKIpSHEZrH-VPcO9_uy~}%Mg;>$ojZ7ew+5<^&c9jrTPE3UY%VDHG0N> zS6p$NxVhbrCWUoJYrRQ`Ug1O6$*3$Q@Q6j9f>?~QXgQuyrp8Dqcqya&{xgrpzcgr| zsrA07Xx_MGrr9@}gkM{_$t`c(j}!1w-+PdG6sRK(PL5pBo7?CtCNHV%q#0*pa@a`? zAb>YACygfBYJF!He91kA9wFp>^wDmyp95S$PUS0WHACDC46FHy*9U@YEg~z45j{VW zT`E2jP9UfGi;W8oT}Ub(b?E*#%vJv8i6MLf440tEFkUIWbai#bcX%(6qhzhymH3_c zy&I^RC0+Tkecq0MNA6lE)8!Oq6GWJNVSq|}5`jzqu{}SLL(G`%#8t?hNxP8N7Ez=0 zXivt5F6bH0W@**Fy{Su@cdgIlgeZzk7Frwo$K=WNX|d7JBDBB49l{_1!j{n-uQgkA zd>Ff&8x1LNeZ<`iI8~=p2-xgL$;}ajfJ=BeF1WSW#rk)mzkOR z!QEYA$%Tsgd*G&0Ipo>mV^QAqQ~yi1vN8ZI8DLb9SbE`6*fWw(Mxp!+OD};X$^c|k z#?>%gD6W8{TpounTxc@XPZFfBqX3T&(w(dPl{Od_$iVN#gz%S0~ZB> zt%w&8snk_!b+fT!*P+K_$Jxku*ZZgE0XWH#G>Is0NFqrb5*z{a`#s#cdZS^SwtP6Y z&1&i{zGPG;c@Ni#Q1FEI>(%rDA3>FfAf7Qb*g)fFFJ8n=cQGoBbGmG7T+r-C1z1x7 z`#3hzRlf!AC;kupR;^ShV#Rf5vTWqYdL$g`d7T_Wa0IpLI&v%|XLB6^;bfD!b27Nq zlqnTm!{z=2y>#rtp-9oykLCKf`C}}&S_bE$SRo)ox zMe;(`Q`6G~p=TU{B!3F;b+X2hP6$(+v>RL}Z%=Qt$mUdphDRO~9 z{F`KVdT=H$#x@x9xo+;AKiTzaKcI){>%bI6jgF3uY?!gT(d>S!6!!h2yr>H)DKG|R z-)pecAte|E5QEWSk<==>DlGDb3`nq@kTPdU-g`_Gyv@ zJcAW26fMvf)}=Y~yI|W?Q7~Ez^k2!T0?ZVA`vIZH+^_-z0jwGGT?#g5Jd7;R=&q(# zzTro?Hz$sD-UFL~_ZzXQ67gpPtfaVp2NuA5vJD&^9U0kY!tn);9pd%sOJ%?+fm3TO zN)c|V`=GH`xpGMFjj4zFPs(RP77HS)f6ndtK?YLFM@^5oWROnOm5KuBKaU>-&_BD( z!<7U;erw{zX`{P%EJE*E3yLCQ+GiFas;sS;i8OImA!~e?V_;Ll+KLaQSPnU8*rLzU z#on!Tbk5y+v)k$f6qkH$Gvh!0JM9s$?QRHUJKGXR!e}ci{|_cBt;{;?o7A8^xQO6i z(5q?hEDPbf1x^&WoH&+gXcB%S)S5-4O`4{FM$GZ$NnR)aLQ^YX>m>#!&RS;E;F9*q z0EaI0wGc$6gtEZ)oEkqS4a5!Uu`5iojM2Dzux~R;mbj9DjhC7}-W{3g7s>>}8vXl6 zRf6iGy~mZ7-REz(Eo3%?zNk~#dI>XtTm(lzrY}=tU`b@~OHw$vQWZ(h1ulzsxTf!n zA%VFN8~91oy`O}IhQ`7aC-_K6EwGUmB`O|yi8hi${c>sEr9Ifb5(`CHDUkp$;QZiX z8lfm(y=BYK;O%frHg2B0B^EAHa-lBkuJk zl$RYj4S_((j_gYxK`Nyj3R3yKnq>a2g3DjD9997_>WeY3kjp7^Dz1S_n%}G5iBMu)tIc` z@@I1DA{clfL)xI=Hi&@*M6QRvJ{G4_WvfUcPKYWx9iZ+CN7MwZe1r z>bL#Q1XahWG{sQk)Azr#f4KLvi&1=`9%bN`JFmg@|N3&&{!uLpPsnVfw)?BqecJ%0pH%OfNne28ty4C$~ zXZNsxf1&`nXW&u!@6{Dbu7SpjTW}hBH$VA7aBNCoQLAMo_%}w7O@$?5nYmBSs*p?6 z83WVWjPg7u;<)usttPw4YFzp@1Dy?LdZdT`Xv^eaYeCfY^ZfjbmtVLuTDNWc z6DyaXq{}h{N-$Y)5n2}M92to8aJAaw2=^c7JDk1_RVLAhiBG3CIZZkgv&hw<%SC(a z?Z_C`4SZ9l`O_B%{*&P}@ct(H!2&Ncl)1F)?&-5^;rT+;CYoBPQ*sa8%$iiG_4@w2 z9edM9*tJf9XCju%AP?DD5xyLRa{ zi#qJ`wrBd8t^a&_qg%QZZ2SL9J1Om~HCE}b{k9oTtkrAh>2|{IMbG4~5Jt?u@iR+| zH#rNmBkNFD9&iW8e=qXt_xr4%`e~y~`GyG@%X|wa8T3VV) zSy8Wu$Xlh^RaSm}UL&B0bPK(HD37bU4z#=P ziRoH-k2EFArSAI_s~3TnKh{QdE>cg&%ZTAIjYh3ZJ5;oI0jcp{nyJtP^II1e#vGcU z{w5i97}FS>V=6N;sS}Xd45XN)P(PgH7+c_%zx0y9kH$j4p)LQ3c1j%lTC^%ZXex^x z{ddX@^=N@^SQ};PjNht-wYJ6g6G zH-3Ch7l+}~^xK6Ldc@%R;EWeJePx|jhr&#VEy)vP@3`Mc~@U2|6*7(sLpemhF zr&+H$kQ?fMRdW(r#JJ{GJ$wGb32B*RVr(o7@Ee1yACT3p(}#gQ7JPa=qVSC{V3<4< zSI};my1_-(CY{7`?<61SM!|>x@0dBYiGqf_wi@JtfXl4kv13O`jcRnUCO4Lafmey0 zc&7^hN{5aeS2M>3)~)W=SIFNOdqtX;Q}HyRqyUr- zZSw7$T(0uZAMX{})&LzXK<-6}C>i?R!1v_oR3(!}z>e?93^b6_Uftd$BIF6JGe*lK z2Grr`zoiPMbk)+-9N^NApd_w_n4h~}cBO0+OpR(x@{ADu zqmh;{L{RE@#sr`|WTwfMM+?&L(KQM>joPF8L~a$z&+BksBBrC#@tr2DnuJ7(V2svI zG_{Bb-9^ht2wdmGD=VX>h|TJNLKPMP5^bM{G*V6T`wske81nzKBEOSohba$RD+LC) zLl=hz{Y71kC?fW|Blv<2x)5z%INc#s;Q=OfO}1{YuRq@Z!G9~haOIa2*o{!~ z%Qv8~7UBNUW5hjR zc$0tZ<^Q|?^YQ(9u0LK>vMFV&NCfZA&TBf(&290NF5l~Iwx~+O+6ci17(2&pJC+es zDJ}f=7xRo(%-Wrm9;+v6!@s`%zxWZ7-9S44F=Clevj&ZOGz~w=XIJ4L3=D@yh?31J zbnaC`;Z>+=;H3{^0$)l*RuBv`MxK-BjoN4+WBB@hV}GEop)M`OouBx}_@uu3fs4oG zV@0SebJ10EgCPC80;L21zV5pRg6<{sOY`8c*Rit*!NVfeoZdin+x>dG5NM3Jg6Ms(llz?_341`mFCLL#4tL^y;zR1`}T(3Qbq z9DFiJfm|v#aN}Q75*)dd!amel?9RwbRHNeYJG`;QHKZqaKDUqDimQO1b6dxG24hcq^vM-RSayZT-uVm%~`gJ5$YeH zsFnd&S1HZ*^V) z_>l&_Z{fXAFp8NJ*fsdWY=hm}#aj?3$(z)K5|kJP#2P??$sGq}_NnN&b6J<**dh-PzUi==BT!cyz z17$Pgr;d7GXL=Ay-rls5rzr09?PM^Rkh#4PoZ1Z*o1(y$O3B7N3V;dmY`%K6p7Wc# z`a~eZD*r(ir?+{`f3P;q2;KJ!_*3BO86Quifib&7?V~-Qq zf8(Vav$$#4*)paEndYAs!)YkgloR^?8l2zh<*B)l+0_)>C}Bvh?{l?zWDf%+w=WA9 zlsqc!fs@y$eY!(jy!(AxUhI>^ZK&F`X{{PHY5<~1_zIlF=%l1KP3>-xVvA3EjEK$A zR-KLQ?UG;1$R{(gUybl&+qWwpziBE5^$`nIVM*rnq;dUKX|NCjaal`lN$|kEu|@f9Kkh#P1^Bhce5FX(1)M5=b~~0x;FU( z?`1)L#$=K;N$2agjp0$_xY(x?sZwQtMEg0--B95FU;+}GmlzO#Mb7o~l2afU%eb!y z&h8L6cbz97!I|xBE-qgIbirBaGuY8F1WndRer)5zqi@Qny`IO|?Z2kXi;wS{1300) z1kM@1#a@K6E)UYu@IUph_%bSBNvvnf?rcRw+RFkK!K;7dpFP#TnL(7tqF;#AMyb6E zq0dd0b<8(?X-J9P+m(;>94J?Ia$(*9T#o_J|5_SVVU?+FG_BXm-t+w5TzOI&aPbYQ z8Bng!9pCnJucMyfCg5uqxe((SC)OQHzZwO&x@$Yk;=^)Ems^e zn?yb;D;lld(%qiM}NZk1BSg+4js zc9WmPv0Z+BMj|WI(Nd_tqPN;XvfphsX#9)~_Z>1*SMapeUop$0fns@UCZ8#MD`s`e zH}y5^Ys;y*@ZgR-jJu$ZrDi_^Wg>DhfYq_NxivDe&@}{gP=1)U+q{ z|4cBo3Y~!&SS$|EvXV3zi5gG{4mPq#_OY7>I9WNBpl+BQ@8~2saLN?6o8=pj7q!NX zliHQ*9zPibmvj|0oWocB6~(d04OFe=h<$C~d5;JXAu%CJpa>k?WBzJF8Bqw`3K%K0(Ld5t^BZhCS+W=z` z5kOr{gO?x_XTOE@KNmp2x91Rdy^uPeO5}vl9`kARJVm2{|StY1LHb zV=RbBakvwj$87A)xZ&llkZ}bVY=VFkeUs0TGm;%{_+33noDf5X?HrfK#_4&*J^?6! z`3ej$3RhjuPs#e6+r%9KNs>|5e5fE0~i zHV==4q|rDVz4<3U5U_VL#mP4n!=d7ps`nNwT4dzxY=9g_N^(jJb&d0p4;EPUtr2iB zBl*R$cJlh|zm*n_hiEK`G*(e2Ilpb|_yyxy5H<)w%xOZ=iC~VRz#v5Q(QMPhqjjHd zJZ%3K@u%;|#J4&O7FA?q;}NHcB_wrU1@8{IJq}6lEU0Ih+lHu|ihjV$|Hs*t*yn_%!;YXPSwr=Ggt&!( zJbl0_-m*l6(g_F}&nLBNeK_^kPbm#-@@H_vV-l;bwT5&0$4~9;5+x|vwqD_Bbsl@COT#$FDD4Ym;6EC7&ox(hB=NmHzN0o5kK)m*aF$lgNftNcgC9FGW z-F|!D1uH1E5;_E;ddB&y0w`Mc<-w|6og%%MOsLw~;`9}kj0cY``}86fq3Br{ngYE=v?{giX(*lU-sz`c#yevJE z)QJW2JTe#2wSkHmODt<|d?{SLZi5d0Det`Dj&5D;&mGvarvr`d4!YEvST-CkF38+a zhU#5zH|lDm>x{TzkcI91OIlI()lb`HX3EtGUH3cp-Q=$y8+#|I8$^w`cMn5fHCHNm zOW(_WrG9=NavAun+@xJbPjU6xp1RAnreycdax3+atEu3})g;ynMYkTA_P`%6UcG9| zD?D<*z;WoC5FFzT5M;6`rZKANA7nvzSI7d#@_!SA`liIaqCk}1a|r2mkd(t{ykjWZ zxYDLm^qzyNy|^TIU!voP7~)C&_4G$Xm>wB(vQ4K>LxC&gqQ%jNRAUr4c6?ITKh7Cj zM`$#jVTV&X$~>QQ==NQ~NT5U|b8PX-1y8So(X?XQ3`%d@3#;?*pKHG+ld3ldsLg z5*8hLP(Jf!&jGw~W0RDVs*h|QiF)a;uj~$&F1*H2{nyvODpJ+{@jo9`ByH9BS>dbB z$FPI3TdxtJVUk`|e&dS!> + + Start() + + Stop() + + Close() +} + +class IOEventHandler{ + - IOEventHandler* prev + - IOEventHandler* next + - IOEventReactor* loop + - IOEventCallback cb + - uint32_t events + - int fd + + Start() override + + Stop() override +} + +class TimerEventHandler{ + - uint32_t interval + + Start() override + + Stop() override + + Close() override +} + +class FdEvents{ + <> + IOEventHandler* head + uint32_t emask + uint8_t flags +} + +class EventReactor{ + <> + + Run() + + CleanUp() + + AddHandler() + + RemoveHandler() +} + +class IOEventReactor{ + - struct FdEventsHead + - struct FdEvents + - std::vector~FdEventsHead~ io_handlers + - EventDemultiplexer* backend + + Run() override + + CleanUp() override + + AddHandler() override + + RemoveHandler() override + + SetDemultiplexer(): +} + +class EventDemultiplexer{ + <> + + Poll() +} + +class IOEventEpoll{ + - int epfd + + Poll() override + + ModifyEvents() + + CleanUp() +} + + +IOEventHandler ..|> EventHandler +TimerEventHandler --|> IOEventHandler +IOEventReactor ..|> EventReactor +FdEvents --* IOEventReactor +IOEventHandler --> FdEvents +IOEventHandler ..> IOEventReactor +EventEpoll ..|> EventDemultiplexer +EventEpoll --o IOEventReactor +``` +### IOEventReactor内数据结构 +![](../figs/io_event_reactor_structrues.png) + +### + +## 涉及功能 +### OHOS::Utils::Events +#### 描述 +```cpp +namespace OHOS::Utils::Events; +``` +命名空间`Events`包含了c_utils中事件处理器功能中各兴趣事件的事件类型。 + +`#include ` + +同时`io_event_common.h`头文件中定义了表示事件类型的C++类型`EventId`、表示响应行为的C++类型`EventCallback`(即`std::function`)。 +#### 属性 + +| | 名称 | +| -------------- | -------------- | +| constexpr EventId | **EVENT_CLOSE**
关闭事件。表明当前事件监听“关闭”事件。 | +| constexpr EventId | **EVENT_ERROR**
错误事件。表明当前事件监听“错误”事件。 | +| constexpr EventId | **EVENT_INVALID**
非法事件。表明当前事件类型设置非法。 | +| constexpr EventId | **EVENT_NONE**
空事件。表明当前事件不监听任何事件类型。 | +| constexpr EventId | **EVENT_READ**
可读事件。表明当前事件监听“可读”事件。 | +| constexpr EventId | **EVENT_WRITE**
可写事件。表明当前事件监听“可写”事件。 | + +### OHOS::Utils::IOEventHandler +#### 描述 +```cpp +class OHOS::Utils::IOEventHandler; +``` +事件描述类。其描述了兴趣IO事件的具体事件类型以及具体响应行为。 +当事件系统捕获到响应类型的事件时,将按照该事件描述类对象中定义的响应行为进行响应。 + +`#include ` + +#### 公共成员函数 + +| 返回类型 | 名称 | +| -------------- | -------------- | +| | **IOEventHandler**()
默认构造函数。其Fd为-1。 | +| | **IOEventHandler**(const IOEventHandler && ) =delete | +| | **IOEventHandler**(const IOEventHandler & ) =delete | +| | **IOEventHandler**(int fd, EventId events =Events::EVENT_NONE, const EventCallback & cb =nullptr)
有参构造函数。需要显示指定Fd。 | +| virtual | **~IOEventHandler**() | +| void | **DisableAll**()
关闭所有事件监听。 | +| void | **DisableWrite**()
关闭对“可写”事件的监听。 | +| void | **EnableRead**()
开启对“可读”事件的监听。 | +| void | **EnableWrite**()
开启对“可写”事件的监听。 | +| EventCallback | **GetCallback**() const | +| EventId | **GetEvents**() const | +| int | **GetFd**() const | +| bool | **IsActive**()
返回当前事件是否已启动。 | +| IOEventHandler * | **Next**() const
获取链表中后一个事件的指针。 | +| IOEventHandler & | **operator=**(const IOEventHandler && ) =delete | +| IOEventHandler & | **operator=**(const IOEventHandler & ) =delete | +| IOEventHandler * | **Prev**() const
获取链表中前一个事件的指针。 | +| void | **SetCallback**(const EventCallback & cb)
设置具体响应行为/回调函数 | +| void | **SetEvents**(EventId events)
设置被监听事件类型。 | +| void | **SetFd**(int fd)
设置被监听对象Fd。 | +| bool | **Start**(IOEventReactor * reactor)
启动当前事件监听。 | +| bool | **Stop**(IOEventReactor * reactor)
停止当前事件监听 | +| bool | **Update**(IOEventReactor * reactor)
更新当前事件状态。当指定事件类型、响应行为变化时需要对其进行更新。 | + +### OHOS::Utils::IOEventReactor +#### 描述 +```cpp +class OHOS::Utils::IOEventReactor; +``` +事件响应器类。其作为事件处理系统的中心调度器,负责管理外部添加的各个事件描述,按照描述添加对事件的监听、对各被监听对象进行轮询并对事件进行分发并处理。 + +`#include ` + +#### 公共成员函数 + +| 返回类型 | 名称 | +| -------------- | -------------- | +| | **IOEventHandler**()
默认构造函数。其Fd为-1。 | +| | **IOEventHandler**(const IOEventHandler && ) =delete | +| | **IOEventHandler**(const IOEventHandler & ) =delete | +| | **IOEventHandler**(int fd, EventId events =Events::EVENT_NONE, const EventCallback & cb =nullptr)
有参构造函数。需要显示指定Fd。 | +| virtual | **~IOEventHandler**() | +| void | **DisableAll**()
关闭所有事件监听。 | +| void | **DisableWrite**()
关闭对“可写”事件的监听。 | +| void | **EnableRead**()
开启对“可读”事件的监听。 | +| void | **EnableWrite**()
开启对“可写”事件的监听。 | +| EventCallback | **GetCallback**() const | +| EventId | **GetEvents**() const | +| int | **GetFd**() const | +| bool | **IsActive**()
返回当前事件是否已启动。 | +| IOEventHandler * | **Next**() const
获取链表中后一个事件的指针。 | +| IOEventHandler & | **operator=**(const IOEventHandler && ) =delete | +| IOEventHandler & | **operator=**(const IOEventHandler & ) =delete | +| IOEventHandler * | **Prev**() const
获取链表中前一个事件的指针。 | +| void | **SetCallback**(const EventCallback & cb)
设置具体响应行为/回调函数 | +| void | **SetEvents**(EventId events)
设置被监听事件类型。 | +| void | **SetFd**(int fd)
设置被监听对象Fd。 | +| bool | **Start**(IOEventReactor * reactor)
启动当前事件监听。 | +| bool | **Stop**(IOEventReactor * reactor)
停止当前事件监听 | +| bool | **Update**(IOEventReactor * reactor)
更新当前事件状态。当指定事件类型、响应行为变化时需要对其进行更新。 | + +## 使用示例 + +1. 使用方法(伪代码) + +```c++ +// IOEventHandler 可以按照业务需要进行继承拓展。如以针对linux底层timerfd定时器为例: +class TimerFdHandler : public IOEventHandler { +public: + using TimerEventCallback = std::function; + TimerFdHandler(int fd, const TimerEventCallback& cb); + ~TimerFdHandler() {} + bool Initialize(uint32_t interval); + void Uninitialize(); + void TimeOut(); + +private: + TimerEventCallback timerCallback_; +}; +``` + +```c++ + // 1. 首先创建定时器获取其Fd。 + int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + + // 2. 创建IOEventHandler对象,对目标事件进行描述 + std::shared_ptr handler = std::make_shared(fd, &TimerCallback1); + + // 3. 创建IOEventReactor响应器对象,启动并使能其事件响应能力。 + std::unique_ptr reactor = std::make_unique(); + ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK); + reactor->EnableHandling(); + + // 4. 根据业务需要,对IOEventHandler对象进行其他初始化操作。本例中是设置定时器的超时时间,定时器超时后会抛出"可读"事件,该事件可被捕获从而使响应器对其进行响应。 + handler->Initialize(10); + + // 5. 启动IOEventHandler对象(也可以使用IOEventReactor::AddHandler 方法启动) + handler->Start(reactor.get()); + + // 6. 开启事件处理循环,`Run(int timeout)`方法使响应器循环进行事件处理,具体包括捕获事件以及对事件的响应过程。 + std::thread loopThread([&reactor]{ + reactor->Run(-1); + }); + + // 7. 定时器超时需要10ms,适当等待事件触发 + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + + // 8. 确定响应结果, 本例中指定的响应行为 `&TimerCallback1`将对`g_data`加一,故可确定`g_data`的值判断是否响应成功。 + // EXPECT_GE(g_data, 1); + + // 9. 终止事件处理循环,`Terminate()`方法将使`Run()`方法退出,从而新线程执行完毕。 + reactor->Terminate(); + loopThread.join(); + + // 10. 事件描述对象生命周期结束时,会从当前响应器对象中移除,从而解除监听。响应器对象生命周期结束时,会清空当前注册的事件描述对象。 + // Notes:尽管事件描述对象生命周期结束时会自动被移除,但手动停止事件描述对象能够提升运行效率,这是因为事件描述对象由于周期结束而被移除时,响应器对象将不会解除其注册的监听事件,该事件仍有可能被响应器捕获。 + + // 11. 所以这里手动停止事件描述对象。 + handler->Stop(reactor.get()); +``` + +2. 测试用例编译运行方法 + +- 测试用例代码参见 base/test/unittest/common/utils_event_test.cpp + +- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C) + +- 使用以下具体命令以运行事件处理系统对应测试用例 + +```bash +run -t UT -tp utils -ts UtilsEventTest +``` \ No newline at end of file diff --git a/docs/zh-cn/c_utils_guide_mapped_file.md b/docs/zh-cn/c_utils_guide_mapped_file.md new file mode 100644 index 0000000..31388a2 --- /dev/null +++ b/docs/zh-cn/c_utils_guide_mapped_file.md @@ -0,0 +1,194 @@ +# 文件映射 +## 概述 + +文件映射功能。c_utils提供基于文件(file-backed)的内存映射。其将文件映射至进程的地址空间中,从而支持通过文件映射后的地址对文件进行读写操作。 +文件映射能够节省时间以及空间开销。此外,文件映射也可以支持跨进程的信息共享。 + +## 涉及功能 + +```mermaid +classDiagram + +class MappedFile{ + - String path_ + - size_t offset_ + - size_t size_ + - MapMode mode_ + - int mapProt_ + - int mapFlag_ + - int openFlag_ + - const char* hint_ + - char* data_ + - bool isMapped_ + - bool isNormed_ + + MappedFile(std::string, size_t, off_t, MapMode, const char*) + + MappedFile(MappedFile&& other) noexcept + + MappedFile(const MappedFile& other) + + MappedFile& operator=(const MappedFile&) + + MappedFile& operator=(MappedFile&&) noexcept + + inline std::string& GetPath() + + inline const char* GetHint() + + inline MapMode GetMode() + + inline void ChangeSize(size_t size) + + inline void ChangeOffset(size_t offset) + + inline void ChangePath(string path) + + inline void ChangeMode(MapMode mode) + + inline void ChangeHint(const char* hint) + + ErrCode MapFile() + + ErrCode UnMapFile() + + ErrCode Resize() + + ErrCode Resize(size_t newSize, bool sync) + + ErrCode TurnNext() + + inline char* Begin() + + inline char* End() + + inline size_t Size() + + inline size_t StartOffset() + + inline size_t EndOffset() + + inline size_t PageSize() + + inline bool IsMapped() + + inline bool IsNormed() + - ErrCode NormSize() + - ErrCode NormMode() + - ErrCode SyncFileSize(size_t newSize) +} + +class MapMode { + <> + DEFAULT + SHARED + PRIVATE + READ_ONLY + READ_WRITE + CREAT_IF_ABSENT +} + +``` +### OHOS::Utils::MapMode +#### 描述 +```cpp +enum class OHOS::Utils::MapMode; +``` +映射模式枚举类,包含一系列枚举值以指定文件的映射模式。 + +#### 枚举值 +|名称 | 值 | 描述 | +| ---------- | ----- | ----------- | +| DEFAULT | 0| 默认模式。等价于SHARED|READ_WRITE | +| PRIVATE | 2| 私有映射模式。对映射区域的写操作不会同步至文件中 | +| SHARED | DEFAULT| 共享映射模式。对映射区域的写操作会同步至文件中 | +| READ_ONLY | 4| 只读映射模式。该模式下若对映射区域进行写操作会导致进程退出 | +| READ_WRITE | DEFAULT| 读写映射模式。该模式下支持对映射区域的读写操作 | +| CREATE_IF_ABSENT | 8| 创建模式。当指定路径文件不存在时将创建文件后再进行映射 | + +### OHOS::Utils::MappedFile + +#### 描述 +```cpp +class OHOS::Utils::MappedFile; +``` +文件映射封装类,其用于管理一个文件的映射。 + +`#include ` + +#### 公共静态常量 +| | 名称 | +| -------------- | -------------- | +| constexpr off_t | **DEFAULT_LENGTH**
默认的映射区域大小。 | + +#### 公共成员函数 +| 返回类型 | 名称 | +| -------------- | -------------- | +| | **MappedFile**(const MappedFile & other) =delete
拷贝构造函数。禁止调用,不推荐单一进程内多个映射文件对象对同一段地址进行操作, 可能导致内存泄漏、内存非法访问等问题。 | +| | **MappedFile**(MappedFile && other) | +| | **MappedFile**(std::string & path, MappedMode mode =MapMode::DEFAULT, off_t offset =0, off_t size =DEFAULT_LENGTH, const char * hint =nullptr)
构造函数。至少需要显式指定待映射的文件路径。 | +| virtual | **~MappedFile**() | +| char * | **Begin**() const
获取映射后的映射区域首地址。 | +| bool | **ChangeHint**(const char * hint)
指定被映射文件区域的大小 | +| bool | **ChangeMode**(MappedMode mode)
指定被映射文件区域的大小 | +| bool | **ChangeOffset**(off_t offset)
指定被映射文件区域的偏移量。 | +| bool | **ChangePath**(const std::string & path)
指定被映射文件对应路径。 | +| bool | **ChangeSize**(off_t size)
指定被映射文件区域的大小。 | +| ErrCode | **Clear**(bool force =false)
清除映射。解除映射区域,重置所有映射状态及参数,关闭已打开文件。 | +| char * | **End**() const
获取映射后的映射区域尾地址。 | +| off_t | **EndOffset**() const
获取当前指定映射区域尾地址对应的文件偏移量。 | +| int | **GetFd**() const
获取当前指定文件对应的文件描述符 | +| const char * | **GetHint**() const
获取当前指定的映射区域期望首地址 | +| MappedMode | **GetMode**() const
获取当前指定的文件映射模式 | +| const std::string & | **GetPath**() const
获取当前指定的文件路径 | +| bool | **IsMapped**() const
指示是否为已映射状态。 | +| bool | **IsNormed**() const
指示当前参数是否已标准化。 | +| ErrCode | **Map**()
使用当前参数映射文件至内存。参数将被标准化。 | +| ErrCode | **Normalize**()
标准化指定映射参数。 | +| MappedFile & | **operator=**(const MappedFile & other) =delete
拷贝赋值重载函数。禁止调用,不推荐单一进程内多个映射文件对象对同一段地址进行操作, 可能导致内存泄漏、内存非法访问等问题。 | +| MappedFile & | **operator=**(MappedFile && other) | +| char * | **RegionEnd**() const
获取映射后的映射区域所在页的尾地址。 | +| char * | **RegionStart**() const
获取映射后的映射区域所在页的首地址。 | +| ErrCode | **Resize**()
按照当前参数重新进行映射。 | +| ErrCode | **Resize**(off_t newSize, bool sync =false)
调整映射区域大小,同时保持起始地址不变。可选择同步调整文件大小。 | +| off_t | **Size**() const
获取当前指定的映射区域大小。 | +| off_t | **StartOffset**() const
获取当前指定映射区域首地址对应的文件偏移量。 | +| ErrCode | **TurnNext**()
“翻页”。将当前参数对应的文件中的被映射区域向后平移。注意“翻页”中的“页”并不代表 内存页。 | +| ErrCode | **Unmap**()
解映射当前已映射文件。建议在参数已标准化时调用该方法,避免内存问题。 | +| off_t | **PageSize**()
获取当前内存页大小。 | + +## 使用示例 + +1. 使用方法(伪代码) + +```c++ + // 1. 创建文件 + std::string filename = "test_read_write_1.txt"; + std::string content = "Test for normal use."; + filename.insert(0, SUITE_PATH).insert(0, BASE_PATH); + RemoveTestFile(filename); + + CreateTestFile(filename, content); // 该方法创建filename指定的文件并写入content + + // 2. 构造MappedFile对象并进行映射 + MappedFile mf(filename); + mf.Map(); + + // 3. 映射后可通过Begin()方法获取起始地址,并从中读取数据 + std::string readout; + for (char* cur = mf.Begin(); cur <= mf.End(); cur++) { + readout.push_back(*cur); + } + + // 4. 同样也可以向对应地址中写入数据 + std::string toWrite("Complete."); + char* newCur = mf.Begin(); + for (std::string::size_type i = 0; i < toWrite.length(); i++) { + (*newCur) = toWrite[i]; + newCur++; + } + std::string res; + LoadStringFromFile(filename, res); // res的内容应与toWrite覆盖后的原本内容一致 + + // 5. 注意,当试图向End()指示的地址以外(但是不超过该地址一个内存页)写入时,写入不会越界但是写入内容一定不会回写至原文件中。 + char* trueEnd = mf.RegionEnd(); // RegionEnd() 返回End()指示地址所在的内存页末尾。 + ASSERT_GT(trueEnd, mf.Begin()); + + (*trueEnd) = 'E'; // 可以向trueEnd指向地址写入数据 + + EXPECT_EQ((*trueEnd), 'E'); // 同样也可以读出 + + std::string res1; + LoadStringFromFile(filename, res1);// 但是文件中不会同步结果, res1仍将和res内容相同。 + + // 6. MappedFile对象会在析构时自动解除映射,并关闭内部创建的fd。当然也可以手动解除映射。 + mf.Unmap(); + + RemoveTestFile(filename); // 该方法删除了创建的文件 +``` + +2. 测试用例编译运行方法 + +- 测试用例代码参见 base/test/unittest/common/utils_mapped_file_test.cpp + +- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C) + +- 使用以下具体命令以运行`mapped_file.h`对应测试用例 + +```bash +run -t UT -tp utils -ts UtilsMappedFileTest +``` diff --git a/docs/zh-cn/c_utils_guide_rust_ashmem.md b/docs/zh-cn/c_utils_guide_rust_ashmem.md new file mode 100644 index 0000000..81013d9 --- /dev/null +++ b/docs/zh-cn/c_utils_guide_rust_ashmem.md @@ -0,0 +1,103 @@ +# Rust侧-匿名共享内存(Ashmem, Anonymous Shared Memory) + +## 概述 +提供Rust侧对应c_utils中[使用匿名共享内存(Ashmem, Anonymous Shared Memory)](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-ashmem.md)的相关接口。 +其在Rust侧构成utils_rust包(Crate)中的ashmem模块,包括Rust侧对匿名共享内存进行操作的各接口方法。 + +## 涉及子模块 +### utils_rust::ashmem + +模块`ashmem`中提供Rust风格的接口以对匿名共享内存进行操作。当前各Rust风格接口底层实际调用子模块`ashmem::ffi`中的方法。 + +`using utils_rust::ashmem` + +`struct Ashmem` + +#### Public Functions + +| 返回类型 | 名称 | +| -------------- | -------------- | +| Option< Ashmem > | **create_ashmem_instance**(name: &str, size: i32)
创建Rust侧Ashmem结构体对象。 | +| void | **close_ashmem**(self: &Ashmem)
通过内部维护的文件描述符关闭当前ashmem。 | +| int | **get_ashmem_fd**(self: &Ashmem)
获取内核中对应ashmem的文件描述符。 | +| int32_t | **get_ashmem_size**(self: &Ashmem)
获取内核中ashmem区域的大小。 | +| int | **get_protection**(self: &Ashmem)
获取内核中的ashmem区域的保护权限值。 | +| bool | **SetProtection**(self: &Ashmem, protType: i32)
设置内核中的ashmem区域的保护权限。 | +| bool | **map_ashmem**(self: &Ashmem, mapType: i32)
将内核中的ashmem内存区域映射至用户空间。 | +| void | **unmap_ashmem**(self: &Ashmem)
解除ashmem映射。 | +| bool | **map_read_write_ashmem**(self: &Ashmem)
以读/写模式映射ashmem内存区域。 | +| bool | **map_read_only_ashmem**(self: &Ashmem)
以只读模式映射ashmem内存区域。 | +| *const c_char | **read_from_ashmem**(&self, size: i32, offset: i32)
从ashmem内存区域`offset`处读出数据。 | +| bool | **write_to_ashmem**(&self, data: *const c_char, size: i32, offset: i32)
在ashmem内存区域`offset`处写入数据。 | + +### utils_rust::ashmem::ffi + +子模块`ashmem::ffi`借助CXX工具通过FFI实现与C++对应代码的互操作。其中各接口通过FFI调用C++侧对应接口,以实现操作匿名共享内存的功能。 + +由于使用CXX对Rust侧以及C++侧的接口进行绑定,该模块中的接口命名风格与C++一致,其参数类型为兼容C++的Rust类型。 + +`using utils_rust::ashmem::ffi` + +#### Public Functions + +| 返回类型 | 名称 | +| -------------- | -------------- | +| SharedPtr< Ashmem > | **CreateAshmemStd**(name: *const c_char, size: i32)
使用指定名称及大小创建Ashmem对象。 | +| void | **CloseAshmem**(self: &Ashmem)
通过内部维护的文件描述符关闭当前ashmem。 | +| int | **GetAshmemFd**(self: &Ashmem)
获取内核中对应ashmem的文件描述符。 | +| int32_t | **GetAshmemSize**(self: &Ashmem)
获取内核中ashmem区域的大小。 | +| int | **GetProtection**(self: &Ashmem)
获取内核中的ashmem区域的保护权限值。 | +| bool | **MapAshmem**(self: &Ashmem, mapType: i32)
将内核中的ashmem内存区域映射至用户空间。 | +| bool | **MapReadAndWriteAshmem**(self: &Ashmem)
以读/写模式映射ashmem内存区域。 | +| bool | **MapReadOnlyAshmem**(self: &Ashmem)
以只读模式映射ashmem内存区域。 | +| *const c_void | **ReadFromAshmem**(self: &Ashmem, size: i32, offset: i32)
从ashmem内存区域`offset`处读出数据。 | +| bool | **SetProtection**(self: &Ashmem, protType: i32)
设置内核中的ashmem区域的保护权限。 | +| void | **UnmapAshmem**(self: &Ashmem)
解除ashmem映射。 | +| bool | **WriteToAshmem**(self: &Ashmem, data: *const c_void, size: i32, offset: i32)
在ashmem内存区域`offset`处写入数据。 | + +## 使用示例 + +1. 使用方法(伪代码) + +```rust + // ffi接口 + let c_name = CString::new(MEMORY_NAME).expect("CString::new Failed!"); + let ashmem = unsafe { ashmem::ffi::CreateAshmemStd(c_name.as_ptr(), MEMORY_SIZE) }; + assert!(!ashmem.is_null()); + assert_eq!(ashmem.GetAshmemSize(), MEMORY_SIZE); + + assert!(ashmem.MapAshmem(ashmem::PROT_READ | ashmem::PROT_WRITE)); + + // 当使用结束时不要忘记解映射和关闭ashmem + ashmem.UnmapAshmem(); + ashmem.CloseAshmem(); + + // rust风格接口 + let ashmem = unsafe { ashmem::create_ashmem_instance(MEMORY_NAME, MEMORY_SIZE) }; + assert!(ashmem.is_some()); + + let ashmem = ashmem.unwrap(); + assert_eq!(ashmem.get_ashmem_size(), MEMORY_SIZE); + + assert!(ashmem.map_ashmem(ashmem::PROT_READ | ashmem::PROT_WRITE)); + + // 当使用结束时不要忘记解映射和关闭ashmem + ashmem.unmap_ashmem(); + ashmem.close_ashmem(); +``` + +2. 测试用例编译运行方法 + +- 测试用例代码参见 base/test/unittest/rust/utils_rust_ashmem_test.rs + +- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C) + +- 使用以下具体命令以运行`utils_rust::ashmem`对应测试用例 + +```bash +run -t UT -tp utils -ts utils_rust_ashmem_test +``` + +## 常见问题 + +请参考[使用匿名共享内存(Ashmem, Anonymous Shared Memory)](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-ashmem.md) diff --git a/docs/zh-cn/c_utils_guide_rust_directory.md b/docs/zh-cn/c_utils_guide_rust_directory.md new file mode 100644 index 0000000..4d12679 --- /dev/null +++ b/docs/zh-cn/c_utils_guide_rust_directory.md @@ -0,0 +1,49 @@ +# Rust-文件与目录 + +## 概述 + +提供Rust侧对应c_utils中[文件与目录](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-directory.md)的接口。其在Rust侧构成utils_rust包(Crate)中的directory_ex模块,包括删除文件,获取文件后缀名和更改文件权限等函数。 + +## 涉及子模块 +### utils_rust::directory_ex::ffi + +子模块`directory_ex::ffi`借助CXX工具通过FFI实现与C++对应代码的互操作。其中各接口通过FFI调用C++侧对应接口,以实现文件与目录相关功能。 + +由于使用CXX对Rust侧以及C++侧的接口进行绑定,该模块中的接口命名风格与C++一致,其参数类型为兼容C++的Rust类型。 + +`using utils_rust::directory_ex` + +#### 全局函数 + +|返回类型 |名称 | +| -------------- | -------------- | +|String |**RustGetCurrentProcFullFileName**()
获取当前程序的完整的绝对路径。 | +|String |**RustGetCurrentProcPath**()
获取当前程序的绝对路径。 | +|String |**RustExtractFilePath**(fileFullName: &String)
通过输入的文件完整路径去获取对应文件所处目录路径。 | +|String |**RustExtractFileName**(fileFullName: &String)
通过输入的文件完整路径去获取对应文件的名称。 | +|String |**RustExtractFileExt**(fileName: &String)
通过输入的文件名去获取对应文件的后缀名。 | +|String |**RustExcludeTrailingPathDelimiter**(path: &String)
返回以去掉'/'结尾的对应路径。 | +|String |**RustIncludeTrailingPathDelimiter**(path: &String)
返回以'/'为结尾的对应路径。 | +|() |**RustGetDirFiles**(path: &String, files: &mut Vec)
获取当前路径及路径子目录下的所有文档。 | +|bool |**RustPathToRealPath**(path: &String, realPath: &mut String)
从路径获取真实路径。 | +|bool |**IsEmptyFolder**(path: &CxxString)
判断路径是否为空。 | +|bool |**ForceCreateDirectory**(path: &CxxString)
强制创建带有子目录的目录。 | +|bool |**ForceRemoveDirectory**(path: &CxxString)
强制删除包含子目录和文档的目录。 | +|bool |**RemoveFile**(fileName: &CxxString)
删除文件。 | +|u64 |**GetFolderSize**(path: &CxxString)
获取文件夹大小(字节)。 | +|bool |**ChangeModeFile**(fileName: &CxxString, mode: &u32)
更改输入文档的权限。 | +|bool |**ChangeModeDirectory**(path: &CxxString, mode: &u32)
更改输入目录的权限,包括子目录。 | + + +## 使用示例 +1. 测试用例编译运行方法 + +- 测试用例代码参见 base/test/unittest/rust/utils_rust_directory_test.rs + +- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C) + +- 使用以下具体命令以运行`utils_rust::directory_ex`对应测试用例 + +```bash +run -t UT -tp utils -ts utils_rust_directory_test +``` \ No newline at end of file diff --git a/docs/zh-cn/c_utils_guide_rust_file.md b/docs/zh-cn/c_utils_guide_rust_file.md new file mode 100644 index 0000000..da53d12 --- /dev/null +++ b/docs/zh-cn/c_utils_guide_rust_file.md @@ -0,0 +1,40 @@ +# 读写文件 + +## 概述 +提供Rust侧对应c_utils中[读写文件](https://gitee.com/openharmony/commonlibrary_c_utils/blob/master/docs/zh-cn/c-utils-guide-file.md)的接口。其在Rust侧构成utils_rust包(Crate)中的file_ex模块,包括对文件内容的读写以及对指定字符串的查找功能。 +## 涉及子模块 + +### utils_rust::file_ex::ffi +子模块`file_ex::ffi`借助CXX工具通过FFI实现与C++对应代码的互操作。其中各接口通过FFI调用C++侧对应接口,以实现读写文件相关功能。 + +由于使用CXX对Rust侧以及C++侧的接口进行绑定,该模块中的接口命名风格与C++一致,其参数类型为兼容C++的Rust类型。 + +`using utils_rust::file_ex` + +#### 全局函数 + +| | 名称 | +| -------------- | -------------- | +| i32 | **RustCountStrInFile**(fileName: &String, subStr: &String, caseSensitive: bool)
查看指定文件中出现指定字符串的次数 | +| bool | **RustFileExists**(fileName: &String)
检查指定文件是否存在。 | +| bool | **RustLoadBufferFromFile**(filePath: &String, content:&mut Vec)
从指定文件中读出数据,存入输入缓存区(`Vec`)结构体中。 | +| bool | **RustLoadStringFromFd**(fd: i32, content: &mut String)
通过文件对应的文件描述符,从中读取全部字符串存入输入`String`对象中。 | +| bool | **RustLoadStringFromFile**(filePath: &String, content: &mut String)
从指定文件中读出全部字符串存入输入`String`对象中。 | +| bool | **RustSaveBufferToFile**(filePath: &String, content:&Vec, truncated: bool)
向指定文件中写入缓存区(`Vec`)对象中的数据。 | +| bool | **RustSaveStringToFd**(fd: i32, content: &String)
通过文件对应的文件描述符,向其写入字符串。 | +| bool | **RustSaveStringToFile**(filePath: &String, content: &String, truncated: bool)
将字符串写入指定文件中。 | +| bool | **RustStringExistsInFile**(fileName: &String, subStr: &String, caseSensitive: bool)
检查指定文件中是否包含指定字符串 | + +## 使用示例 + +1. 测试用例编译运行方法 + +- 测试用例代码参见 base/test/unittest/rust/utils_rust_file_test.cpp + +- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C) + +- 使用以下具体命令以运行`utils_rust::file_ex`对应测试用例 + +```bash +run -t UT -tp utils -ts utils_rust_file_test +``` -- Gitee