From bb239de2a5eb1fde857239430e1e792fedaea267 Mon Sep 17 00:00:00 2001 From: f18m Date: Mon, 27 Nov 2023 23:46:31 +0100 Subject: [PATCH] First migration round --- doc/arch1.png | Bin 0 -> 3747 bytes doc/io1.png | Bin 0 -> 6969 bytes doc/msg1.png | Bin 0 -> 5574 bytes doc/msg2.png | Bin 0 -> 10425 bytes doc/msg3.png | Bin 0 -> 12753 bytes doc/objtree1.png | Bin 0 -> 4988 bytes doc/objtree2.png | Bin 0 -> 8757 bytes doc/objtree3.png | Bin 0 -> 15057 bytes doc/zmq_architecture.adoc | 177 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 177 insertions(+) create mode 100644 doc/arch1.png create mode 100644 doc/io1.png create mode 100644 doc/msg1.png create mode 100644 doc/msg2.png create mode 100644 doc/msg3.png create mode 100644 doc/objtree1.png create mode 100644 doc/objtree2.png create mode 100644 doc/objtree3.png create mode 100644 doc/zmq_architecture.adoc diff --git a/doc/arch1.png b/doc/arch1.png new file mode 100644 index 0000000000000000000000000000000000000000..30a4f7990c36287ce06c652c1d606411d60c37f3 GIT binary patch literal 3747 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 I+Y71x0w#zpZ~y=R literal 0 HcmV?d00001 diff --git a/doc/io1.png b/doc/io1.png new file mode 100644 index 0000000000000000000000000000000000000000..21f58ecf0c796f08af26fc2b2c887b9c948eb743 GIT binary patch literal 6969 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 literal 0 HcmV?d00001 diff --git a/doc/msg1.png b/doc/msg1.png new file mode 100644 index 0000000000000000000000000000000000000000..ddafd84d0ae6bc54a523d4afbd2ea2f8af5a943e GIT binary patch literal 5574 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 literal 0 HcmV?d00001 diff --git a/doc/msg2.png b/doc/msg2.png new file mode 100644 index 0000000000000000000000000000000000000000..67fb269c1f2cfcd1a128fb09ea7874c4987eae4a GIT binary patch literal 10425 zcmcJV2UJt(y7xCW934Of6+ys4Q4tuVNsUU;Nbk~B1VS&NLjvkpP>>=`y7bOSuVO(^ z=`E3tB7{&C2uKNh&vx!zXU=zLec!$7oa?M5BT4qoe&473|G(!A($cuhw1;C4f*?%T zD@r;DvMmTf820Vn1-}_In3IAZyKbspRzkMW|5EC*o+8LG1gmsW&pTmu$VV&EE2-(b zX5O(=l6yi@Zhr6yeaJag4+6*(+h&hOKUAbgB9Pc4sc~{2i zPW*4W-YOLlFRqABS-Zvl5}x9HOZy80!}sg#-$p9}(r3yDVTv4a_gC^B?UAEY@O+Nf z+^SBt7zh?sfv@z6OUAnzej=p`zbnCyYx@px9^>a%F)}hr65fu~a?{zqasTlrAu@Gk*U3`JP{Y z?fDobnAjvsSS#gMi#=8|R2Y8pvK@VmwrBV5?21>7NjBpjqo%sELbq+-4wuawZ;p{A zC(8NgxVpL)56nIa3hKPi#5q-PoR3d=b#?VB7OSnK^!r3>yrFX|;v%p{4V}yij1grL zw`n`d%ERMaXi@JJENcBe>^T3KGanPqyS~xW(~Hf~&5FCdoiPrs9-o_g2LEmJ;@H@j zQ}Emsv^>>tGvIb`i$OYR3jIfP0Kr5w&9m1wORM=yRMNWXB#X! z(O+iIFC|50w^UPC4+#nm7Taeo;c{^5yuIVZWm1F?*0HB}_*0 zw&9eE$6Z$!#?fyDi#Ay0fPTG`C*Q6v`pwtb9A$oxlau2r{P@We$@!P-g{y1RMIoV~ zp*h*vE``l)ZB8z__LDvu$qJ4ebh^5yXL*(9Y+SSJ=0Z$8I}Z=fBDsFEx5{CCc~)Ek z5qd$ML!G%vy+jr*}A0aY+hj@>E7PM zY)6mg7n;?`kZIH8qStAOO!AsroAffP=0gQ$H3qPW98yjRZfG<$yksh5K;j+|_q>YlIdT9)U(#(&##jtgIFkbzw$H8e-nen&jG&;dl~o45udl>r ze%;#xtESc?knEpYTzpPFUQ)fpx>ZMAUA;hp?chO)$yhH*Eu@lXshg)$lVRSqJ?z@G zYuQJ{tZ@)6j~+j^@4}|0rAc^yyH1~ws_zWpl+x4DNi{V0$-p+{t6#i$o0&@{JzmQB zV|%+M^8-aL8Fv@bZ@7+Q85tQ=h?lj`4|taP?TaKPE8*2FjYK!UI;5X*jk=WvJ2aMb zTvS%p#LCLbxcF93vzgD%ojXGmf?BP+pK!@8y*q4i>iqd@x|wR7gH`x=J#R;Nurim= zm(Znjst}ZyH|y)`o9cLe*FiGA+C+`az4e}elwyTQ$0DuW0{$mcHNok z5Y=(=e&qwxyE@7{HMe-s43o5!TkLDK2%wjJ`SL|iTl;fRw`xSW<3MILNMMX`0dXdIWSki_SDZ?=#9j236$lwP{5vlD6l0vgH{PTZq?1sXH z{BewT8^!jy)E6sWtMF099dvs#DtqPu-JeC_w(ZT; z=Q!_@lBMdJnk>mgXA8NA@koXjdbtmjl$0Dia3J;jSW|_&y5pNo`nrVsq!u49uXlCi zp%)(02I!sAE{86=pEf^z@}#0=V{m7wZMU4+BXT?@;AK+4=BmNL1Jo>aMU1j#hvtyY z=EiE-gNBrpWAf`WC9@NuT|=IbRfUBkP~Qf6$2=-98=qM?FvQvgP1`wuW6$n}d?b|6UL&g1)GZ4dot_5BxLsBGTOB9~HN zQsG6D}-$*M1TYr|&ejvd*lsh1*3-NvudsNI)u-@d(P@80f(@#e$< z$T&Uc+VA%pLwQ630sIS*J2@A78VwGvE$?8aZ=7nPzPr`Yce&H3n2;kEwcP z<579vo*g@O#6A_!pK6ckXg54wUt9Y* ztZ~Ru>8^2hs3#oaxUg!^*<5M-#3VekakYDnjMrR#W#xG$9tBei0sC4h;#E~uPJ$W7 z$8Pfcn|piR&L5p36~yEFpy`>GfB5)O$H5{0&D*yJ_wRqcwB&A9<5|$w@o96+sDV}%-OT<#Hg4U!E@)j3TVS0y2&DE&#J|U zSdbtc6PoAzGXtOl$kTdseQCXh`g(flZ{A#@PZ`#``CwWSX_D?dh(XdEV~9K>y+_}E zKI?a-((|Ay%HBO-jJb3$@nQL&}zCRYvcIc2@ zWAG8^1^qI@9jZNj zxuV{qu%3Q@{<-3VkJcry%}S^OY8HiBpphukn+-YaQ_a(%8J}6UqFclg)GCSz%c8i* zx_y0kpM|Gzbo9FPQRbbycG-=-y3L)JCC$snXA3=pL)J5&xbQUje2k%if!*gf_t4!Q zax(Pwtu8Jp8CrYL7mL4TW0RMkucjJ(*0oBo2p%t@)NjRUb$uOHQfH{zqdQwWtrVWV zqSsd>sg@`iuP*C3qXqIyC6v1$nLcA9%!Gk=ioE=h3Xh)_#40e=XOpZCIovF&qpMqH z+s)rM>)DzlUvqIiWwleYj`e3N@W`Hha>%(lKEJ%iSB}t#fD5ZcW($;ud|S z^{007ZY>b?8hf1!e?4~^92yi~(rr&eTU-ypcxG+_5+sZTwJsM6E4d$M(T+& z`kpmrAUb>@QW6z2xd~ z&vIsF9F&!mCRggW>a60|CNMHS3+b?tw<-n>va+TzaY|OU44ac{H4$T}HQTqHnz#9L zh2*Q(pE;YFCOnhIXF_EVZDfC%ob23|jB$oERD(){y?XT=C=SpsJ!-MPy>3aAC0EUd z9an65%YtzLwP_7f8uDJ8MSdv^PjGD4nU1%o5})+3tJe|Rbuo@^xe8?yZ6*f~AC`4K$Rp_x%X?Z%%J6b1cW)CJ5C`_}9vyrX8fvJb za(`oEgBQE^&{-D+yy}%JT6T81!J^T!zP!>D<1@m-p2NoVP|{$x;d+AN;-#HU4vyAs z3Dk|vw$;!i{{`&$#KcrX5bN5;V*5B$M5sX-AO`0Kt0GJ(1Zb!B-x3Ul`JvcBLrW5V zYwt=o768T2sX2WagX3_1No?J8TdcxU*x1=8&&6~&9u_tYgK!SzmQQFtapDA;OR(C~ zF^~x|^(!=5FDL-_X;Oi4JGrAOngicL$}C(B6*jNUhK%u`cD<`2K$awqjI<{hAjXV8 zZ*|+xemT5Bfv`3Sisp=vP}JMcE=GsJlI0l|R@-2F*~P7GxhIIssw966^(fMG_hSSluI@fOx7tG8RPKq z@T=<3YxSdq&8pKu8_TavrnSYWOyO5HF3iQ+Q|Bzp`Dv{IY*1$|-ra>t11V?Nc+5r$ z+1#(S>LuR8iM%GpZ^rhB}=mM z!Qry|URXY8F2-!FwxedVEjceQPaS+;5Linwn>L4V-}!glUSnlZ(>S&D%9^S=TSsyz zvA=p9K`VQu;ofCrA)yOaexa=3FnNDA7rp0^ zf>uSjJJ&Bkjve_%CD5GHp$tYvMxyp`YOty#tJzMneq&su_l4zU`kYsNo(COvLC?S- z^8pX>TExZ2T=znhVI~?srs{X$`PeD?cDIZlZ)*b!}cWk!~w#$*Nkhu zMZ}Ea;^JMJa)So0TnrtIgKr0lPJ+l2L%Y)NzwgjDFp!C<+uB@@J7@I>f9^BLf~mvx zKkgCNx|2a)4X(m9(>pq}>K5B%lg`xlj>>FHVX1sjVR2dIz~{2%`4MNME$4BBjo6h2)zL9h%zmOw6gE-NfbRozn`;;6t66s1X3CyXbzzJal?@pu#Bkushcg ztWx~)o4q35)xS&L{>yLw{U!+YQ<5Ou{XWNvTI!jb7h<3C`=n;>5^F@A47Bz|_tV0l zz)u1UdH3#}bc|U&(d^~Rm*5{3QRA8DHLUIJT?vw1-t3X#$M^5GKw(RGOzHi!b?45x z13rqWm)HE+k^eNE!NI}(ieDgdQ%Y>weN!`4RtH8lGx=1bajkI@Ny6{mRg4hxKw29` zuYm6aIVohJCAPji;Ec*$U=2RiY()(;d{O<@dOd25vYK7~!_vNn-x@2XR#du;KLXd1 z)f^+@SIvfevs=wJ2<}mX_oi>ubJh4qwoH2T`FE%O)VI5RnD_z;yeaHa6Eq! zm2bE!N1;{>dyg@N@L_UaA|~Z(DBJ=LDsi)6H#j-Nh;;C!p!5ZSyF$34{+u_bw$^lUqV?(9&mca? z;LP<+O$XC0NtvPpz>2QL8ZXWCb=NL+sg@PEbn z-s}+bnlp`A<01aIfnM7(Sk(FDYNpTR^9KpjX=!P#fM6+ZFE4ZZG_)ki4@Abq#DgDx z8WC|5@;~0a#m}~-9Cp`h;YV}pf5!wz0Uk{?sc=H|BrGmq?haU1K5SK0m5l3`-#2GR zHq{jr6!!e`i#BNGI!aq}bNA=B4`?+bbPcfO5$QMH-p?^CGGCjBcXkK%T(>$A4`AI8 zz$?(c=lS_(LH|gHzPSE+8|9%D*vKbGrB7I@6;PVn+sVMVBa@N}=Z0#U$z;PkgMuyq zUuG(-oOm@rO%tQv!@Ok^uo210$#?GFwJPZ|jn+3bMEhBPvDITzp;;dE0kn8aOG`(j zKRzsS2B@c5wY%#axx#tGx19iFA0%dVkIMjT3OIz`w971%VgN2fm9C1Q^xCW-RNLkW z1OlijA&9&@(jwaOK>oaDNbv(APa+nf*>}! z;w0?F?MY`*Qwvu1KLq5icL0EVL&;g1JZ4pH%Ag{^c?(a!dGp4dHl+{mmA(4~hye;5 zMn^|?_4?U-ib@}@^UJerdh)Tk*}h|)kJC-f%W*FPV}sC8UP-;bLB<=`h>$9~m^e^z zIaKSTi`n>g*W7Qm%r{gT660NC;~Bs)(h*)WpG3_nT`oefJqixi13v(N+^JoB@U^Jm z>7$a9E$-TRoJ&q8iUxyKf$q>#=kFhY(~`!<_Yi;QtUP z>up`2LWSt9!rL%$%UwhL>R2eI5VSh@Xxo*!AsNUA-{qMc2#H*adSd?{Hx%#MYpARD zg6x5vlki)1z;;2PjL**(y?=iNRljK}Azd#C>v8UCUJgH(DL!ZX$wLSUJ^=yyzG5rx zQy=920;Rh%ATPYRijH9O+X2qHgA2uChQo?)zT2bH4lm6;H5{tci9r=0ND(jrdQDHb zXp?E7U@p{00=7_GU^gTH1?KS~A-m64hq8n)lCT^`j?3fL@cF@djb#6YAgj~~$o{-P z{?KA%KI&pL3=I>WxRP%gsC6LYCnyJYn``9y>Xsav;1?|~Y=S$#yn76YDL1+hC96U$ z(a)aQPP8SO%-@H+gMD&qQwOLWSf2Oxsip#Tp%Y*BqR#Mr^LVc(}F_d}z5zdS_dm3hNPNkS(}?gbzjKok}YEf!g*9#C#~7=T^VP zhF*o>h7Is~!hh}&+^K_Tq!2y7jJpX#2R$=0brk#J9@x=mCV-#f09?e0+eScpbhYsR zes67g79RCC&6ute-nEVy!UlNT#nAk}8 zE=?X1YSS%u8p?%TT<{(^#qB&09UlH%J59y*&F{Y?3GYN|`+=%w2W&J2xZiIuzI*__ zQZDcZ;Nqp;x0Ch(v#J>OecUvl^4)u&{KHcLw5P!CEV!RWMth-MFM)%V-P(H1$^0*Z zYFOC+C-YtzhpNe;;9m)aN`kPq#Lpx0=UCDy`&VR?8F0C9uxPcO$VqVEQK;Dr(vI z>%HH9p9B-#w$(rDNm&CYpanBN-3u22H|Zl=W*?)B>_V#i1mp1Y%XEi5dcDyddD4e4ZQl%7Cvj*~6OS>Khp0+4}cL`2%97YvjC z2{+)Dq>rfY2qfL(G(@f`{R1NcaOFdX1RlfhtS+MTVU;3f=EHCfZq~oh|cqJvJ_v~XEs}#&u6;LBiZ3!erT4LbJ z7ZBzWpmcyh0ewX`RCpSOi5^Tx&ucL-Fu+@Njg8|L1K3yM#0m-t#*hC-N3Kle6-|M) zjNu*suT%b9{F7?Z)Lhjfv~O{cQvjQ6J5nyT<)}}^iL`TW%x`TL@oOXi#>c?QRre4n z^)DI*0}*7t_w4ab_B5jsYukp0`=RjnCT}hYG-tmB%vl<+MFbv=hCd4G1L))cYy|9A z7RVuc2pu5XJun|Mn^!2fXl|ZlP+**~osk)(Q)pKOzGgIC4kH>8@Q3*g)M9{OlYkiw zwhQG0Mn>TNHF8Qz^?(m_vuet9MzCacN;(hcH#8{GyD{{quq^s8VMZN2G)R=A`xw!H zPxe4xr2(9rMC*c^TQQ@ca{|0+8nZcuabI1qde_uMHd(LZo(5FOfZ&+o_;`tntx_;| zCJPqTo`ATgP4%imLVEV05_Jy?OAIfp${CR3JTQGtY^qBp80$b42SO(VWH1*@DeMx5 zwA-z^^}3CP<~10glsOJauKxIOo|3Jqsc8tQJ3c*~r=MqF3zfcrDE{L4T$0ELDXN> z)FhYLlc(h7=ri3BYb*0bLMG+7+5WOUOiaCSkOO9Qx)cRC3WBoz<+-8hgwh{v(o;_L z4xC4hP!rM$g(}JZKEtDJt2^j)`gFliJdYrfLbr?NG(=??EEUMYw>~9r5>H;YX-nvY zAxB0+!co+%fJUKqWypBW#Ny*?C~EfaVUKU#Og+HL3hFik29P*Xz7Z4&!w1YHxlL+T zvK`D{`)j<4R3E-fmYy0-jOE;ibQnuCU%812wqMy(VAg`|0`0m4#+y|264taU)Oo6+ z&jHrG6FAMZTkxMZN;1&WN>O~kj2;RACkt*STjJfPKU3WYjkgDFr%BXqVIG;1t3@*Ntxw!JnfO1oYSli@^>AcS@n= z$c02evEwf1=T@T<6Ng4E(QzJ-do3}8y@<
    -btws4APt<{-`Z>PZsf=Q;W*s2*N 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 literal 0 HcmV?d00001 diff --git a/doc/objtree3.png b/doc/objtree3.png new file mode 100644 index 0000000000000000000000000000000000000000..f7fc44ba1fde055542aef48822cc5dd9066a721d GIT binary patch literal 15057 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 Gef}3EAI+%% literal 0 HcmV?d00001 diff --git a/doc/zmq_architecture.adoc b/doc/zmq_architecture.adoc new file mode 100644 index 0000000000..225de744ea --- /dev/null +++ b/doc/zmq_architecture.adoc @@ -0,0 +1,177 @@ +== NAME +zmq_architecture - 0MQ Internal Architecture + +== Introduction + +This oage is an attempt to provide an overview of the libzmq internal architecture. +It is not intended to go into too much detail. +Details tend to change as time goes on and the document would get out of sync quickly. +To get the details you should check the source code instead. + +The first thing to do is to warn the reader that the codebase is complex. +It's not complex in terms of number of lines (currently it has ~10k lines) or by being spaghetti code (it's not). +Rather, it's complex because of sheer amount of different combinations it takes into account. +Consider that it runs on over ten operating systems each of them having several versions. +It runs on many different microarchitctures ranging from ARM to Itanium. +It can be compiled by different compilers, starting with gcc and ending with MSVC and SunStudio. +It has to interact nicely with 20+ different language bindings. +It allows to use different underlying transports as different as in-process message passing and reliable multicast. +It supports different messaging patterns: remote procedure call, data distribution, parallel pipelining and more. +Each socket can either connect to the peer or allow the peer to connect to it. +It can even do both. +Dialogue between two nodes can either survive breakages of the underlying connection or it can be transient. Etc. Etc. +All these options are mutually orthogonal, giving literally thousands of possible combinations to take into account. + +The moral of the above is that the code is complex even though it may look simple and it is easy to break. +Till now, approximately ten man-years were invested into the project amounting to 2 hours spent on each single line of code, +including lines like "i++;". +Thus: Be careful and try to understand what the code does and why does it do it in that particular way before changing it. + +== Global state + +Using global variables in a library is a pretty sure way to shoot yourself in a foot. Everything works well until the library gets linked into an executable twice (see the picture). At that point you'll start getting bizzare errors and crashes. + +[[=image arch1.png]] + +To prevent this problem //libzmq// has no global variables. Instead, user of the library is responsible for creating the global state explicitly. Object containing the global state is called 'context'. While from the users perspective context looks more or less like a pool of I/O threads to be used with your sockets, from libzmq's perspective it's just an object to store any global state that we happen to need. For example, the list of available //inproc// endpoints is stored in the context. The list of sockets that have been closed but still linger in the memory because of unsent messages is held by context. Etc. + +Context is implemented as class //ctx_t//. + +== Concurrency model + +ØMQ's concurency model may a bit confusing at first. The reason is that we eat our own dogfood and use message passing to achieve concurrency and internal scalability. Thus, even though ØMQ is a multithreaded application you won't find mutexes, condition variables or semaphores meant to orchestrate the parallel processing. Instead, each object will live in its own thread and no other thread will ever touch it (that's why mutexes are not needed). Other threads will communicate with the object by sending it messages (called 'commands' to distinguish them for user-level ØMQ messages). Same way the object can speak to other objects -- potentially running in different threads -- by sending them 'commands'. + +From user's point of view passing commands between objects is easy. Just derive your object from base class 'object_t' and that's it. You can send commands and define handlers for incoming commands. Have a look at command.hpp file. It defines all available commands. Say, there is a 'term' command with a single argument called 'linger'. To send 'term' command with linger argument of 100 to object 'p' do this: + +[[code]] +send_term (p, 100); +[[/code]] + +On the other hand, if you want to define handler for the 'term' command do this: + +[[code]] +void my_object_t::process_term (int linger) +{ + // Implement your action here. +} +[[/code]] + +However, be aware that the above only works if you are derived from 'object_t' class! + +For most commands, there's a guarantee that the destination object won't disappear while command is in-flight. (To understand the guarantee check the section explaining the object tree model used to tie asynchronous objects into well-defined hierarchies.) However, for couple of commands (basically for those that are sent across the object tree rather than along its latices) the guarantee doesn't apply. For these commands the sender calls //inc_seqnum// function on the destination object, which synchronously increments a counter stored in the destination object (//sent_seqnum//) before sending the command itself. When the destination object processes the command, it increases another counter (//processed_seqnum//). When the object is shutting down, it knows that it can't finish while //processed_seqnum// is less than //sent_seqnum//, i.e. there are still commands in flight to be delivered to this object. The whole process is done transparently in //object_t// and //own_t// classes. Command sender and command receiver can just send and receive commands and don't have to care about the command sequence numbers. + +Remark: Actually, some pieces of data //are// enclosed in critical sections. Two rules apply to choosing where to use critical section: + +# There's a need for the data to be accessible from any thread at any time (say the list of existing //inproc// endpoints). +# The data guarded by the critical section should never be touched on the critical path (message passing per se). + +== Threading Model + +As for threads, there are only two kinds of them in ØMQ. Each thread is either 'application thread' i.e. thread created outside of ØMQ and used to access the API, or an I/O thread -- created inside of ØMQ and used to send and receive messages in the background. 'thread_t' is a simple portability class to create threads in OS-agnostic manner. + +It should be understood that while the above discussion is correct from OS's point of view, ØMQ has a bit different notion of threads. From ØMQ's perspective, thread is any object that has a 'mailbox'. Mailbox is basically a queue to store commands sent to any object living in that thread. The thread retrieves the commands from the mailbox in the order they were sent in and processes them one by one. The mailbox is implemented in 'mailbox_t' class. + +There are two different kinds of threads as far as ØMQ is concerned: I/O threads and sockets. + +I/O threads are easy. In this case OS thread and ØMQ thread correspond each to another. Particular I/O thread is running in its own OS thread and has a single mailbox for incoming commands. + +Sockets are somehow more complex. In short, each ØMQ socket has its own mailbox for incoming commands and thus it is treated by ØMQ as a separate thread. In reality, single application thread can create multiple sockets meaning that in this case multiple ØMQ threads map to a single OS thread. To make it even more complex, ØMQ sockets can be migrated between OS threads. For example, Java binding may use ØMQ socket from a single thread, however, after the work is done, it passes it to the garbage collection thread to be destroyed. In such case the association between ØMQ thread and OS thread changes -- the socket is said to be migrated to a different OS thread. + +== I/O threads + +I/O threads are background threads used by ØMQ to handle network traffic in asynchronous way. The implementation is pretty minimal. //io_thread_t// class is derived from //thread_t// which is a simple compatibility wrapper on top of OS-specific threading API. It is also derived from //object_t// which makes it capable of sending and receiving commads (such as //stop// command which is sent to the I/O thread when the library is being terminated). + +In addition to that, each I/O thread owns a poller object. Poller object (//poller_t//) is an abstraction over different polling mechanisms as provided by different OSes. It is a typedef for a preferred polling mechanism class, such as //select_t//, //poll_t//, //epoll_t// etc. + +There's a simple helper class called //io_object_t// which all the objects living in I/O threads are derived from. Thanks to that they are able to perform following functions: Register a file descriptor (//add_fd//). From that point on, a callback is invoked when something happens with the file descriptor (//in_event//, //out_event//). Once the file descriptor is not needed, the object can unregister it using //rm_fd// function. Object can also register a timer using //add_timer// function which causes //timer_event// to be invoked when the timer expires. Timer can be canceled using //cancel_timer// function. + +[[=image io1.png]] + +It is worth of noting that the //io_thread_t// itself registers a file descriptor with the poller it owns. It's the file descriptor associated with its mailbox (recall that any thread, whether I/O or application thread have an associated mailbox). That fires the //in_event// on the //io_thread_t// when a new command arrives. //io_thread_t// then dispatches the command to its destined object. + +== Object trees + +The internal objects created within ØMQ library, are, for the most part, organised into tree hierarchies. The root of the hierarchy is always a socket: + +[[=image objtree1.png]] + +Each object in the tree can live in a different thread. It is in no way bound to live in the same thread as its parent. The root of the tree (socket) lives in an application thread while the remaining objects live in I/O threads: + +[[=image objtree2.png]] + +The main raison d'être of the object trees is to provide deterministic shutdown mechanism. The rule of the thumb is that object asked to shut down sends shutdown request to all its children and waits for the confirmations before shutting down itself. + +Note that the exchange of shutdown request and confirmation -- which are both commands -- effectively flushes all the commands currently on the flight between the two objects. That's why most commands (those that are passed along latices of the object tree) don't need to use command sequence counters (see above) to guarantee that the object won't be shut down while there are still messages in flight aimed at it. + +The shutdown process gets more complex when object decides to shut itself down without being asked to do so by the parent -- such as when session object shuts down after the TCP disconnection. We have to account for parent-initiated termination, self-initiated termination and even the case when the two accidentally happen at the same time. + +It turns out that all the cases can be solved by self-terminating object asking its parent to shut it down. The diagrams below are sequence diagrams for all the scenarios. Note that parent asks child to shut down sending it //term// command. Child confirm its termination by sending //term_ack// back to the parent. Additionally, child, when it wants to self-destruct, asks parent to shut it down by sending it //term_req// command. + +[[=image objtree3.png]] + +Note that in the last case, the //term_req// command is simply ignored and dropped by the parent. It knows it have already sent a termination request (//term//) to the child, so there's no point in sending it anew. If it did send the second termination request, it would arrive at the child after it have been deallocated and trash the process by causing a segmentation fault or by overwriting the memory. + +The object tree mechanism is implemented in //own_t// class. Note that //own_t// is derived from //object_t// and thus every object in the object tree can send and receive commands (it needs to do so during the termination sequence). However, the opposite is not true. There are objects that can send and receive commands, but are not part of an object tree (e.g. pipe endpoints). + +== The reaper thread + +There's one specific problem with the shutdown mechanism as described above. Shut down of any particular object (including socket) can take arbitrary amount of time. However, we would like //zmq_close// to have POSIX-like behaviour: You can close TCP socket, the call returns immediately, even if there's pending outbound data to be sent to the peer later on. + +So, call to //zmq_close// from an application thread should initiate the socket shutdown, however, we cannot rely on the said thread to do all the handshaking with the child objects. The thread may be already involved in doing something completely different and it may never even invoke ØMQ library anymore. Thus, the socket should be migrated to a worker thread that would handle all the handshaking in application thread's stead. + +The logical choice would be to migrate the socket to one of the I/O threads, however, ØMQ can be initialised with zero I/O threads (to be used exclusively for in-process communication). Thus, we need a dedicated thread to do the task. And reaper thread is exactly that. + +It's implemented as //reaper_t// class. The socket sends //reap// command to the reaper thread, which, upon receiving the command, takes care of the socket and shuts it down cleanly. + +== Messages + +Before we can progress further, we have to know how ØMQ messages work. + +The requirements for messages are rather complex. The main reason for complexity is that the implementation should be very efficient for both very small and very large messages. The requirements are as follows: + +* For very small messages it's cheaper to copy the message than keep the shared data on the heap. These messages thus have no associated buffer and the data are stored directly in the //zmq_msg_t// structure -- presumably on the stack. This has huge impact on performance as it almost entirely avoids need to do memory allocations/deallocations. +* When using //inproc// transport, message should never be copied. Thus, the buffer sent in one thread, should be received in the other thread and get deallocated there. +* Messages should support reference counting. Thus, if a message is published to many different TCP connections, all the sending I/O threads access the same buffer rather then copying the buffer for rach I/O thread or TCP connection. +* The same trick should be accessible to user, so that he can send same physical buffer to multiple ØMQ sockets without need to copy the content. +* User should be able to send buffer that was allocated by application-specific allocation mechanism without need to copy the data. This is especially important with legacy applications which allocate large amounts of data. + +To achieve these goals messages in ØMQ look like this: + +For very small messages (VSMs) the buffer is part of //zmq_msg_t// structure itself. This way the buffer is allocated on the stack and there's no need for using allocation function, such as //malloc//, which tend to be the performance bottleneck for small message transfer. //content// field contains ZMQ_VSM constant. The message data are stored in //vsm_data// byte array. //vsm_size// specifies the length of the message: + +[[=image msg1.png]] + +Note that maximal size of the message that fits into //vsm_data// buffer is specified by ZMQ_MAX_VSM_SIZE constant. By default it is set to 30, but you can change the value when building the library. + + +For messages that won't fit into //vsm_data// buffer we assume that allocating the buffer on heap is cheaper than copying the message data around all the time. We allocate the buffer on the heap and make //zmq_msg_t// structure point to it. + +The structure allocated on the heap is called //msg_content_t// and it contains all the metadata relevant to the allocated chunk: its address (//data//), its size (//size//), funtion pointer to use to deallocate it (//ffn//) and a hint value to pass to the deallocation function (//hint//). + +The buffer along with its metadata can be shared between several //zmq_msg_t// instances. In such a case we have to keep buffer's reference count (//refcnt//) so that we can deallocate it when there are no more //zmq_msg_t// structures pointing to it: + +[[=image msg2.png]] + +As can be seen on the diagram, to minimise the number of allocations, buffer for message data and the metadata can be allocated in a single memory chunk. + +Note that the reference counting mechanism is accessible to the user. Calling //zmq_msg_copy// doesn't physically copy the buffer, instead it creates a new //zmq_msg_t// structure that points to the same buffer as the original message. + +Finally, if message buffer is supplied by the user, we can't store the buffer metadata in the same memory chunk and thus we have to allocate a separate chunk for the metadata: + +[[=image msg3.png]] + +== Pipes + +== Message scheduling + +There are different scheduling algorithms used in ØMQ, however, all of them work on a single datastructure, namely on a flat array of pipes. Some pipes are //active// meaning that they you can send/recv messages from them, some are //passive//, which means that message cannot be sent to the pipe because high watermark have been reached or that message cannot be read from the pipe because there is none. + +If the individual pipes in the array were just flagged by active/passive flag, scheduling would be inefficient. For example, if there were 10,000 inbound pipes, all of them except of a single one passive, fair-queueing algorithm would have to check 9,999 pipes before receiving each single message. + +To solve this problem, all the active pipes are located at the beginning of the list, while passive pipes are at the end. There's a single variable (//active//) that determines how much of the pipes at the beginning of the array are active. The rest are passive. + +Thus, when performing a scheduling algorithm, such as load-balancing or fair-queueing we have to bother only with the N initial pipes which are guaranteed to be active and completely ignore the rest. That kind of approach leads to O(1) scheduling. + +A bit more complex part is how to activate and deactivate individual pipes. And it turns out that it's not so complex after all and that it can be done in O(1) time. The diagram below shows deactivation of pipe X. Note that all that's needed is swapping two elements in the array and decrementing the //active// variable: + +[[=image sched1.png]] \ No newline at end of file