PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/golang/1.22.0/src/sync/atomic
Viewing File: /opt/golang/1.22.0/src/sync/atomic/atomic_test.go
// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package atomic_test import ( "fmt" "reflect" "runtime" "runtime/debug" "strings" . "sync/atomic" "testing" "unsafe" ) // Tests of correct behavior, without contention. // (Does the function work as advertised?) // // Test that the Add functions add correctly. // Test that the CompareAndSwap functions actually // do the comparison and the swap correctly. // // The loop over power-of-two values is meant to // ensure that the operations apply to the full word size. // The struct fields x.before and x.after check that the // operations do not extend past the full word size. const ( magic32 = 0xdedbeef magic64 = 0xdeddeadbeefbeef ) func TestSwapInt32(t *testing.T) { var x struct { before int32 i int32 after int32 } x.before = magic32 x.after = magic32 var j int32 for delta := int32(1); delta+delta > delta; delta += delta { k := SwapInt32(&x.i, delta) if x.i != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } j = delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestSwapInt32Method(t *testing.T) { var x struct { before int32 i Int32 after int32 } x.before = magic32 x.after = magic32 var j int32 for delta := int32(1); delta+delta > delta; delta += delta { k := x.i.Swap(delta) if x.i.Load() != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } j = delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestSwapUint32(t *testing.T) { var x struct { before uint32 i uint32 after uint32 } x.before = magic32 x.after = magic32 var j uint32 for delta := uint32(1); delta+delta > delta; delta += delta { k := SwapUint32(&x.i, delta) if x.i != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } j = delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestSwapUint32Method(t *testing.T) { var x struct { before uint32 i Uint32 after uint32 } x.before = magic32 x.after = magic32 var j uint32 for delta := uint32(1); delta+delta > delta; delta += delta { k := x.i.Swap(delta) if x.i.Load() != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } j = delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestSwapInt64(t *testing.T) { var x struct { before int64 i int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 var j int64 for delta := int64(1); delta+delta > delta; delta += delta { k := SwapInt64(&x.i, delta) if x.i != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } j = delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestSwapInt64Method(t *testing.T) { var x struct { before int64 i Int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 var j int64 for delta := int64(1); delta+delta > delta; delta += delta { k := x.i.Swap(delta) if x.i.Load() != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } j = delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestSwapUint64(t *testing.T) { var x struct { before uint64 i uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 var j uint64 for delta := uint64(1); delta+delta > delta; delta += delta { k := SwapUint64(&x.i, delta) if x.i != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } j = delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestSwapUint64Method(t *testing.T) { var x struct { before uint64 i Uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 var j uint64 for delta := uint64(1); delta+delta > delta; delta += delta { k := x.i.Swap(delta) if x.i.Load() != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } j = delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestSwapUintptr(t *testing.T) { var x struct { before uintptr i uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr var j uintptr for delta := uintptr(1); delta+delta > delta; delta += delta { k := SwapUintptr(&x.i, delta) if x.i != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } j = delta } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestSwapUintptrMethod(t *testing.T) { var x struct { before uintptr i Uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr var j uintptr for delta := uintptr(1); delta+delta > delta; delta += delta { k := x.i.Swap(delta) if x.i.Load() != delta || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } j = delta } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } var global [1024]byte func testPointers() []unsafe.Pointer { var pointers []unsafe.Pointer // globals for i := 0; i < 10; i++ { pointers = append(pointers, unsafe.Pointer(&global[1<<i-1])) } // heap pointers = append(pointers, unsafe.Pointer(new(byte))) // nil pointers = append(pointers, nil) return pointers } func TestSwapPointer(t *testing.T) { var x struct { before uintptr i unsafe.Pointer after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr var j unsafe.Pointer for _, p := range testPointers() { k := SwapPointer(&x.i, p) if x.i != p || k != j { t.Fatalf("p=%p i=%p j=%p k=%p", p, x.i, j, k) } j = p } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestSwapPointerMethod(t *testing.T) { var x struct { before uintptr i Pointer[byte] after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr var j *byte for _, p := range testPointers() { p := (*byte)(p) k := x.i.Swap(p) if x.i.Load() != p || k != j { t.Fatalf("p=%p i=%p j=%p k=%p", p, x.i.Load(), j, k) } j = p } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestAddInt32(t *testing.T) { var x struct { before int32 i int32 after int32 } x.before = magic32 x.after = magic32 var j int32 for delta := int32(1); delta+delta > delta; delta += delta { k := AddInt32(&x.i, delta) j += delta if x.i != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestAddInt32Method(t *testing.T) { var x struct { before int32 i Int32 after int32 } x.before = magic32 x.after = magic32 var j int32 for delta := int32(1); delta+delta > delta; delta += delta { k := x.i.Add(delta) j += delta if x.i.Load() != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestAddUint32(t *testing.T) { var x struct { before uint32 i uint32 after uint32 } x.before = magic32 x.after = magic32 var j uint32 for delta := uint32(1); delta+delta > delta; delta += delta { k := AddUint32(&x.i, delta) j += delta if x.i != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestAddUint32Method(t *testing.T) { var x struct { before uint32 i Uint32 after uint32 } x.before = magic32 x.after = magic32 var j uint32 for delta := uint32(1); delta+delta > delta; delta += delta { k := x.i.Add(delta) j += delta if x.i.Load() != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestAddInt64(t *testing.T) { var x struct { before int64 i int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 var j int64 for delta := int64(1); delta+delta > delta; delta += delta { k := AddInt64(&x.i, delta) j += delta if x.i != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestAddInt64Method(t *testing.T) { var x struct { before int64 i Int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 var j int64 for delta := int64(1); delta+delta > delta; delta += delta { k := x.i.Add(delta) j += delta if x.i.Load() != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestAddUint64(t *testing.T) { var x struct { before uint64 i uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 var j uint64 for delta := uint64(1); delta+delta > delta; delta += delta { k := AddUint64(&x.i, delta) j += delta if x.i != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestAddUint64Method(t *testing.T) { var x struct { before uint64 i Uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 var j uint64 for delta := uint64(1); delta+delta > delta; delta += delta { k := x.i.Add(delta) j += delta if x.i.Load() != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestAddUintptr(t *testing.T) { var x struct { before uintptr i uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr var j uintptr for delta := uintptr(1); delta+delta > delta; delta += delta { k := AddUintptr(&x.i, delta) j += delta if x.i != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestAddUintptrMethod(t *testing.T) { var x struct { before uintptr i Uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr var j uintptr for delta := uintptr(1); delta+delta > delta; delta += delta { k := x.i.Add(delta) j += delta if x.i.Load() != j || k != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestCompareAndSwapInt32(t *testing.T) { var x struct { before int32 i int32 after int32 } x.before = magic32 x.after = magic32 for val := int32(1); val+val > val; val += val { x.i = val if !CompareAndSwapInt32(&x.i, val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } x.i = val + 1 if CompareAndSwapInt32(&x.i, val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestCompareAndSwapInt32Method(t *testing.T) { var x struct { before int32 i Int32 after int32 } x.before = magic32 x.after = magic32 for val := int32(1); val+val > val; val += val { x.i.Store(val) if !x.i.CompareAndSwap(val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } x.i.Store(val + 1) if x.i.CompareAndSwap(val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestCompareAndSwapUint32(t *testing.T) { var x struct { before uint32 i uint32 after uint32 } x.before = magic32 x.after = magic32 for val := uint32(1); val+val > val; val += val { x.i = val if !CompareAndSwapUint32(&x.i, val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } x.i = val + 1 if CompareAndSwapUint32(&x.i, val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestCompareAndSwapUint32Method(t *testing.T) { var x struct { before uint32 i Uint32 after uint32 } x.before = magic32 x.after = magic32 for val := uint32(1); val+val > val; val += val { x.i.Store(val) if !x.i.CompareAndSwap(val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } x.i.Store(val + 1) if x.i.CompareAndSwap(val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestCompareAndSwapInt64(t *testing.T) { var x struct { before int64 i int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 for val := int64(1); val+val > val; val += val { x.i = val if !CompareAndSwapInt64(&x.i, val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } x.i = val + 1 if CompareAndSwapInt64(&x.i, val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestCompareAndSwapInt64Method(t *testing.T) { var x struct { before int64 i Int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 for val := int64(1); val+val > val; val += val { x.i.Store(val) if !x.i.CompareAndSwap(val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } x.i.Store(val + 1) if x.i.CompareAndSwap(val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func testCompareAndSwapUint64(t *testing.T, cas func(*uint64, uint64, uint64) bool) { var x struct { before uint64 i uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 for val := uint64(1); val+val > val; val += val { x.i = val if !cas(&x.i, val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } x.i = val + 1 if cas(&x.i, val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestCompareAndSwapUint64(t *testing.T) { testCompareAndSwapUint64(t, CompareAndSwapUint64) } func TestCompareAndSwapUint64Method(t *testing.T) { var x struct { before uint64 i Uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 for val := uint64(1); val+val > val; val += val { x.i.Store(val) if !x.i.CompareAndSwap(val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } x.i.Store(val + 1) if x.i.CompareAndSwap(val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestCompareAndSwapUintptr(t *testing.T) { var x struct { before uintptr i uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for val := uintptr(1); val+val > val; val += val { x.i = val if !CompareAndSwapUintptr(&x.i, val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } x.i = val + 1 if CompareAndSwapUintptr(&x.i, val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestCompareAndSwapUintptrMethod(t *testing.T) { var x struct { before uintptr i Uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for val := uintptr(1); val+val > val; val += val { x.i.Store(val) if !x.i.CompareAndSwap(val, val+1) { t.Fatalf("should have swapped %#x %#x", val, val+1) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } x.i.Store(val + 1) if x.i.CompareAndSwap(val, val+2) { t.Fatalf("should not have swapped %#x %#x", val, val+2) } if x.i.Load() != val+1 { t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uintptr(magicptr), uintptr(magicptr)) } } func TestCompareAndSwapPointer(t *testing.T) { var x struct { before uintptr i unsafe.Pointer after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr q := unsafe.Pointer(new(byte)) for _, p := range testPointers() { x.i = p if !CompareAndSwapPointer(&x.i, p, q) { t.Fatalf("should have swapped %p %p", p, q) } if x.i != q { t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) } if CompareAndSwapPointer(&x.i, p, nil) { t.Fatalf("should not have swapped %p nil", p) } if x.i != q { t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestCompareAndSwapPointerMethod(t *testing.T) { var x struct { before uintptr i Pointer[byte] after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr q := new(byte) for _, p := range testPointers() { p := (*byte)(p) x.i.Store(p) if !x.i.CompareAndSwap(p, q) { t.Fatalf("should have swapped %p %p", p, q) } if x.i.Load() != q { t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i.Load(), q) } if x.i.CompareAndSwap(p, nil) { t.Fatalf("should not have swapped %p nil", p) } if x.i.Load() != q { t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i.Load(), q) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestLoadInt32(t *testing.T) { var x struct { before int32 i int32 after int32 } x.before = magic32 x.after = magic32 for delta := int32(1); delta+delta > delta; delta += delta { k := LoadInt32(&x.i) if k != x.i { t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) } x.i += delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestLoadInt32Method(t *testing.T) { var x struct { before int32 i Int32 after int32 } x.before = magic32 x.after = magic32 want := int32(0) for delta := int32(1); delta+delta > delta; delta += delta { k := x.i.Load() if k != want { t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) } x.i.Store(k + delta) want = k + delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestLoadUint32(t *testing.T) { var x struct { before uint32 i uint32 after uint32 } x.before = magic32 x.after = magic32 for delta := uint32(1); delta+delta > delta; delta += delta { k := LoadUint32(&x.i) if k != x.i { t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) } x.i += delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestLoadUint32Method(t *testing.T) { var x struct { before uint32 i Uint32 after uint32 } x.before = magic32 x.after = magic32 want := uint32(0) for delta := uint32(1); delta+delta > delta; delta += delta { k := x.i.Load() if k != want { t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) } x.i.Store(k + delta) want = k + delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestLoadInt64(t *testing.T) { var x struct { before int64 i int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 for delta := int64(1); delta+delta > delta; delta += delta { k := LoadInt64(&x.i) if k != x.i { t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) } x.i += delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestLoadInt64Method(t *testing.T) { var x struct { before int64 i Int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 want := int64(0) for delta := int64(1); delta+delta > delta; delta += delta { k := x.i.Load() if k != want { t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) } x.i.Store(k + delta) want = k + delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestLoadUint64(t *testing.T) { var x struct { before uint64 i uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 for delta := uint64(1); delta+delta > delta; delta += delta { k := LoadUint64(&x.i) if k != x.i { t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) } x.i += delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestLoadUint64Method(t *testing.T) { var x struct { before uint64 i Uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 want := uint64(0) for delta := uint64(1); delta+delta > delta; delta += delta { k := x.i.Load() if k != want { t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) } x.i.Store(k + delta) want = k + delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestLoadUintptr(t *testing.T) { var x struct { before uintptr i uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for delta := uintptr(1); delta+delta > delta; delta += delta { k := LoadUintptr(&x.i) if k != x.i { t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) } x.i += delta } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestLoadUintptrMethod(t *testing.T) { var x struct { before uintptr i Uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr want := uintptr(0) for delta := uintptr(1); delta+delta > delta; delta += delta { k := x.i.Load() if k != want { t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) } x.i.Store(k + delta) want = k + delta } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestLoadPointer(t *testing.T) { var x struct { before uintptr i unsafe.Pointer after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for _, p := range testPointers() { x.i = p k := LoadPointer(&x.i) if k != p { t.Fatalf("p=%x k=%x", p, k) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestLoadPointerMethod(t *testing.T) { var x struct { before uintptr i Pointer[byte] after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for _, p := range testPointers() { p := (*byte)(p) x.i.Store(p) k := x.i.Load() if k != p { t.Fatalf("p=%x k=%x", p, k) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestStoreInt32(t *testing.T) { var x struct { before int32 i int32 after int32 } x.before = magic32 x.after = magic32 v := int32(0) for delta := int32(1); delta+delta > delta; delta += delta { StoreInt32(&x.i, v) if x.i != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) } v += delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestStoreInt32Method(t *testing.T) { var x struct { before int32 i Int32 after int32 } x.before = magic32 x.after = magic32 v := int32(0) for delta := int32(1); delta+delta > delta; delta += delta { x.i.Store(v) if x.i.Load() != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) } v += delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestStoreUint32(t *testing.T) { var x struct { before uint32 i uint32 after uint32 } x.before = magic32 x.after = magic32 v := uint32(0) for delta := uint32(1); delta+delta > delta; delta += delta { StoreUint32(&x.i, v) if x.i != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) } v += delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestStoreUint32Method(t *testing.T) { var x struct { before uint32 i Uint32 after uint32 } x.before = magic32 x.after = magic32 v := uint32(0) for delta := uint32(1); delta+delta > delta; delta += delta { x.i.Store(v) if x.i.Load() != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) } v += delta } if x.before != magic32 || x.after != magic32 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) } } func TestStoreInt64(t *testing.T) { var x struct { before int64 i int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 v := int64(0) for delta := int64(1); delta+delta > delta; delta += delta { StoreInt64(&x.i, v) if x.i != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) } v += delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestStoreInt64Method(t *testing.T) { var x struct { before int64 i Int64 after int64 } magic64 := int64(magic64) x.before = magic64 x.after = magic64 v := int64(0) for delta := int64(1); delta+delta > delta; delta += delta { x.i.Store(v) if x.i.Load() != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) } v += delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestStoreUint64(t *testing.T) { var x struct { before uint64 i uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 v := uint64(0) for delta := uint64(1); delta+delta > delta; delta += delta { StoreUint64(&x.i, v) if x.i != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) } v += delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestStoreUint64Method(t *testing.T) { var x struct { before uint64 i Uint64 after uint64 } magic64 := uint64(magic64) x.before = magic64 x.after = magic64 v := uint64(0) for delta := uint64(1); delta+delta > delta; delta += delta { x.i.Store(v) if x.i.Load() != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) } v += delta } if x.before != magic64 || x.after != magic64 { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) } } func TestStoreUintptr(t *testing.T) { var x struct { before uintptr i uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr v := uintptr(0) for delta := uintptr(1); delta+delta > delta; delta += delta { StoreUintptr(&x.i, v) if x.i != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) } v += delta } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestStoreUintptrMethod(t *testing.T) { var x struct { before uintptr i Uintptr after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr v := uintptr(0) for delta := uintptr(1); delta+delta > delta; delta += delta { x.i.Store(v) if x.i.Load() != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) } v += delta } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestStorePointer(t *testing.T) { var x struct { before uintptr i unsafe.Pointer after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for _, p := range testPointers() { StorePointer(&x.i, p) if x.i != p { t.Fatalf("x.i=%p p=%p", x.i, p) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } func TestStorePointerMethod(t *testing.T) { var x struct { before uintptr i Pointer[byte] after uintptr } var m uint64 = magic64 magicptr := uintptr(m) x.before = magicptr x.after = magicptr for _, p := range testPointers() { p := (*byte)(p) x.i.Store(p) if x.i.Load() != p { t.Fatalf("x.i=%p p=%p", x.i.Load(), p) } } if x.before != magicptr || x.after != magicptr { t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) } } // Tests of correct behavior, with contention. // (Is the function atomic?) // // For each function, we write a "hammer" function that repeatedly // uses the atomic operation to add 1 to a value. After running // multiple hammers in parallel, check that we end with the correct // total. // Swap can't add 1, so it uses a different scheme. // The functions repeatedly generate a pseudo-random number such that // low bits are equal to high bits, swap, check that the old value // has low and high bits equal. var hammer32 = map[string]func(*uint32, int){ "SwapInt32": hammerSwapInt32, "SwapUint32": hammerSwapUint32, "SwapUintptr": hammerSwapUintptr32, "AddInt32": hammerAddInt32, "AddUint32": hammerAddUint32, "AddUintptr": hammerAddUintptr32, "CompareAndSwapInt32": hammerCompareAndSwapInt32, "CompareAndSwapUint32": hammerCompareAndSwapUint32, "CompareAndSwapUintptr": hammerCompareAndSwapUintptr32, "SwapInt32Method": hammerSwapInt32Method, "SwapUint32Method": hammerSwapUint32Method, "SwapUintptrMethod": hammerSwapUintptr32Method, "AddInt32Method": hammerAddInt32Method, "AddUint32Method": hammerAddUint32Method, "AddUintptrMethod": hammerAddUintptr32Method, "CompareAndSwapInt32Method": hammerCompareAndSwapInt32Method, "CompareAndSwapUint32Method": hammerCompareAndSwapUint32Method, "CompareAndSwapUintptrMethod": hammerCompareAndSwapUintptr32Method, } func init() { var v uint64 = 1 << 50 if uintptr(v) != 0 { // 64-bit system; clear uintptr tests delete(hammer32, "SwapUintptr") delete(hammer32, "AddUintptr") delete(hammer32, "CompareAndSwapUintptr") delete(hammer32, "SwapUintptrMethod") delete(hammer32, "AddUintptrMethod") delete(hammer32, "CompareAndSwapUintptrMethod") } } func hammerSwapInt32(uaddr *uint32, count int) { addr := (*int32)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 old := uint32(SwapInt32(addr, int32(new))) if old>>16 != old<<16>>16 { panic(fmt.Sprintf("SwapInt32 is not atomic: %v", old)) } } } func hammerSwapInt32Method(uaddr *uint32, count int) { addr := (*Int32)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 old := uint32(addr.Swap(int32(new))) if old>>16 != old<<16>>16 { panic(fmt.Sprintf("SwapInt32 is not atomic: %v", old)) } } } func hammerSwapUint32(addr *uint32, count int) { seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 old := SwapUint32(addr, new) if old>>16 != old<<16>>16 { panic(fmt.Sprintf("SwapUint32 is not atomic: %v", old)) } } } func hammerSwapUint32Method(uaddr *uint32, count int) { addr := (*Uint32)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 old := addr.Swap(new) if old>>16 != old<<16>>16 { panic(fmt.Sprintf("SwapUint32 is not atomic: %v", old)) } } } func hammerSwapUintptr32(uaddr *uint32, count int) { // only safe when uintptr is 32-bit. // not called on 64-bit systems. addr := (*uintptr)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 old := SwapUintptr(addr, new) if old>>16 != old<<16>>16 { panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old)) } } } func hammerSwapUintptr32Method(uaddr *uint32, count int) { // only safe when uintptr is 32-bit. // not called on 64-bit systems. addr := (*Uintptr)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 old := addr.Swap(new) if old>>16 != old<<16>>16 { panic(fmt.Sprintf("Uintptr.Swap is not atomic: %#08x", old)) } } } func hammerAddInt32(uaddr *uint32, count int) { addr := (*int32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { AddInt32(addr, 1) } } func hammerAddInt32Method(uaddr *uint32, count int) { addr := (*Int32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { addr.Add(1) } } func hammerAddUint32(addr *uint32, count int) { for i := 0; i < count; i++ { AddUint32(addr, 1) } } func hammerAddUint32Method(uaddr *uint32, count int) { addr := (*Uint32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { addr.Add(1) } } func hammerAddUintptr32(uaddr *uint32, count int) { // only safe when uintptr is 32-bit. // not called on 64-bit systems. addr := (*uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { AddUintptr(addr, 1) } } func hammerAddUintptr32Method(uaddr *uint32, count int) { // only safe when uintptr is 32-bit. // not called on 64-bit systems. addr := (*Uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { addr.Add(1) } } func hammerCompareAndSwapInt32(uaddr *uint32, count int) { addr := (*int32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := LoadInt32(addr) if CompareAndSwapInt32(addr, v, v+1) { break } } } } func hammerCompareAndSwapInt32Method(uaddr *uint32, count int) { addr := (*Int32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := addr.Load() if addr.CompareAndSwap(v, v+1) { break } } } } func hammerCompareAndSwapUint32(addr *uint32, count int) { for i := 0; i < count; i++ { for { v := LoadUint32(addr) if CompareAndSwapUint32(addr, v, v+1) { break } } } } func hammerCompareAndSwapUint32Method(uaddr *uint32, count int) { addr := (*Uint32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := addr.Load() if addr.CompareAndSwap(v, v+1) { break } } } } func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) { // only safe when uintptr is 32-bit. // not called on 64-bit systems. addr := (*uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := LoadUintptr(addr) if CompareAndSwapUintptr(addr, v, v+1) { break } } } } func hammerCompareAndSwapUintptr32Method(uaddr *uint32, count int) { // only safe when uintptr is 32-bit. // not called on 64-bit systems. addr := (*Uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := addr.Load() if addr.CompareAndSwap(v, v+1) { break } } } } func TestHammer32(t *testing.T) { const p = 4 n := 100000 if testing.Short() { n = 1000 } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) for name, testf := range hammer32 { c := make(chan int) var val uint32 for i := 0; i < p; i++ { go func() { defer func() { if err := recover(); err != nil { t.Error(err.(string)) } c <- 1 }() testf(&val, n) }() } for i := 0; i < p; i++ { <-c } if !strings.HasPrefix(name, "Swap") && val != uint32(n)*p { t.Fatalf("%s: val=%d want %d", name, val, n*p) } } } var hammer64 = map[string]func(*uint64, int){ "SwapInt64": hammerSwapInt64, "SwapUint64": hammerSwapUint64, "SwapUintptr": hammerSwapUintptr64, "AddInt64": hammerAddInt64, "AddUint64": hammerAddUint64, "AddUintptr": hammerAddUintptr64, "CompareAndSwapInt64": hammerCompareAndSwapInt64, "CompareAndSwapUint64": hammerCompareAndSwapUint64, "CompareAndSwapUintptr": hammerCompareAndSwapUintptr64, "SwapInt64Method": hammerSwapInt64Method, "SwapUint64Method": hammerSwapUint64Method, "SwapUintptrMethod": hammerSwapUintptr64Method, "AddInt64Method": hammerAddInt64Method, "AddUint64Method": hammerAddUint64Method, "AddUintptrMethod": hammerAddUintptr64Method, "CompareAndSwapInt64Method": hammerCompareAndSwapInt64Method, "CompareAndSwapUint64Method": hammerCompareAndSwapUint64Method, "CompareAndSwapUintptrMethod": hammerCompareAndSwapUintptr64Method, } func init() { var v uint64 = 1 << 50 if uintptr(v) == 0 { // 32-bit system; clear uintptr tests delete(hammer64, "SwapUintptr") delete(hammer64, "SwapUintptrMethod") delete(hammer64, "AddUintptr") delete(hammer64, "AddUintptrMethod") delete(hammer64, "CompareAndSwapUintptr") delete(hammer64, "CompareAndSwapUintptrMethod") } } func hammerSwapInt64(uaddr *uint64, count int) { addr := (*int64)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 old := uint64(SwapInt64(addr, int64(new))) if old>>32 != old<<32>>32 { panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) } } } func hammerSwapInt64Method(uaddr *uint64, count int) { addr := (*Int64)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 old := uint64(addr.Swap(int64(new))) if old>>32 != old<<32>>32 { panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) } } } func hammerSwapUint64(addr *uint64, count int) { seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 old := SwapUint64(addr, new) if old>>32 != old<<32>>32 { panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) } } } func hammerSwapUint64Method(uaddr *uint64, count int) { addr := (*Uint64)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 old := addr.Swap(new) if old>>32 != old<<32>>32 { panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) } } } const arch32 = unsafe.Sizeof(uintptr(0)) == 4 func hammerSwapUintptr64(uaddr *uint64, count int) { // only safe when uintptr is 64-bit. // not called on 32-bit systems. if !arch32 { addr := (*uintptr)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 old := SwapUintptr(addr, new) if old>>32 != old<<32>>32 { panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) } } } } func hammerSwapUintptr64Method(uaddr *uint64, count int) { // only safe when uintptr is 64-bit. // not called on 32-bit systems. if !arch32 { addr := (*Uintptr)(unsafe.Pointer(uaddr)) seed := int(uintptr(unsafe.Pointer(&count))) for i := 0; i < count; i++ { new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 old := addr.Swap(new) if old>>32 != old<<32>>32 { panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) } } } } func hammerAddInt64(uaddr *uint64, count int) { addr := (*int64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { AddInt64(addr, 1) } } func hammerAddInt64Method(uaddr *uint64, count int) { addr := (*Int64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { addr.Add(1) } } func hammerAddUint64(addr *uint64, count int) { for i := 0; i < count; i++ { AddUint64(addr, 1) } } func hammerAddUint64Method(uaddr *uint64, count int) { addr := (*Uint64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { addr.Add(1) } } func hammerAddUintptr64(uaddr *uint64, count int) { // only safe when uintptr is 64-bit. // not called on 32-bit systems. addr := (*uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { AddUintptr(addr, 1) } } func hammerAddUintptr64Method(uaddr *uint64, count int) { // only safe when uintptr is 64-bit. // not called on 32-bit systems. addr := (*Uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { addr.Add(1) } } func hammerCompareAndSwapInt64(uaddr *uint64, count int) { addr := (*int64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := LoadInt64(addr) if CompareAndSwapInt64(addr, v, v+1) { break } } } } func hammerCompareAndSwapInt64Method(uaddr *uint64, count int) { addr := (*Int64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := addr.Load() if addr.CompareAndSwap(v, v+1) { break } } } } func hammerCompareAndSwapUint64(addr *uint64, count int) { for i := 0; i < count; i++ { for { v := LoadUint64(addr) if CompareAndSwapUint64(addr, v, v+1) { break } } } } func hammerCompareAndSwapUint64Method(uaddr *uint64, count int) { addr := (*Uint64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := addr.Load() if addr.CompareAndSwap(v, v+1) { break } } } } func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) { // only safe when uintptr is 64-bit. // not called on 32-bit systems. addr := (*uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := LoadUintptr(addr) if CompareAndSwapUintptr(addr, v, v+1) { break } } } } func hammerCompareAndSwapUintptr64Method(uaddr *uint64, count int) { // only safe when uintptr is 64-bit. // not called on 32-bit systems. addr := (*Uintptr)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { for { v := addr.Load() if addr.CompareAndSwap(v, v+1) { break } } } } func TestHammer64(t *testing.T) { const p = 4 n := 100000 if testing.Short() { n = 1000 } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) for name, testf := range hammer64 { c := make(chan int) var val uint64 for i := 0; i < p; i++ { go func() { defer func() { if err := recover(); err != nil { t.Error(err.(string)) } c <- 1 }() testf(&val, n) }() } for i := 0; i < p; i++ { <-c } if !strings.HasPrefix(name, "Swap") && val != uint64(n)*p { t.Fatalf("%s: val=%d want %d", name, val, n*p) } } } func hammerStoreLoadInt32(t *testing.T, paddr unsafe.Pointer) { addr := (*int32)(paddr) v := LoadInt32(addr) vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Int32: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<16 if vlo == 1e4 { new = 0 } StoreInt32(addr, new) } func hammerStoreLoadInt32Method(t *testing.T, paddr unsafe.Pointer) { addr := (*int32)(paddr) v := LoadInt32(addr) vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Int32: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<16 if vlo == 1e4 { new = 0 } StoreInt32(addr, new) } func hammerStoreLoadUint32(t *testing.T, paddr unsafe.Pointer) { addr := (*uint32)(paddr) v := LoadUint32(addr) vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Uint32: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<16 if vlo == 1e4 { new = 0 } StoreUint32(addr, new) } func hammerStoreLoadUint32Method(t *testing.T, paddr unsafe.Pointer) { addr := (*Uint32)(paddr) v := addr.Load() vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Uint32: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<16 if vlo == 1e4 { new = 0 } addr.Store(new) } func hammerStoreLoadInt64(t *testing.T, paddr unsafe.Pointer) { addr := (*int64)(paddr) v := LoadInt64(addr) vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Int64: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<32 StoreInt64(addr, new) } func hammerStoreLoadInt64Method(t *testing.T, paddr unsafe.Pointer) { addr := (*Int64)(paddr) v := addr.Load() vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Int64: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<32 addr.Store(new) } func hammerStoreLoadUint64(t *testing.T, paddr unsafe.Pointer) { addr := (*uint64)(paddr) v := LoadUint64(addr) vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Uint64: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<32 StoreUint64(addr, new) } func hammerStoreLoadUint64Method(t *testing.T, paddr unsafe.Pointer) { addr := (*Uint64)(paddr) v := addr.Load() vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Uint64: %#x != %#x", vlo, vhi) } new := v + 1 + 1<<32 addr.Store(new) } func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) { addr := (*uintptr)(paddr) v := LoadUintptr(addr) new := v if arch32 { vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) } new = v + 1 + 1<<16 if vlo == 1e4 { new = 0 } } else { vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) } inc := uint64(1 + 1<<32) new = v + uintptr(inc) } StoreUintptr(addr, new) } //go:nocheckptr func hammerStoreLoadUintptrMethod(t *testing.T, paddr unsafe.Pointer) { addr := (*Uintptr)(paddr) v := addr.Load() new := v if arch32 { vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) } new = v + 1 + 1<<16 if vlo == 1e4 { new = 0 } } else { vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) } inc := uint64(1 + 1<<32) new = v + uintptr(inc) } addr.Store(new) } // This code is just testing that LoadPointer/StorePointer operate // atomically; it's not actually calculating pointers. // //go:nocheckptr func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) { addr := (*unsafe.Pointer)(paddr) v := uintptr(LoadPointer(addr)) new := v if arch32 { vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Pointer: %#x != %#x", vlo, vhi) } new = v + 1 + 1<<16 if vlo == 1e4 { new = 0 } } else { vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Pointer: %#x != %#x", vlo, vhi) } inc := uint64(1 + 1<<32) new = v + uintptr(inc) } StorePointer(addr, unsafe.Pointer(new)) } // This code is just testing that LoadPointer/StorePointer operate // atomically; it's not actually calculating pointers. // //go:nocheckptr func hammerStoreLoadPointerMethod(t *testing.T, paddr unsafe.Pointer) { addr := (*Pointer[byte])(paddr) v := uintptr(unsafe.Pointer(addr.Load())) new := v if arch32 { vlo := v & ((1 << 16) - 1) vhi := v >> 16 if vlo != vhi { t.Fatalf("Pointer: %#x != %#x", vlo, vhi) } new = v + 1 + 1<<16 if vlo == 1e4 { new = 0 } } else { vlo := v & ((1 << 32) - 1) vhi := v >> 32 if vlo != vhi { t.Fatalf("Pointer: %#x != %#x", vlo, vhi) } inc := uint64(1 + 1<<32) new = v + uintptr(inc) } addr.Store((*byte)(unsafe.Pointer(new))) } func TestHammerStoreLoad(t *testing.T) { tests := []func(*testing.T, unsafe.Pointer){ hammerStoreLoadInt32, hammerStoreLoadUint32, hammerStoreLoadUintptr, hammerStoreLoadPointer, hammerStoreLoadInt32Method, hammerStoreLoadUint32Method, hammerStoreLoadUintptrMethod, hammerStoreLoadPointerMethod, hammerStoreLoadInt64, hammerStoreLoadUint64, hammerStoreLoadInt64Method, hammerStoreLoadUint64Method, } n := int(1e6) if testing.Short() { n = int(1e4) } const procs = 8 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs)) // Disable the GC because hammerStoreLoadPointer invokes // write barriers on values that aren't real pointers. defer debug.SetGCPercent(debug.SetGCPercent(-1)) // Ensure any in-progress GC is finished. runtime.GC() for _, tt := range tests { c := make(chan int) var val uint64 for p := 0; p < procs; p++ { go func() { for i := 0; i < n; i++ { tt(t, unsafe.Pointer(&val)) } c <- 1 }() } for p := 0; p < procs; p++ { <-c } } } func TestStoreLoadSeqCst32(t *testing.T) { if runtime.NumCPU() == 1 { t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) N := int32(1e3) if testing.Short() { N = int32(1e2) } c := make(chan bool, 2) X := [2]int32{} ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}} for p := 0; p < 2; p++ { go func(me int) { he := 1 - me for i := int32(1); i < N; i++ { StoreInt32(&X[me], i) my := LoadInt32(&X[he]) StoreInt32(&ack[me][i%3], my) for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ { if w%1000 == 0 { runtime.Gosched() } } his := LoadInt32(&ack[he][i%3]) if (my != i && my != i-1) || (his != i && his != i-1) { t.Errorf("invalid values: %d/%d (%d)", my, his, i) break } if my != i && his != i { t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) break } StoreInt32(&ack[me][(i-1)%3], -1) } c <- true }(p) } <-c <-c } func TestStoreLoadSeqCst64(t *testing.T) { if runtime.NumCPU() == 1 { t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) N := int64(1e3) if testing.Short() { N = int64(1e2) } c := make(chan bool, 2) X := [2]int64{} ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}} for p := 0; p < 2; p++ { go func(me int) { he := 1 - me for i := int64(1); i < N; i++ { StoreInt64(&X[me], i) my := LoadInt64(&X[he]) StoreInt64(&ack[me][i%3], my) for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ { if w%1000 == 0 { runtime.Gosched() } } his := LoadInt64(&ack[he][i%3]) if (my != i && my != i-1) || (his != i && his != i-1) { t.Errorf("invalid values: %d/%d (%d)", my, his, i) break } if my != i && his != i { t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) break } StoreInt64(&ack[me][(i-1)%3], -1) } c <- true }(p) } <-c <-c } func TestStoreLoadRelAcq32(t *testing.T) { if runtime.NumCPU() == 1 { t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) N := int32(1e3) if testing.Short() { N = int32(1e2) } c := make(chan bool, 2) type Data struct { signal int32 pad1 [128]int8 data1 int32 pad2 [128]int8 data2 float32 } var X Data for p := int32(0); p < 2; p++ { go func(p int32) { for i := int32(1); i < N; i++ { if (i+p)%2 == 0 { X.data1 = i X.data2 = float32(i) StoreInt32(&X.signal, i) } else { for w := 1; LoadInt32(&X.signal) != i; w++ { if w%1000 == 0 { runtime.Gosched() } } d1 := X.data1 d2 := X.data2 if d1 != i || d2 != float32(i) { t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i) break } } } c <- true }(p) } <-c <-c } func TestStoreLoadRelAcq64(t *testing.T) { if runtime.NumCPU() == 1 { t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) N := int64(1e3) if testing.Short() { N = int64(1e2) } c := make(chan bool, 2) type Data struct { signal int64 pad1 [128]int8 data1 int64 pad2 [128]int8 data2 float64 } var X Data for p := int64(0); p < 2; p++ { go func(p int64) { for i := int64(1); i < N; i++ { if (i+p)%2 == 0 { X.data1 = i X.data2 = float64(i) StoreInt64(&X.signal, i) } else { for w := 1; LoadInt64(&X.signal) != i; w++ { if w%1000 == 0 { runtime.Gosched() } } d1 := X.data1 d2 := X.data2 if d1 != i || d2 != float64(i) { t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i) break } } } c <- true }(p) } <-c <-c } func shouldPanic(t *testing.T, name string, f func()) { defer func() { // Check that all GC maps are sane. runtime.GC() err := recover() want := "unaligned 64-bit atomic operation" if err == nil { t.Errorf("%s did not panic", name) } else if s, _ := err.(string); s != want { t.Errorf("%s: wanted panic %q, got %q", name, want, err) } }() f() } func TestUnaligned64(t *testing.T) { // Unaligned 64-bit atomics on 32-bit systems are // a continual source of pain. Test that on 32-bit systems they crash // instead of failing silently. if !arch32 { t.Skip("test only runs on 32-bit systems") } x := make([]uint32, 4) p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned shouldPanic(t, "LoadUint64", func() { LoadUint64(p) }) shouldPanic(t, "LoadUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).Load() }) shouldPanic(t, "StoreUint64", func() { StoreUint64(p, 1) }) shouldPanic(t, "StoreUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).Store(1) }) shouldPanic(t, "CompareAndSwapUint64", func() { CompareAndSwapUint64(p, 1, 2) }) shouldPanic(t, "CompareAndSwapUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).CompareAndSwap(1, 2) }) shouldPanic(t, "AddUint64", func() { AddUint64(p, 3) }) shouldPanic(t, "AddUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).Add(3) }) } func TestAutoAligned64(t *testing.T) { var signed struct { _ uint32 i Int64 } if o := reflect.TypeOf(&signed).Elem().Field(1).Offset; o != 8 { t.Fatalf("Int64 offset = %d, want 8", o) } if p := reflect.ValueOf(&signed).Elem().Field(1).Addr().Pointer(); p&7 != 0 { t.Fatalf("Int64 pointer = %#x, want 8-aligned", p) } var unsigned struct { _ uint32 i Uint64 } if o := reflect.TypeOf(&unsigned).Elem().Field(1).Offset; o != 8 { t.Fatalf("Uint64 offset = %d, want 8", o) } if p := reflect.ValueOf(&unsigned).Elem().Field(1).Addr().Pointer(); p&7 != 0 { t.Fatalf("Int64 pointer = %#x, want 8-aligned", p) } } func TestNilDeref(t *testing.T) { funcs := [...]func(){ func() { CompareAndSwapInt32(nil, 0, 0) }, func() { (*Int32)(nil).CompareAndSwap(0, 0) }, func() { CompareAndSwapInt64(nil, 0, 0) }, func() { (*Int64)(nil).CompareAndSwap(0, 0) }, func() { CompareAndSwapUint32(nil, 0, 0) }, func() { (*Uint32)(nil).CompareAndSwap(0, 0) }, func() { CompareAndSwapUint64(nil, 0, 0) }, func() { (*Uint64)(nil).CompareAndSwap(0, 0) }, func() { CompareAndSwapUintptr(nil, 0, 0) }, func() { (*Uintptr)(nil).CompareAndSwap(0, 0) }, func() { CompareAndSwapPointer(nil, nil, nil) }, func() { (*Pointer[byte])(nil).CompareAndSwap(nil, nil) }, func() { SwapInt32(nil, 0) }, func() { (*Int32)(nil).Swap(0) }, func() { SwapUint32(nil, 0) }, func() { (*Uint32)(nil).Swap(0) }, func() { SwapInt64(nil, 0) }, func() { (*Int64)(nil).Swap(0) }, func() { SwapUint64(nil, 0) }, func() { (*Uint64)(nil).Swap(0) }, func() { SwapUintptr(nil, 0) }, func() { (*Uintptr)(nil).Swap(0) }, func() { SwapPointer(nil, nil) }, func() { (*Pointer[byte])(nil).Swap(nil) }, func() { AddInt32(nil, 0) }, func() { (*Int32)(nil).Add(0) }, func() { AddUint32(nil, 0) }, func() { (*Uint32)(nil).Add(0) }, func() { AddInt64(nil, 0) }, func() { (*Int64)(nil).Add(0) }, func() { AddUint64(nil, 0) }, func() { (*Uint64)(nil).Add(0) }, func() { AddUintptr(nil, 0) }, func() { (*Uintptr)(nil).Add(0) }, func() { LoadInt32(nil) }, func() { (*Int32)(nil).Load() }, func() { LoadInt64(nil) }, func() { (*Int64)(nil).Load() }, func() { LoadUint32(nil) }, func() { (*Uint32)(nil).Load() }, func() { LoadUint64(nil) }, func() { (*Uint64)(nil).Load() }, func() { LoadUintptr(nil) }, func() { (*Uintptr)(nil).Load() }, func() { LoadPointer(nil) }, func() { (*Pointer[byte])(nil).Load() }, func() { StoreInt32(nil, 0) }, func() { (*Int32)(nil).Store(0) }, func() { StoreInt64(nil, 0) }, func() { (*Int64)(nil).Store(0) }, func() { StoreUint32(nil, 0) }, func() { (*Uint32)(nil).Store(0) }, func() { StoreUint64(nil, 0) }, func() { (*Uint64)(nil).Store(0) }, func() { StoreUintptr(nil, 0) }, func() { (*Uintptr)(nil).Store(0) }, func() { StorePointer(nil, nil) }, func() { (*Pointer[byte])(nil).Store(nil) }, } for _, f := range funcs { func() { defer func() { runtime.GC() recover() }() f() }() } } // Test that this compiles. // When atomic.Pointer used _ [0]T, it did not. type List struct { Next Pointer[List] }