From 1c720ab2c7edcdf9e9af08b2e05b650f562e1372 Mon Sep 17 00:00:00 2001 From: rajames Date: Wed, 7 Oct 2026 23:51:30 -0400 Subject: [PATCH] fix(v4.0.0): what a node passes on waits with it, offered -- a relay is not held by a stuck node Found after the last commit: a message being passed on toward a node that was stuck held the node passing it on in the wait, taking in what came but serving none of it; text typed for a stuck node left Hera deaf. And a node that had done text for a sender that then stuck waited on it to give its answer. A node with nothing to do now deals first with what is for itself; then offers at once the first message for each port and each refusal owed, and sleeps in the wait. What is taken is written and done with; the rest stays with the messages waiting, in order. How text ended is put with the messages waiting, not written from (FINISH). The stack is kept as shallow between lines as it was. Co-Authored-By: Claude Opus 5.5 --- capsules/v4/nucleus-64.f18 | Bin 56784 -> 58032 bytes v4/capsule/core.v4 | 49 +++++----- v4/capsule/quit.v4 | 185 ++++++++++++++++++++++++++++--------- v4/tests/test_host_mesh.c | 25 ++++- v4/tests/test_host_quit.c | 4 +- v4/tests/test_host_unit.c | 9 ++ 6 files changed, 201 insertions(+), 71 deletions(-) diff --git a/capsules/v4/nucleus-64.f18 b/capsules/v4/nucleus-64.f18 index 2622e49267794d6df9dd9ce4b06ff505fe429ed9..a108582133d6dca4f0254dc24ecc3b934b960bb2 100644 GIT binary patch literal 58032 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 literal 56784 zcmb__34B$>_5aPw0tpyEkk!`bRzVG$RRIwavOqK>AqktbDgpv3$u$H;MTsqSK?>4p zUBOgwk4qI5ElNOCr1}KKty-lOEACN(xWa$VobUI(cL$!){{HuqPtKc}v(1?^XXeh# zz1M$d^GMHJ9p#_7=J!(Q$BOgiSL)c&M{17#Cm!?4e|^-;@;e0?gbfeeyG62wBft6R zIiJhV_47`+RNz5g)0+bQSf3{Zk}e8W{Mg_%l7EP|_%nfrd1+4xH2D@^e#_O{%eLkI zsY`7+`52|GsxJPP(qmo}x~VH@g!t-q_h*nO`_*72S< zNZ<)x_LBmKK<;2~vDN1UFU{r~{tB~a#01Y-2*9eA+t^cukumf9k>^Rs!(}O~2kK<*MzTJw}f9$8443 z$6mK_XZm2l^1M62zj=2jttSY(quh_pS|@mS1J94u*!urfLV&r9{VYHEEm!@{&9**g zg1-KyS8V#hfc}J#ocp|7qoVLpe+=r8t#)Smldn|oD)4>GTV(lcH-SK|$G!ETI5puo z&2L=tj@6HJm8@6xFGKeGq(%9UMfuYX|7Tj^Pdb-B+rj_)FdMJW2LCrwzEjMe zp!fUexXy8f_)#aH{QcMkcM9)$3pR`u$b8B*?Qx;x^NKz(%-WrPG=l9@y7^ndVSDsV z(ebQrN_aeDd)x%S>mRR=^;7y|IqK8AbBy&%+L8W9Kh1-DH=laB`T0rk3zFm)CdsFL zT>c{+{IZn#=fy65EFAYt|0$RJl9V8hwo$yn)-T7V)IYB2Fr6QJ-nP@Yz-~HUV;o?A zVSjI2qVa)tq8({J+NlM8+crh}dwcMoyG8x{d-(Ym^!L(E<3vC9hjY+gQhB(A;|Jr? zern`cyZcXRysZYm-=lm^ipGn1h}X0uA?Mwat=dUDu)#|ZFF&wWfP0

^7mt! z4(fN6`sZ2jf6n(hM|6B)f1HYP`nTyockgpDA`5R5K7RAC5dtZP^=F()D;!-cVA$2qzQp!}FH)LTS-jZVmjtGs zTsTo6uR|fP2cRF*@#34|ig7ggHE3M=7Wqd+G@eHCE6B>i9Pl|J;9H+71zEP#++S6e z=gH4}8_khvz%jrd;Lt^ZlAd2?$IVj5U_*dE2(ZM{xZz*j$Hq(gcUsj%J6=0ty%C@r zPWp(>;|6Wh`yj?)@-gjayK*J$V&rWS6^;F@f0}p`l1qOpiE!Sh@o)m@dqh-Ut^-s> z7TEiL`bqf$ZI7>EcTBtXoCZDp>`gYl(!PFaC)@6CLGTpfaeQ>}Gb+`t6;6XpgFQw9 za-6O|Q5)nd=;O!v+c<#c3ho0k3MZ)D^TQ2yF8H1WI5*&<_PGi6nYTda3m-z>N0hr; zc-?mYEUAZFEn?3Jl*z-KVXp72^ek0t> z{XN=`Y1=p^-{9MNGj3UA^KTdIOFchBntY7^Hwf;7v?uxp$9vXmD-88$fai=87&oHA z%v=q-#@PDp(PUt^OQHXo$P3>}k%`~i1vUl!3wDP;(0a5_~^f z*CS|$)tH|%{dp35k$*GV^|CW?hT0f*7 zqtG6`0JkQIQ~qL&6SNEIjb66DV3)2DKzWMzDcyj_g<##vfF&{y4Pn-O*QnA&z z!ivy@;e6P8G~ntb8duofpCV4t|Hi}43n=$NT^AtUM9jO`U;aY8-HI3VXY{u&@N2F& z8u|^QXF|SR-)~%^`%|PJh;>)Nm5cYA)MFm}jqC2r=REc)^p~x>I=w3NjISl0#z)qF z1^oLJ7_u4bkU}HZC$LW=&oF+a^j137GX_2z0DGl2)M$vOFss1NOWXqxT=aeu_U zZ)JNL`S!kb)JVNQggDRN`sj6{O(Z|8*sp-l4e-O%467I0aX^~RAENJXw(U%P*?u#; z`Uc_4dPfF^`40r&BLO+@GxDt62&s2QNuITMVP)9xLqLBVVEs;Ak6X)mYb?dujrK_& zrv6ZRvS=5-@BrBnxHQ021SdVHDOb28;rk02CW~00oFfR@3H>c{lC9=JX;cxCa z4f_eLNzDMM?mw)Cm`#|di{s;Ian3t_Z9OOE~Gika$*^K)%whQTa-^cNl`Q*1N z&{x-=sGo`Nw%(5beh52!1^h?SIA7^=qv%OLAl?tDTF!Nct*8h2n|NsXQ!nPf2mXyq zbRV5@iF*6H!}DR*gZ$n|>f{BhxaT5dC>=1AR9qpL(($jN9~Mrs*%u zyTbAL?zmp7tSo2$D+3C!-T&>hyO*xxAKN`Gec$a)I<~u6=NQ4d3ET$0O@O9er%C?6 zbRFl|UbHu%nTOd9&GCi(bAQnFg+9E$CLQDWye{wAae(&Yz6bSXJDT~tl|z4`U(o(c z9}T(gx=X-6_Mw$WzCr&j)pl{^9+h7IH?afj@e9<)$Nd!RGY|89rsGczYo_f;G z$3aiV3-^A6ctLwqYn*C9`{aVY8RwOlpP3%`x%H>CA{~!ykQ7C5<)!P7TM=+LKaZmP zTli&Fq$yXj#+IIJ11!^J<4dEG&$L;-u_Blr5ldU)MrhLaBNr#h&dAiYODE}qr~h^P11 zc?j2;mD=+*p`DoCjP&Xyx{k*DmyyqP=L1pjFXXT9u6{{=^IB#s5)|_Dn|q%kY4!{H z8OxW&{cMfk`S4Sge+vU&MLg`+Q~m|%+AhC`UzvHBjf>QW@y*1iP&|1X`g5I*Y1a2< z^sDG<<;QZ?qp@uBZKCfh;6ph}p+`0QA@_AKF1`tT>P>qv|6bJdUZ?#TpIo~TpZ#<` zQ8`O5OLRzMPM)!+1b_ zo`$~j({pT;G6PL%Yf{caUK|LNM#X;=D%(aX*wS3^HPTlFEmA3JKD@UzMqI2m{i z{dE5P7UXPM{IK1}9eT?2Qw5*(3*s`)%MgDPGioHCnEpM#Wd|V zZ-K5`{sa0cmgnt2x;njSuH`)R2!+lBkI$zc7$71s#< zLGsUBX8r#;f$Lx&GtPy^@u!h5ICAlP)U(K6e}(ol()+vBZ`);PTsjW=bKRKdx%x35 z`@!2#p<|K19Q}dkfhaGqXH5Gsye@JE3Vg3|4td&AGTsVW`6U|gF^LfL_atj z_=jicdJ*GG1JCzBU$*1WjQYF9KAj-{{UH9SeQI%^F@p8Rz98Gp@U?N9^E7jQ++IT$ z9%=6{-i17SvfPxAZmXkDc}9t?Pk^^u*Ry%DqyqKwV_(?y$P>{{ZoQ%^-t$o}`faaC z#~dR?RhSQOJ~0dUOpnj22+c=^L=}PMy(aayBuwY!mkbdMrlV7*RVSurPMaD{OdlZ$ zbDazQlg(G&{^Ze-g7*ddbtn59;`l!1KQ?Z*DV$*Km_IiB+(sQH{6*=))waWSfo5GI zS0Lw6YtYV&S6nw19J#puZu;AWlBQpCJzDbQVt?bh`$X8C`#0PV_6X+?f&H?_|9x_x6l>T@fkRY@e&3 z9pZ9y-;HU;SIQy2U#jyF+MjmdKFfp9V>SH$g{SmBo%Zu%dLHZVN%SRNmkv!6Y`b7Q zW_@l5`jy(ntn=IcEVzkRvi!_qJvmfZQEnIh3&YEZ-a7c*1%U26o9kjFpO5PG*jKF0&rdk69xG0w1F8_-XR z(^cP{K^)ihpp;3f2ko>A?P2Kc#rp(J#pfj{zh#cX-N66Op`)Ku&o(8+x~^Q2XIwfS zC(+Im0ans^w zPSW-3szP1AEJ3{~uNUZg08&oM5C{M`1my<<@|?n2#Bt8MxQ@ekxE|$E@G<+~)^Gog zb*lg$=UIqvX6^ljpM<{t8PhN%KKP)cK)|c}b%R0G za~?Xh?rZkpt(@{=o$pY;8Q?n^(2bL3-Nf3bF6bYcHuJSy(bvQ?dle%tuzfQp<=gf9 z(MF&k6vD45_dLj()r#CpA=k*Uc6Q~Madm_6H}`8VS?Ju~ZG?Z*ZvR)mUj}{5ebXwD zN4{=5aNXOikJxr#oT5IAKhHqF_nmoGMt+5zPdSglddp$2d4OD}_&w6(_Xqf8+i`hz zd@Rlzq3s|_CtP=e?zYzXSwEoOtjD9UN4K;zJC2dHX%}mswmAP$S(T^rTOt5H2D$e+ z@)sbTP@jFuevLv5zxHgJ~deX(0;@93f}L(fp(7+7g>(f<83f{3GhYef$rw*LcC=> z>IQvwK|jWUw8D}~DYBI{ko-RY->rZV%u8Nrqw$aQ%xAyZ0Dp}@-iy$K`p`d!_eLA7 zcQQT6C#`CfRna<0f}Y<)zfT-Jd4J4)mDyIuqgUGKJ_q?yf1`(u9}&!}{(slUm6JZA zaHN<>SF7W8?}{7X6hO8s_2vBw?f1B2U)PTD@}?${x0n3``ubcc=ekh(Se-v>bdKwH zB=qV9$a>K)NYDHT=8bPV{>gqqzf8{?X~#F$9)lpK-%phH9_mB+j5F!uN7?b0ck}e~ z0`NVt75=-RKkLVK`KkSl@jj!Xuw3k1sK*P@mx~CT@3&*iJpgT87y-C+8qbXPT zoeezK{%(Jz{>$MH#E%FQbN$?S8~`u+v_-CER_e#CmxuEcxB!K1$=Ygg8X^v{Bxc5(YB^Phts{0H_j>#=qo^IqI8 zwjQ(_`v>hz{W(6fobsNB9^^|tj3d;8_-;KmvL22<;_>%A8JRjBo97JdypVb^p1y*4 z0qy;B?HI_%zDRFsb1y;tHSRPa9Uo8C-t0H&O6H{wSBC5_ zoxrahAlupXC)S((! ze9OR?d~?9>2#4=_hwlcYUB0|eff*C_pVZD=2Xfa9=Hgrj`#GNjufhJn7b%z7{T!~V z^11ABD8JEp&XnW3`#kLUOpP~V;kT8Ux*p8$x*B_5S4ykd~?m`f^iz^ z&3c(&i2Eme%5OOoV|PLf~h_wb6uWxW;xSQ zyk~~{m)xIh4+Ik*&X=F_4m;e&Cq6$%KIXk0r${;d<$A_5=Q;AgP7B|8UGUk?f6mnR zNZf$-^J99R-R#Sc5IkO#NBJ|*PF%lZIqN|`XZ!Iz0e58Tedt?|$Nhh{8~ylc)Z+p8 zH`mV|cKn@wM?UAG9auk8K3D3%a_Y(R%&Q##ZOYRA^Azof^+fvH8V8^98~cUZr!q_Z zn10Q5YVx@W_S*n{8_}Kl=m9w-f-wBkMjdQ z|K2u>^BdjoWIuWreEv;7c+Z<1)QsHSPCKz4q^Dm{uifD1r8G5(-ajB+_oR-?#P^r) z_*BXnFMYi4fc571*SO>gd(xWi?e{(0&L7!Nz6bw#eRN-(enaF5TB3g!XAo{(c38MZzy{Y>8cZ&q-px ze8?XRSns^==1jzllc&m_MF^4Z^) zrRei-e)i4zQqJ{=hMV-cF8Z;bec+c;PCrN+sn7S>Mw9|vvtb_-ukAH6t3FqLFpgxp zcDAbz7S;Z{5Oi|^-Tue=lY;HX_1%Pex?fa z(wjweJCEXfLdsXnTqNb}&u%&KX5c*}e9n*ZS)L5~rAu!U{%nuMN&F>?w{oVHonRCpx9T`82-`iVZ(sP`DA!v7${mAd<}w_XysIo=*B2jiwo=f}RYOWO~@f8NO2Xz8indx1V-Kji$9bnm+Iu)o0j z4ADuhbi^~>XP9}5ozG?+PJxD(WcI@TUgU?@6uY(*pPkDN-g6E>zfDhvt z<$jc<^KqA7pCtVF96$9M06f~&o$r%B>&Oni@I{36V z?NFJe^H|bR|02*CJy(hUQ%}ZOSI<{*AMrNeN5Ont_btnv=Se7s^*ROee&hJjX-?XG zzW4x9&Rl%ng6-+zbyhU<-na1kIC0={1x0JTi`3d`Tvi|#L^k33bf5u7P|6cFNxyyNepY6f; zpN!969X@aDTx!Qp(%*%0(x2T}^Esx=kv|IS<-}*b z&HCq`gz~?*kIX79vs1ak96irep=R(np1uS5uK*f9$`yLf)6;tE6Ufw_bpHkZHiwSm zY-Vpgw^LeKW~Q=c9}^5n|0(D`cIY{;%IK}@$CXt|NV=WC-{H_rgTH3>*7Gh!W7X~j zj@<7-_pL)uf6wkczD)G3D9BN};W@EFFrpr5n9xQ5X*WI(+cD0^-dC1YjI?~Ks&szs z+H*hfY3K0cbFyh;#ukfS_GVIk;OYka14#Fop1W>F`wz<0e!%C*Mq}NX^yzteza4(7 ziuq0e_#Fs1cUzb*&vg&VyzDLEMZTO*@O)|B)Ty;n&h)g|v!jXWnmKjh^qJ8R{^aWE z(*)nupYex$E9)jtN#uKWw8p;wkmb{A&paowyvDBD{x5vzR44M8Y8WS`&jI7s^sSgy zHz$#R`Ic4FF8$J&AQG1aL_EJt-(wbRd*JEwYTqMV;=N6rtpPByo_-XCz? z-F*)x`*HI~J(o#;;`*C^e|R2qaeKX=;QAN+;_mk0eV3I^`bj6f!AZa3q~CGUA2{i+ zopk1YVfo#i^r23=uaiE}NuT7TCpzgFPWoIYJ{k5+P5mA=c7ueO`n|T zA9XXserk@Jhy1*{POyKh-+^yUI4(?%R)_e^I%ArR6UqA-_{^DghR9>TnN}OM8Zcc` z6Aj0O>gj_1BmF3uep6-$9r;eK4acK8Rku~X1v96F^qW~z9kOrj1<_EvnRAX+zg51a zlV^qEM|9TAP`sHvQ!Cz@J@ad{1zFG9nscIw^`2c<8)~O1b#p@Te3}s)!k;xcRA04X z>-PUY>oI#TKM2RUX?9tFu1I_LR{In`l5{=biR>VM_6H6goAn^G5Q->K2_ zL*qlOtzGMOEtq*;xP6QRCbn1fj0-~Tec`lPE2lNT$*Y|n@{3v1!hRGrh6%~3IWr`u z)=UHv%WY*%Mr(3MoKxe@3qpF-MQcLs7d3(s<>>6AbvdOq(NLT*V#DM2%<#PDjA=8& za-!k!eDc(3w#8bjU%|99L+xH$t90z2#tlOKZ)&tU%#g?o<1#_X#d)2XNKBqwpK4`yC<7hnD#-vbv{h{R8M1mQ?AIZj@E_acwN*60^--y zs)br>m(gaTn^=$kYrTT;wq|Omy`s~@{qv{xi{k2Vyr`|66RKxjD|XIluj_O}01E-j z0Z#+02ITYlWNF_9_%Rah_L)`#8yyi|bBvkk9!f@z(FB^GWypH^eV*>Ag<) zkU!;?VEvr$!CAE*_tAB|D%pE*UVuFJJvh(A>Fv5JIGzo^gK;O{REzb~BSe4jX}ciq2P!`8WbCj)=-KYHLq>4Ft2Jf0mo3oaxXg?CDQm}dPW z%09@Cf?p57*8JdTr{1Jvz5T`d{4Jl0zUynzBK~|f+h-B_Ux}Ay{lmpeEf`xabX;#a z7Wy5=`o{)0NqJg9MVUa0Y#{N60B>*{U;Aa5e!;Cmh|ER&T;L6l<8PAkv`Sqcclj3q zuMm*W;n2>h75XMf@*fSnlZlV-9=`p~oS4Wl-$}DD%^WYX+)Oi%e!K{pxDoR7BtmOik+nv&-{iGLRG zW(N3pKYf8d*HAS|q{c5Fcs0b&*8KvmGx^TCmir!rA<^P$;l^?LyvgT;=CM+Y`_Cu~;MW7PbyKY4Mxe0L4wx#)kvL5TO%a9K;?~||ey{N?Rz2xSRQpPm#doMXK zH11JO`8IuD8{<0R4QQ`L*}C3s+ROSg&j*q3ZNO^;f6`Na@TQ(?ET#WS0ep~>?YL{=iP3Gy^P%M79a1&VZM2Pl#To6 zXX`$LQOBy1R-x<2CVqsj$Dq&MfKNfM4baQLkY3NZdf`1fl%HHLwKw%L>R44G!!(lE z${5WyLXXverk%En!jXz$R&V0Hgz{J%Z-e6HhVZta{1xJ54~YpvO0h*#BbuLYqWldP z@1!u^J1GAb;P;DX#{|RAKJRmZ=_Q4E0{NXw>bnj2{{d`ST%&Y27m+cx)Y_vAfq--$ z1OG!n-{0|~@K4E=|MB?t1LK<=+yoS-&fg zo?mG7)TbHa^1Ti!XAkjFuau+0@-u*!4rto9K`>Hs!g%dao&{Ksa|Gc1wTdpnJY3tD?FP-G^@G(*^f{#K z(9q_5&C8(DB-0=HvIIgBv4l59Sc>MwX zlMA@0gYFY2yzkI<1*S-!n_egL=={OJe2qpx98CNju3 zHBX;AWt{&8e0BgDf4@ucQzz(w2jcBU`44ft2L&(UoQp{9D7hvd&_Dg-EjHaB6MtK3 z<_{=u1K6P>=bQWfj#V&T_8$rk3Oa$lJz)2ajQipDaJlg%wN&pj$*d>n4~X-#zf!_# zdk3NXmjPb=gTf;vtd@5e$`1wfWB1wnzN4Vu0UhtNs=@8a80(%=u%HwF-YIPgw% z@cBGO8oozZs^S8@3W1;R(DAvdv=QOw-zl#I_$N7Z{C;0*d7kZ>#IFS27zdy0Bv<&l4^nza;a7GdjBS1U-)(8G0yMP{Adz%c-=_)}hvqI_}c)4`7(I zQF_10cu6LI0Nw9MkN3IqJ8DbO|K0Cxq=A94V;lKtzUT3TK+5ZzsgdCZ)Ze8~6=ZWI zqi0;1;VpPt@X{)a?R=2_D|vD)gWd}PZ-=~v9rb=&XXRGTD#1?)o6oxgbhiSU?;Yg| z9U@;_o9j~(BSkU6NmlMJ^ldr6!}vJ#;=Hv#1pJ+Tfb;*yBj41=Y7{xN5;+Q1 zL(hBS(2iek40*)HvGr)LrjGPCz0Z#v8V+F3fW8UPeBb0rk-+w&|Cl)Vy5zH+GJ@}# zhV_bp&+~w<2K80>Z_Gc47-cMypGb?6zNDA!%L+KKw_LOaloMt|F0 zT=ys4a`e;h13QJ=uX*t@>;GIAi*(|68orPEUB|Hhn)bEwZtbY^KGQxn{RRDQv99Nl zFKuVyfyE=eOXup-8Ty#uW9eM_Wbz|@xpJ+NyW_$7&uH(@G@el}+UW=ApVF5l3ZtMu z5YXSI^z<{*lZt#&$A%T@1Ny_rCy5?yJE5PB4J$GLbUCDNMGx{xEePu|1oX#}PZB*k zP>+JJ9wR_EjP$MOK|U!QP+_Q(L0<%TSf}-N+>P`N$ANN`mjUv9x}1j1!8&P9r?8(A zk5Ot6;so){dkL)n-vYhZZCEI64UH==VVmGQCVK?T}ZdZ4zKUa7y?40!J88Ka_gD`?#xLqgK5jkZ?bN4M8>-hxg`I1u~Gf!A2Ecv~cwL!esahkpSIneR>rc2RK&j9~9 z=*#zRlaBlDKehfwzd@qUBjDEq`{S%P_np|^=y&v2AO6I4rd|IDzQ%7YYJI1AU*zz; z9`t|q2h)FSdHTT0@q(9EF8|}#yXc3tfSj*!U$X9B7sUj7`^~yuw=Mo0u${-I4=fue z<@$7i{Lj8Eo1+*+3NoOZx( z3uy4R3ZJy93cEjRCvzrE{Eoou5Xa9Ie8!RVBAsdJQw?#tZooglp%YrUGKx#lKDwh! zdA|hyfpNO)1wS${S3qzbhVny+mpx9$v4IB%IP#+p%6kJEKiVz%e)g&V5E#h`OKe19;;8;q?~Ui|rEWA0qdLfo=$3;r^T#hSzIG zwZ=EBmRAgZBLe>Q4~o8#p%{=PVXjh?j|MdB8`jm#x=%+bj|>arR{^gA(5#n)@yBwe zAk?0B3h*WXa=qpZ)^mBy8o}c_jk|6W85_3ORPZ?!kbZB{R^QaT5upjqS-_hCcrN8S z>)C9d)X{kpL?2$YpsNP#-SIMepLPM;<7(BP?=?srt?N3ZzYuiiIrNv3p6_)9pN#SP zf@XpHWgdN?>sjPi{!c^R5E@<$!;JJ#L2m z{L&-rxW(z?O@Y01z2!#e-F#s9dG5cEp6kX~pK<3=nW{$oezaoWdNx46s{!wX9uHBD zqvzioJs*UgRfmQ3M1P!r@BUby|C#zm3b-Pn6?qi;-44k6r-7dOV_JcpHw!tXAzcmp zCjg&@{)XQAao~>y;RW9Hz+VgKSL-@3`)g`Jcp-Nq@HP-XrsF32TcjY|zc&Fd259uN z{oBxM|0=-7C))8f;B5hXXa9Y#+r7(nCEx-mT_-zHBe*)HBzuAtPC^qr? z%ctabWHdIyQSbrqw*i{{EUWiG*fTOZ+-{!&?_&qwZNKe}7dc;q~SpkiTbtUB60*|8{*%c*teOBRhXE?Yu$KEsOO%5&pe%Y<$V+jBx<*u}x>S zKjUK-%G-DTaXBsb>wKwh*=%b!|7vajNI^JGcjzoynD3*&9xZ71Z5Mt1spQii(+WoC zNjelHO}Z=SI|Gvbpw2oTZoB9r8|PVHKU?>I48LOGS1SJ!t|<8Qa`^QIKhnE=Gl%O6 zbOqwDyB>5T_#F=D<6PG_2zVL!y00_N`2g)e;P(d{3j4dy+a}Bxe5p=8^xfJRjzi{s zDQee$o@?8C2BvsJJ0mX9KBF<8O|XspEPx)z1D;HO0bM2J&U^AHJ5H2u(eETtKSIBB zjP*nMso|sXhw_W`P0G3(5?7)Ma*F{u4s*VKdgoHhw>A4rXM4sTv3k-D{=$Kw^JvuX zbVt8*d|!g|P--{>dQA*qeJ;xcrjIDGe(ZiWNh39iuvfc~tvhC0M89Up!by;V9UXS;Wrr)d*DO`UhzTqDlFM{tOJx07+l~B&k}-Ciqn^~`tIqWe!rJ&P#=*5ON;<9b zWIO(qOCs^=qKPk(=$F-n_le>D+qsL5x9m^UuLJTschPmfWO`J)U~vea0ss-P-p;D$%~lzIz?R{D$9W z<@Y-3@w^kyH4@L%1LIAOjqkMAsgN^op}vQa{!My6Hsv=`vEf+%9~mjIo^udt%XLiC zTvd|go||Wsq#e`oy<&GgZz}AP56E-&mD48ID&MADfm3EgYZBA7<^>6f=^;@`nSQxg z&+)Ons=DYn%ys4qyDYNxpdG5Z=yOL*U(_WShi(7ndMfqGpHmx>YaTZpB63+Cm4vzY zJQ@9odKi9ooKH6&eiFQbkav3CWw66cK=-|Ad_Il!GjdK7K8T z??&8cEbC5;!Sp)VZPVk!Z2zDh zPj=Dw^RT{L7c%y>;~4cLAAk4mZ$+C&;{Id%T?XRWNaq89Pead#0F!;!D(wIr2h4X8 ztzFn&jL+o-A6U86^EKGpU9aK(Jp1GNUE2Pvuir9kq3F-|{;)qhjQ&G^W?cC+iQTq2 zcH7Qz3U;HOgZe$QQG z%9U||!VT~bwp*KV8bK?~z@`}be?Q>22V^`l@2?5Pt0FvT%<>u0^L{NHnC{!ZZ~w$} zv}nMfP+Ah^@)!3WArQk+U?<6w%j~yz7f8N2XUwdVG~+4jlUAN*@4T#Y3j(eqP>=lq zxxd#7wYnAxTgC zOK_hQLB?#`3i4g-O*YODkKb=Twukzu@91s%ZODIHZQuNwbA&hTKJ|ZZ-;C!|}O z&)xy~$-ckG_aPf-$FWGUPKX$H?}nUZ)C1pBVw~mq)0L3J@4xckupq{z5 z=9KdY@a}6x&e|k$?gHIikmGN?+Qv1$@2(x}?B=&ee%6@2Me?(vOc%KE`CycK-Ujf0 z0nwJhh>xTy$k5qwhIIc0{(F1TK{0?fWAva?eqMm9Xd|E_$~yp>^?c$Di%T{8wJ7fb zXwFgCxJUdnv{Oh4!=M-NdjN7@$=JgVnc>}6&pQ}+Q9!dFKzmqxXPeYJ0(idyH0%7- z|HwrBb5MRXAlI*btV4IfI&5>J?pqA%s_QMpJE5!cW!m(UCldK{f5+_Cyd?Slay@TC zzAg8k@S@~%UuG-LvlMh){F&qzbxqU#8i%iWzRJd9@-=>E?ap=g`1uiij+XMM=Rhwb z)c@<2&4GTpFJ$_k<@eSBDu?wj_1hqNP3)SzTi~Rwy6?nZ;@1CE)Z_G4@IHB?&#S`E z&#t{g;M?!)wDE5t9A{q3DKW{v0%_JGx?t1UlAr8af&!!0=kjygwHo)xXIxjUr@2qI z_P7%K#FOS7sEg1b&WkKbl1W^?gxDP9o;wF zG*tKFF74WMgW%l{zU1F~NsFat{dr#EO7On|{Qn5LKLc`Ka1rpBPdu~kYyC6eyWm&W z|3nA5*p3fE-v_(a=h_1NGxfH1B7IBn-gABarU7!fzP}vlJDm1sn!Ks^iX`~1U)8;@ z`&G36_F*%Z3oo7nqklB;`DO@Wy$rw5j?JvDcupgUf4KXLCcgKh?gAf0{1^bpbNnB` zZ%qHP>p>HiY5(Fm*hTQ4b*Q(A+qU1W?^V4#M{R43R8R&;R2TOkc4eS!!|F#i+ru|k4oN*uYh|O9i=^d#5=Uw$V9{0IO z!7*3;x&t(Bv)t8(%?gz?7thD3767b{qPfWgzQ-5^w{a7bE-;eifl}7%Ivr9o2 zMVyVGg4ZD5kLkYAyp=E8ena_`H=ygYCkYALk91}pX#LsP$HKZFmfHG~e)V6_AD&Xa z)FYXG90y3>r`rowZoh82uXt29ZTEiNG*0*Jrt5GqH1P4rH~wS$BhSrJU&cSPzgjEx z*$KMiVE+Rg`nj+N^=3Qgc551=_UMH9069ypiBp&-8N1kd3H_P-Zsao(a@lW`I{u&e zuK#+$^RHpK8JPc$(Pj65(dcga^Bef__-=TPJm3?c+8@uL|7^Ki$Fo0m)A4V{EXE_1 z>!V-(8U2C&d#&TAO^Ys>pD1D5#n^|_ip@9k6%z{0m23Y8|LDKhIsVIe{S8U{m-0#X z1pOC&$b9-?)H#0yd(Yp#y5<2=DlLlMib0r_(m=>9zEZK3&h z6Uqm4&8T3W!07wob|4?(FkYXI@r!(;BUNAO!?^m-ZcTp`+W)|Ae2z5E7xAD}zfZ-; z`fv1$4QzL`FP|r&T`6yCFyGYkDby>{UB}yR!Ef$@@Ox%hFYm={5@cSI-&A5AdM~ovNykwO2Op|Zp64QL2 zJNXP^{hj&^W_t(irO*2`y`^7D84=LwJaG77saA3x^RspTJdn%%cI5x=v2SdXv47u& zdO>~f)+GJ=bf%s6QmpxyPT3+(LI^KQU6*{3_^|Bk;dpgzuX3DHl~uW2vV!(Xv<2Yn$C zn)^^IF}h9T3;jgB&+}-XR>g%XC>i5bjUQgZmHz+;&Y*VUa~dFb2wZVScvC%*k4!=)@y2uo`a`6zTc|@GPdD; zaBjYTs_LojV9rB94(}If*ISX#=RElwE$v1-C7d78b=}H*8$USj-;Q=$$@as!v`b+B z)Da~oi^|0R40xY7`167P1Lqgr^*k=mQMmhI`_VAYcg;E>pY!RI9y(v)I#mnfRrVQn zzL_y%Y>|)@IU8z`9?IxT>WTRv_2Ku*cC-JE(C-!L+bW@i0qwx24IrO)Wj}HGWQ;8@ z5Nf{PkDR)IzN5p3-`ysk7UJ9qC;?VlbeublLzpt8@W8=kGqli#cIEwTIT@LlYds)7Np{Pe%iEcbrK`y}{ z(3yQ=dzt;ub@Jo9!J0O9vn^@P=h$(V`SjBPk!S6`Gxvq}{%(NsIna3ypZmGoZ&fU_ z&j7jp;@9k*9MddM7C+b@+3$FMVh9L%KF*aFoNvN=;8-u#dwqA^@24K~3Z~d|WTZ3C zNBmYqxX)3a)r0e3eU3T`J^UV+f8#rie2%)B_&xN#lyQ%A@#m=3E|kyvMkD`15y5k5 zbJ2f)1AaW0b~?U)#`?JQT;;0=eQ7{Xz0@9zJC_5G_VTmevF%omxWsspR#KKH`q@q@ zKX6?EzdI3d3G8qe>||hnL7lfHESK+_YS}sFG%4qMq=-lP)YH5#-`YoTH902(| zMtdyyrHu!q6CQE}^6|ZCS8leVndhlT+40B*CFBWs0&*V+UY_dRD%k5{-{@&qMB-xcpqcXnaek>3 z1so?ggYG4Vo_YlI#ie%qDs$-H1l{WnJ?CoyeN~~2#Ehqu|8LN}>(Fyv8`Qs`P~$q* zt4RML=ss}h)1YS->t9l+<5Wp5N)&tny3a|E_eArY(BAY1hv>fn-7dgLPmN=3d+I(a zks0qe&SV65j1wC7s5j#R_1Ls?v-KyYJM?t@O7~5A^sIkeWFFR2=QSMv`#I?$PP))Z zm-ke?_&tzbla3i6d^v8-l7zXKHtuO%gXxMP(NKA>N&PKJc~6b!34D)9*D`|zQ6u4zQ+A+=po;ct=O02x|uiV{D}P^ zh$A`LA8k|-$$C}vRJaHJoYk{F7eyAdCm+U>9Idaz#+w8_69LJGaV6lxxRQj=RM4N{ z@L_xj_%OaC;WG>LXFGftXZB;gf;h8p`h#4CsDW zqx`VLUljt{XLuwyr}3HO^ZZ9vPkld$zgXuD=MR=r^BqkE-chL-PoC2GC(py(&=dQY z$R}MR&dAA#Khdis$=|0w8II`s6Pp#FjXCpC@NjnT>b$CfVR{{M-zE)&m+k%Yx@& zGf9sZ1Q${Ok9M`^4D7GhPuaqaKt3a-EbKGr5x#hZoSXx*x zJP|*om!`gUcwh26k! ze}^yiJvh*Jt)1tt?|ziE50=5a#_oDQ=r_-RA83tSKXAl)zky>vcTKYp{d{Ml$Sri_bKQ!5 z;`+UZ1|*(a&h}-y-U2<(LVaHB+0-QRry)JPm(DMnQLlrf&|G}Z2jqJu$J=3*ly|1T zn+G~2U6oUAryj+l@qFhvz0Z&`xz0vC#{zQv;`0TDKkmQuewoh~ToSay>(2?F01wZj zF|N;b^b7jWD1AP>Dp#oE*L>(P+p$061~G$nJ#RV)Acm?SHuooX47yNfN+dHKy z%nzuqAJgydOgK)t5fc9_;8Pay`Tb<#)c}v<7x5^E^e*IhOFmo|ARhTdztJ4x@%a(* zC!SZYc#B~N;`4bD7oY7;NPIq*;_Bf=HHUa#4%f8qGD^Hxdp01S^wfv?F`tm@{`}tb F{{sLEi$4GW diff --git a/v4/capsule/core.v4 b/v4/capsule/core.v4 index 0ac19c32..e5fcc2d0 100644 --- a/v4/capsule/core.v4 +++ b/v4/capsule/core.v4 @@ -182,7 +182,7 @@ header CMOVE \ messages in so as to be free to write, where it cannot begin a message \ of its own: so it notes what it owes, (OWE), in the eight pairs at \ (OWED) -- whom it is owed to, and the node the message was for -- and -\ sends it when it next has nothing else to do, (PAY). With eight owed +\ sends it when it next has nothing else to do, (PAY-SET). With eight owed \ already, one more is let go and counted. Nothing is owed for a NACK or \ for a GONE, type 5: there is no NACK for a NACK. The last 36 cells of \ the messages waiting are kept for those two types, so that ordinary @@ -303,13 +303,14 @@ header CMOVE 16 !b 0 !b 0 !b ; \ how many nodes may pass it on (the TTL: MESH.md 7b); ACL tag; sequence \ PAYING WHAT IS OWED (MESH.md 7c.3). Every refusal owed is offered at -\ once, each on the port it goes by, one to a port, and the node sleeps in -\ the wait: so one owed to a node that is stuck does not keep back one -\ owed to a node that waits for it, and the node takes in whatever is -\ written to it meanwhile. One there is no way for, or whose way is a +\ once, each on the port it goes by, one to a port, with whatever the node +\ has to pass on (quit.v4, (IDLE)), and the node sleeps in the wait: so +\ one owed to a node that is stuck does not keep back one owed to a node +\ that waits for it, and the node takes in whatever is written to it +\ meanwhile. One there is no way for, or whose way is a \ port with nothing on it, is let go and counted first. (PAY-K) has a \ cell for each port: which refusal is offered there, counted from 1; 0, -\ none. +\ none; -1, a message being passed on. \ ( k -- ) the k-th refusal owed is done with: the last takes its place : (PAID) @@ -327,30 +328,32 @@ header CMOVE \ ( k -- ) offer the k-th refusal owed on its port, if nothing is there yet : (PAY-OFFER) - dup 2* (OWED) + a! @ \ k to - dup (PORT-FOR) (PORT) - \ k to n the port, by its number + dup push 2* (OWED) + a! @ \ to R: k (the stack is kept shallow: this runs between lines) + dup (PORT-FOR) (PORT) - \ to n the port, by its number dup (PAY-K) + a! @ if FREE - drop drop drop drop ; + drop drop drop pop drop ; FREE: drop - dup push (OFFER) + a! ! \ k the message's first word, whom it is to - 1 + pop (PAY-K) + a! ! ; + dup push (OFFER) + a! ! \ the message's first word, whom it is to + pop pop 1 + SWAP (PAY-K) + a! ! ; -\ ( -- flag ) offer every refusal this node owes and wait once: if one -\ is taken its other words are written and it is done with. Zero if -\ nothing is owed, and then nothing was waited for. -: (PAY) +\ ( -- ) let go every refusal owed that cannot be sent; no port has an +\ offer; then offer each that is left on its port +: (PAY-SET) (OWED#) a! @ if NONE -1 + FOR pop dup push (PAY-DROP) NEXT - (OWED#) a! @ if NONE - (PAY-K) a! PORTS-1 FOR 0 !+ NEXT - -1 + FOR pop dup push (PAY-OFFER) NEXT - (OFFERS) if CAME - drop (GATE-PORT) a! @ (PORT) - (PAY-K) + a! @ -1 + \ k: the one that was taken + jump CLEAR + NONE: drop + CLEAR: (PAY-K) a! PORTS-1 FOR 0 !+ NEXT + (OWED#) a! @ if NONE2 + -1 + FOR pop dup push (PAY-OFFER) NEXT ; + NONE2: drop ; + +\ ( k -- ) the offer of the k-th refusal owed was taken, and B is at the +\ port: its other words are written, and it is done with +: (PAY-GO) dup 2* (OWED) + 1 + a! @ \ k about 4 (HDR) 4 !b !b \ from, type 4; four characters; about - (PAID) -1 ; - CAME: drop -1 ; - NONE: drop 0 ; + jump (PAID) \ ( -- ) send what has been printed, to where (PRINT-TO) says, by the port \ (PRINT-PORT): its length, then its characters, four to a word, the first diff --git a/v4/capsule/quit.v4 b/v4/capsule/quit.v4 index 039360f8..80b8abfb 100644 --- a/v4/capsule/quit.v4 +++ b/v4/capsule/quit.v4 @@ -54,12 +54,24 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro \ stops compiling first; it is always jumped to, never called, by \ something that has emptied the return stack (or by a fault, which empties \ it). (LINE-STATUS) keeps how the last text ended. +\ THE MESSAGE SAYING HOW IT ENDED is not written here: whoever sent the +\ text may be stuck, and this node would wait on it. It is put with the +\ messages waiting and passed on from (IDLE), as any message for another +\ node is. : (FINISH) ( s -- ) 1 (QUIET) a! ! \ from here an error is not this text's: see (RAISED) (LINE-STATUS) b! dup !b (FLUSH-OUT) - (MSG)+1 a! @ (DONE-PORT) a! @ (GATE) \ to whoever sent the text - 3 (HDR) 4 !b !b \ a message of type 3, four characters long: how it ended + 1 (MQ#) a! @ + -MQ-ROOM + -if FULL \ how it ended goes with the messages waiting, + drop \ to be passed on as any is: (IDLE) + (MSG)+1 a! @ (MQ!) (ME) a! @ (MQ!) 3 (MQ!) \ to whoever sent the text, from this node, type 3 + 0 (MQ!) 0 (MQ!) 0 (MQ!) 4 (MQ!) \ four characters long + 0 (DONE-PORT) a! @ - (MQ!) \ by the port that leads back, kept below zero: this node's own + (MQ!) \ how it ended + jump (IDLE) + FULL: drop \ no room at all: it is offered here, and the node waits + (MSG)+1 a! @ (DONE-PORT) a! @ (GATE) + 3 (HDR) 4 !b !b jump (IDLE) : (DONE) @@ -68,38 +80,144 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro OK: drop 1 jump (FINISH) GO: drop 0 jump (FINISH) -\ ( -- ) WAITING. A node with nothing to do deals with the oldest of the -\ messages waiting (core.v4). With none waiting it is blocked reading its -\ ports (docs/v4.0.0/MESH.md 4.1): it executes nothing until a neighbour -\ writes, and what arrives is taken in as any message is, its first word -\ from any port and the rest from the port that came on. The message's -\ text goes into TIB, which holds 1024 characters, the most a message -\ carries; one that came with a length no message has is error 12. A -\ message of type 1 for this node is text to interpret: it is done as a -\ line was, and (FINISH) reports how it ended. A message for another node -\ is passed on, (PASS-ON). +\ THE MESSAGES WAITING, GONE THROUGH. Three words below go through them +\ all, as (A-QUEUE) does further down: each in turn is taken from the +\ front, its eight cells into (MQ-HDR), and either used up or put at the +\ back, so that those that stay are in the order they were in. (A-LEFT) +\ is how many cells are still to be looked at, and (A-FOUND) what the pass +\ has found. + +\ ( -- n ) the next of them is in (MQ-HDR); n is how many words of text +\ it has, which are still at the front +: (MQ-NEXT) + (A-HDR) + (MQ-HDR)+6 a! @ -if SIZED drop 0 jump N + SIZED: 3 + 2/ 2/ + N: (A-LEFT) a! @ over 8 + - ! ; + +\ ( -- port | 0 ) the port the message in (MQ-HDR) goes by: for one this +\ node made itself, (FINISH), the port kept with it, below zero; for any +\ other, the way to the node it is for +: (FWD-PORT) + (MQ-HDR)+7 a! @ -if THEIRS 0 SWAP - ; + THEIRS: drop (MQ-HDR) a! @ jump (PORT-FOR) + +\ ( -- flag ) IS THERE ONE FOR THIS NODE? The first that is, is taken +\ out: its seven words into (MSG), the port it came on into (REPLY), its +\ text into TIB. +: (MINE?) + 0 (A-FOUND) a! ! + (MQ#) a! @ (A-LEFT) a! ! + L: (A-LEFT) a! @ if END drop + (MQ-NEXT) + (A-FOUND) a! @ if LOOK drop jump KEEP + LOOK: drop + (MQ-HDR) a! @ (ME) a! @ xor if MINE drop jump KEEP + MINE: drop 1 (A-FOUND) a! ! + (MQ-HDR) a! @ (MSG) a! ! (MQ-HDR)+1 a! @ (MSG)+1 a! ! (MQ-HDR)+2 a! @ (MSG)+2 a! ! + (MQ-HDR)+3 a! @ (MSG)+3 a! ! (MQ-HDR)+4 a! @ (MSG)+4 a! ! (MQ-HDR)+5 a! @ (MSG)+5 a! ! + (MQ-HDR)+6 a! @ (MSG)+6 a! ! (MQ-HDR)+7 a! @ (REPLY) a! ! + TIB 2/ 2/ SWAP if EMPTY + -1 + FOR (MQ@) over a! ! 1 + NEXT + drop jump L + EMPTY: drop drop jump L + KEEP: (A-BACK) (A-TEXT) jump L + END: drop (A-FOUND) a! @ ; + +\ ( -- flag ) WHAT IS TO BE PASSED ON IS OFFERED (MESH.md 7c.3): for each +\ message, the first for its port, its first word is offered there, unless +\ a refusal owed is offered there already; (PAY-K) is set to -1 for that +\ port. It stays with the messages waiting until the offer is taken. +\ One that cannot go at all is let go, counted in (LOST), and whoever +\ waits on it is told (core.v4, (TELL-OF)): one with no way known; one +\ whose way is a port with nothing on it; and one that fifteen nodes have +\ passed on already. The flag is not zero if any was let go. +\ A MESSAGE IS PASSED ON BY AT MOST 16 NODES. Its fourth word says how +\ many more may; 0, as a device sends it, is taken for 16. +: (FWD-SET) + 0 (A-FOUND) a! ! + (MQ#) a! @ (A-LEFT) a! ! + L: (A-LEFT) a! @ if END drop + (MQ-NEXT) (A-WORD) a! ! \ its words of text, kept off the stack: this runs between lines + (MQ-HDR)+3 a! @ if FRESH jump COUNT + FRESH: drop 16 + COUNT: -1 + if REFUSE drop + (FWD-PORT) if REFUSE \ ( port ) + dup (THERE) if REFUSE2 drop + (PORT) - dup (PAY-K) + a! @ if FREE \ ( p slot ) p: the port, by its number + drop drop jump KEEP + FREE: drop dup push (MQ-HDR) a! @ SWAP (OFFER) + a! ! \ whom it is to, offered + -1 pop (PAY-K) + a! ! + KEEP: (A-BACK) (A-WORD) a! @ (A-TEXT) jump L + REFUSE2: drop + REFUSE: drop + (A-WORD) a! @ if NOTEXT -1 + FOR (MQ@) drop NEXT jump TOLD + NOTEXT: drop + TOLD: (LOST) a! @ 1 + ! 1 (A-FOUND) a! ! + (MQ-HDR)+1 a! @ (MQ-HDR) a! @ (MQ-HDR)+2 a! @ (TELL-OF) jump L + END: drop (A-FOUND) a! @ ; + +\ ( -- ) THE OFFER OF ONE WAS TAKEN, on the port (GATE-PORT) holds: the +\ first of the messages waiting that goes by that port is the one. Its +\ other words are written, each waiting for the neighbour, which has its +\ first and reads to the end; and it is done with. +: (FWD-GO) + 0 (A-FOUND) a! ! + (MQ#) a! @ (A-LEFT) a! ! + L: (A-LEFT) a! @ if END drop + (MQ-NEXT) + (A-FOUND) a! @ if LOOK drop jump KEEP + LOOK: drop + (FWD-PORT) (GATE-PORT) a! @ xor if THIS drop jump KEEP + THIS: drop 1 (A-FOUND) a! ! + (GATE-PORT) a! @ b! + (MQ-HDR)+1 a! @ !b (MQ-HDR)+2 a! @ !b + (MQ-HDR)+3 a! @ if FRESH jump COUNT + FRESH: drop 16 + COUNT: -1 + !b \ one fewer may pass it on + (MQ-HDR)+4 a! @ !b (MQ-HDR)+5 a! @ !b (MQ-HDR)+6 a! @ !b + if NOTEXT -1 + FOR (MQ@) !b NEXT jump L + NOTEXT: drop jump L + KEEP: (A-BACK) (A-TEXT) jump L + END: drop ; + +\ ( -- ) WAITING. A node with nothing to do looks through the messages +\ waiting (core.v4). +\ ONE FOR THIS NODE is dealt with, the oldest first: (MINE?). A message +\ of type 1 is text to interpret: it is done as a line was, and (FINISH) +\ reports how it ended; one that came with a length no message has is +\ error 12. A NACK is counted and a GONE from the node's centre believed. +\ WITH NONE FOR IT, what it has for other nodes, and the refusals it owes, +\ are offered, each on the port it goes by, and the node sleeps in the +\ wait (MESH.md 7c): until one is taken, and then the rest of that one is +\ written; or until a word comes for it, and then that message is taken in +\ and it looks again. A node that is stuck never takes what is offered +\ it, and holds up nothing else. +\ WITH NOTHING WAITING AND NOTHING OWED it is blocked reading its ports +\ (docs/v4.0.0/MESH.md 4.1): it executes nothing until a neighbour writes, +\ and what arrives is taken in as any message is. : (IDLE) L: 1 (QUIET) a! ! \ nothing here is any text's doing: see (RAISED) - (MQ#) a! @ if WAIT drop jump HAVE - WAIT: drop (PAY) if BLOCK drop jump L \ what it owes is offered, and it sleeps (core.v4) + (MINE?) if OTHERS drop jump HAVE + OTHERS: drop + (MQ#) a! @ (OWED#) a! @ + if BLOCK drop + (PAY-SET) (FWD-SET) if SET drop jump L \ one was let go: what is owed has changed + SET: drop + (MQ#) a! @ (OWED#) a! @ + if BLOCK drop + (OFFERS) if CAME drop + (GATE-PORT) a! @ (PORT) - (PAY-K) + a! @ \ what was offered on the port it was taken on + -if OWED drop (FWD-GO) jump L + OWED: -1 + (PAY-GO) jump L + CAME: drop jump L BLOCK: drop (PORT)+8 b! @b (PORT)+9 b! @b (PORT) + dup b! \ ( to port ) B: the port it came on SWAP (TAKE) jump L HAVE: - (MQ@) (MSG) a! ! (MQ@) (MSG)+1 a! ! (MQ@) (MSG)+2 a! ! (MQ@) (MSG)+3 a! ! - (MQ@) (MSG)+4 a! ! (MQ@) (MSG)+5 a! ! (MQ@) (MSG)+6 a! ! (MQ@) (REPLY) a! ! (MSG)+6 a! @ -if SIZED drop 0 (MSG)+6 a! ! 0 SPAN a! ! NODE-ERROR b! 12 !b \ no telling what it was SIZED: drop - TIB 2/ 2/ (MSG)+6 a! @ 3 + 2/ 2/ if EMPTY - -1 + FOR (MQ@) over a! ! 1 + NEXT - drop jump READ - EMPTY: drop drop - READ: 0 (MSG)+6 a! @ TIB + C! \ a zero after the text (MSG)+6 a! @ SPAN a! ! - (MSG) a! @ (ME) a! @ xor if MINE drop jump (PASS-ON) - MINE: drop - (MSG)+2 a! @ -1 + if TEXT \ for this node, and + (MSG)+2 a! @ -1 + if TEXT -3 + if NACK -1 + if GONE drop jump (IDLE) \ neither text nor these: let go NACK: drop (REFUSED) a! @ 1 + ! jump (IDLE) \ a message of this node's was refused: counted GONE: drop (MSG)+6 a! @ -4 + if G4 drop jump (IDLE) \ a node is gone, if its centre says so: @@ -118,25 +236,6 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro Q1: (PRINT-PORT) a! ! jump (LINE) -\ ( -- ) A MESSAGE FOR ANOTHER NODE is passed on (MESH.md section 7): all -\ of it, as it came, to the port that leads toward that node. With no way -\ known it is let go, and (LOST) counts it. -: (PASS-ON) - (MSG)+3 a! @ if FRESH jump COUNT \ how many more nodes may pass it on; - FRESH: drop 16 \ from a device, which set none: sixteen - COUNT: -1 + if SPENT (MSG)+3 a! ! - (MSG) a! @ (PORT-FOR) if NOWAY - dup (THERE) if NOONE drop - (MSG) a! @ SWAP (GATE) (MSG)+1 a! 5 FOR @+ !b UNEXT \ its seven words - (MSG)+6 a! @ 3 + 2/ 2/ if SENT - -1 + TIB 2/ 2/ a! FOR @+ !b UNEXT \ and its text - jump (IDLE) - SENT: drop jump (IDLE) - NOONE: drop \ its way is a port with nothing on it - SPENT: \ it has been passed on as often as it may be - NOWAY: drop (LOST) a! @ 1 + ! - (MSG)+1 a! @ (MSG) a! @ (MSG)+2 a! @ (TELL-OF) jump (IDLE) \ whoever waits on it is told (core.v4) - \ ( -- ) THE TEXT, INTERPRETED. It is in TIB with a zero after it and its \ length in SPAN, and the return stack is empty. It is interpreted with one \ return entry under it, this word's call of INTERPRET; whatever is on the diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c index 7a86554c..4da5ff66 100644 --- a/v4/tests/test_host_mesh.c +++ b/v4/tests/test_host_mesh.c @@ -398,6 +398,13 @@ int main(void) CHECK(is_empty(tell(10, "66 NO-ROUTE")) && waiting(hera) && waiting(mid) && waiting(far), "the way is forgotten, and all three are at rest"); } + /* ---- what a node passes on keeps its order, however long it must be kept (MESH.md 7c) ---- */ + CHECK(is_empty(tell(11, "12 2 ROUTE")), "node 11 is told the way to node 12 is by node 10"); + CHECK(is_empty(tell(12, ": SLOW 30000 0 DO LOOP ;")), "node 12 is given a word that takes a while"); + CHECK(strcmp(tell(11, ": TRIO S\" SLOW 68 EMIT\" 12 SEND S\" 69 EMIT\" 12 SEND S\" 70 EMIT\" 12 SEND ; TRIO"), "DEF") == 0, + "it sends node 12 three texts, the first slow to do: node 10 keeps the other two until node 12 reads again, and they are done in order: \"%s\"", printed); + CHECK(is_empty(tell(11, "12 3 ROUTE")) && waiting(hera) && waiting(mid) && waiting(far) && pool[0].n.mem[MQ_COUNT] == 0, "the way is told again; all three are at rest, keeping nothing"); + /* ---- a node that is stuck holds up no one (MESH.md 7c) ------------------- */ v4_fabric_gone_error(&f, V4_ERROR_NO_ONE); @@ -406,7 +413,7 @@ int main(void) /* a refusal owed to a stuck node whose number is the lower */ CHECK(is_empty(said(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(said(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12"); - CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message and is then stuck in a loop"); + CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND S\" 1 DROP\" 12 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message, and node 12 text, and is then stuck in a loop"); CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 12 owes node 11 a refusal, and cannot give it: node 11 is not reading"); CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed); { @@ -423,6 +430,18 @@ int main(void) "node 10 sends 77 a message and waits: node 12, which still owes the stuck node, tells node 10 it was refused: \"%s\"", printed); CHECK(is_empty(said(10, "77 NO-ROUTE")), "the way is forgotten"); + /* a message passed on toward the stuck node waits with the node passing it on, which goes on serving */ + { + v4_cell kept = pool[0].n.mem[MQ_COUNT]; + CHECK(is_empty(said(11, "1 DROP")) && ended == 0 && pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n), + "text from the console for the stuck node comes to node 10, which cannot hand it on: it keeps it, offered, and sleeps"); + CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, + "node 10 goes on doing what it is sent, and passing on what is for others: \"%s\"", printed); + CHECK(pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n), "still keeping what is for the stuck node"); + } + /* the stuck node's own answer: node 12 did text node 11 sent before it stuck, and cannot give it the answer */ + CHECK(pool[2].n.mem[MQ_COUNT] > 0 && v4_node_in_wait(&pool[2].n), "node 12 keeps the answer it has for node 11, offered, and sleeps"); + /* a line that must begin a message to the stuck node waits, and the node takes in what comes */ CHECK(is_empty(said(10, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n) && !pool[0].n.asking, "node 10 sends the stuck node a message: its line waits in the wait, not blocked writing"); @@ -447,8 +466,8 @@ int main(void) CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL && ended == 1, "the line ends in an error that says no one is there: \"%s\"", printed); } step_cap = 20000000; - CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera), - "node 12 goes on, the refusal it owed node 11 let go: it owes nothing and is at rest"); + CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && pool[2].n.mem[MQ_COUNT] == 0 && pool[0].n.mem[MQ_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera), + "node 12 goes on; what it owed node 11 and kept for it, and what node 10 kept for it, are let go: they owe and keep nothing, and are at rest"); /* a refusal owed to a stuck node whose number is the higher */ step_cap = 3000000; diff --git a/v4/tests/test_host_quit.c b/v4/tests/test_host_quit.c index b9a5e1a2..e5ff6d8d 100644 --- a/v4/tests/test_host_quit.c +++ b/v4/tests/test_host_quit.c @@ -63,7 +63,7 @@ static v4_heat h; static v4_text tx; static v4_cell w_key, w_key_end, w_fault, capsule_latest; static v4_cell w_idle; /* (IDLE): where the node waits for a message */ -static v4_cell w_idle_end; /* (PASS-ON): the word after it */ +static v4_cell w_idle_end; /* (LINE): the word after it */ static char out[V4_CONSOLE_CAP + 1]; /* STORAGE (MESH.md section 8). The node asks its kernel for its blocks, and @@ -871,7 +871,7 @@ int main(void) printf(" capsule: %ld words\n", (long)v4_text_here(&tx) - 16); if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; } w_idle = v4_text_word(&tx, "(IDLE)"); - w_idle_end = v4_text_word(&tx, "(PASS-ON)"); /* the word after (IDLE) in quit.v4 */ + w_idle_end = v4_text_word(&tx, "(LINE)"); /* the word after (IDLE) in quit.v4 */ w_key = v4_text_word(&tx, "KEY"); w_key_end = v4_text_word(&tx, "CR"); /* the word after KEY in core.v4 */ w_fault = v4_text_word(&tx, "(FAULTS)"); diff --git a/v4/tests/test_host_unit.c b/v4/tests/test_host_unit.c index f988783f..ff5e38a1 100644 --- a/v4/tests/test_host_unit.c +++ b/v4/tests/test_host_unit.c @@ -530,7 +530,16 @@ int main(void) CHECK(strcmp(tell(13, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 13 is stuck in a loop"); CHECK(strcmp(tell(12, ": W13 13 AWAIT . ; W13"), "(still running)") == 0 && node_numbered(12)->mem[AWAIT_FROM] == 13 && waiting(12), "node 12, which is not wired to it, waits for its answer"); + /* while it is stuck it holds up no one (MESH.md 7c): text for it waits with Hera, who goes on */ + (void)tell(13, "1 DROP"); + CHECK(ended == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking && node_numbered(10)->mem[MQ_COUNT] > 0, + "text typed for the stuck node waits with Hera, offered: she sleeps in the wait, not blocked writing"); + (void)tell(11, "11 100 * ."); + CHECK(strcmp(printed, "1100 ") == 0 && ended == 1, "text typed for another node is passed on and done meanwhile: \"%s\"", printed); + (void)tell(10, "1 2 + ."); + CHECK(strcmp(printed, "3 ") == 0 && ended == 1, "and so is text for Hera herself: \"%s\"", printed); (void)tell(10, "13 KILL"); + CHECK(node_numbered(10)->mem[MQ_COUNT] == 0, "killing it, she lets go what she kept for it"); CHECK(node_numbered(13) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(12)->mem[AWAIT_FROM] == 0 && waiting(12), "Hera kills node 13: node 12's wait ends, with an error that says the node is gone: \"%s\"", printed); step_limit = 30000000ul;