Files
boc/rust-service/target/debug/deps/libcrossbeam_epoch-6e29ae3b3cd894c0.rmeta
T

967 lines
246 KiB
Plaintext
Raw Normal View History

rust
«×#rustc 1.96.0 (ac68faa20 2026-05-25)ÁíàÄTËŸ ÜJîÄ)'ß\¥!-3d1337db07d0b3aeÁÀ뉊]!ÜÛê(¹Þ—šên-5be7b69c3ff7b5b8Á¤²XctÔ'ÐÓ©z¨ɽÓ-a4945860e1c53b00Á¤°ð ¾ä-±($²ï=©Ã-7e98a21bfd32b0edÁòÖÀH•‘PIÓHã#£-055f30b747f859b6Árustc_std_workspace_coreÁ­Cçß^ò½èÝ$­Çÿ+Cé-c4878ee60b2242c9ÁŸÃï+Ñ]ŠqB<ÏïW#-8dd1dd90e70d0b6aÁ miniz_oxideÁ€š»J(P>àö÷g\K-1eb618da2918ab7fÁadler2ÁÆ;+Þ®5¥Ìýݰ¦ÛLˆ-f7919172d268e069Á hashbrownÁPäV9ÒÆèÜ"ÊÖVŽ\-0fc2184a5da6723aÁrustc_std_workspace_allocÁs&ØòØy¯s•bæ!‰ýŠ-97e4bf30be240674Á
std_detectÁhŠBîÙºÌI®ËÅš-9dbbf8346ba7ac8bÁrustc_demangleÁûë9´Ç×@Œ’ùXFº-f33013f239bf9f14Ácfg_ifÁÜLhž§Œaã¯>­-0a71c8f33a838301Á addr2lineÁ׎Þ!]8V$É@@-e618e6be60e87ba2ÁgimliÁ¸
°µ~Î1‹Ñt ðÁ€w-1f7768a68858f670ÁobjectÁ
áPÃ?­À¶¼QHJ¥-914cd6a4dbe590d1ÁmemchrÁ›º«8Ór­2Ù $¨ûib-cf21ca6f2bb15dcdÁë
‹ás«LÖ€îâƒ×ɯŒ-ee6f3747e38367f0Ácrossbeam_utilsÁ z“ÚLå<ýÓ;ã¡ÒFÕ-66e145216f0a822fÁloomÁ$Ðcrossbeam_loomÁ primitiveÁLÀt‡testsÁ,ð¤$Ϥ³¾Ô¾,›ïAtomicEpochReprÁ|¤ó64ÁăÔ‚ï EpochReprÁLÅó ĤÔ£ïEpochReprSignedÁ|À ó ÄŸ Ôž ¬ MAX_OBJECTSÁ\crossbeam_sanitizeÁ”ëµ $ÿÔꬾ,˜¤$÷£¾,¸P$—PÔ$þ=$Ý=Œ¾
íÀ¢cellÁ¥æ withÁ £ impl FnOnce(*const T) -> RÁwith_mutÁ £ impl FnOnce(*mut T) -> RÁç¤atomicÁ 
  
strongest_failure_orderingÁ*CompareAndSetErrorÁ,'gÁ,¥,¡CompareExchangeErrorÁ0ë
0¥0¡0currentÁ0æ 6¥6¡6×CompareAndSetOrderingÁ:successÁ:failureÁ=ü=Š@ü@Šlow_bitsÁC¥ensure_alignedÁE¥ compose_tagÁG¥
decompose_tagÁI¥ PointableÁKALIGNÁKInitÁKinitÁK´O'aÁKQÛKãT¥T²T¾TÉT´YÛT[ÛTãM^¥^^elementsÁa c¥clayoutÁf¥f²f¾fÉf´kÛfmÛfãVp¥pdataÁp_markerÁt¥v¥x¥xæ  {¥{É{{
{‘
{ load_consumeÁë
{È¡{swapÁë
¡{ ë
¡  {¡Žë
Ž¡Ž Ž {¾ë
{compare_and_setÁë
 ¡{compare_and_set_weakÁšë
š š¡{ fetch_andÁžë
{fetch_orÁ ë
{ fetch_xor碑
{
into_ownedÁ{try_into_ownedÁ
¦¥¦× ©¥©× ¬¥¬ƒ
¯¥¯>²¥²÷µ¥µ÷¸¥¸÷»ë
»¥»÷¿¥¿÷Â¥Â
into_usizeÁÂOwnedÁÆ¥ÆËÆÖÊ¥ÊòÊÎ¥Îfrom_rawÁÎinto_boxÁÎæ Ó¥ÓÉÓ into_sharedÁÖë
ÓtagÁÓwith_tagÁÚ¥ÚãÝ¥Ý×à¥àƒã¥ãåã´ç¥çê¥ê÷í¥í÷ð¥ðborrowÁó¥ó
borrow_mutÁö¥öÉ ù¥ùas_mutÁSharedÁüë
ü¥üËüÖ!¥ƒ"¥#¥ò$Šë
Š¥Šas_rawÁ%Žë
Ž¥Ž
Žis_nullÁŽ´ŽŽÉŽŽŽ¯Žº&š¥š÷'ë
¥(¡¥)£ë
£¥£ï
*§¥§+ª¥ª×,­¥­×-°¥°> collectorÁ³³³³³³³ CollectorÁºglobalÁ³³³¾>³Àæ ÀregisterÁ³Ãƒ³Å׳dz³ LocalHandleÁÊ®³Ìÿ
Ì is_pinnedÁÌØ³ Ðã³
Ò×deferredÁÔÔÔÔÔÔÔÔ
DATA_WORDSÁÔDataÁÝ ÔDeferredÁßÑßËßÖÔã×ÔåNO_OPÁæ
no_op_callÁåæ èèÑêèÑìåÑepochÁïï ï® ïÓ ïôstartingÁôëô­ ôpinnedÁôunpinnedÁô successorÁïûæ û¬ûÈû £GuardÁ®deferÁŒŒ£defer_uncheckedÁ£ 
defer_destroyÁ¥ flushÁrepinÁ repin_afterÁ˜˜£˜
ScopeGuardÁ
ˆ˜žãØ  ¢ã¤× unprotectedÁ¦ GuardWrapperÁ§
§ˆ¦¦ UNPROTECTEDÁ嬬¬¬¬¬¬¬¬¬ ¬
¬ ¬ ¬
¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬þ ¬BagÁÎ deferredsÁÏ Î¬¬Óæ Óis_emptyÁÓtry_pushÁÓsealÁ¬Ø>Ù ¬Ûã¬Ý׬¬à
is_expiredÁ¬GlobalÁâlocalsÁâqueueÁâÅ"¬æ
COLLECT_STEPSÁææ æpush_bagÁæcollectÁê æ try_advanceÁ¬LocalÁíentryÁíØíbagÁí guard_countÁí handle_countÁí pin_countÁíÅ"¬õPINNINGS_BETWEEN_COLLECTÁõÉõ˜õØù õ­ õ±$ü õœ%þ õÿ
õþõ©%õacquire_handleÁõrelease_handleÁõfinalizeÁ  ¬ ˆentry_ofÁˆ
element_ofÁˆô,çŒlistÁ  IsElementÁ˜¥˜“-˜£-˜ô,IterÁë
¥£predÁcurrÁheadÁÖ¦>¨deleteÁª¥ªªæ ªinsertÁ®ë
ªù°ë
²¥²²ãë
¥ó Œ once_lockÁ¼¼¼¼OnceLockÁÀ¥ÀonceÁÀ»¼Ä¥¼Æ¥¼È¥Èæ È get_or_initÁËÈ
initializeÁÍÍ È
get_uncheckedÁ¼Ñ¥ÑãŒñ)ÔÔÔÔÔÔÔÔÔÔ Ô
Ô ÔNodeÁá¥áËáó Ôå¥Ôç¥Ôé¥éæ é
push_internalÁépushÁé pop_internalÁî î épop_if_internalÁññ ñ étry_popÁé
try_pop_ifÁöÔø¥øã 
  
>ŒŒŒŒŒŒŒØ COLLECTORÁŒÿ
 Œ­  Œdefault_collectorÁŒ with_handleÁšš£š š 
UnsafeCellÁ£
£¥£ˆ§¥§×ïEpochÁªËïïﮃï°>ï²×ï´Öïï ·ï AtomicEpochÁ¹Ëï
»>ï ½×¬ SealedBagÁ¿Å"¿_bagÁ¬
Â>¬ Ä×EntryÁÆó È×ListÁÊ¥ÊÊ÷.ÊÖÏ¥ÏÏ× IterErrorÁÓStalledÁÔ
× Ù×ÔQueueÁÛ¥Û÷.ÛtailÁÔߥß׌HANDLEÁâ__rust_std_internal_init_fnÁâ ä å__RUST_STD_INTERNAL_VALÁä çü:

6
9
9
9
;
<
>
?
A
B






Ž
Ž



š
š
ž
 
¢
¨
¨
¨
«
«
«
®
Ø
Ü
ß
ß
ß
â
æ
é
ò
õ
ø
û

ƒ







˜

š
 
 
¡
¦
¦
§
©
©
ª
¬
¬
¬
­
¯
¯
¯
°
Â
Ä
Æ
Æ
Æ
È
È
Í
Î
Ï
Ñ
Ó
Ó
Ó
ä
ä
ä
ý
þ
ÿ
Œ





˜
Ÿ
 
£
¥
¥
¥
Õ
Ö
Ü
Þ
Þ
Þ
á
é
é
é
ê
ê
ê
ì
ì
÷
ø
ù
û
ü
ü
þ
þ



ƒ



Š


š

œ
œ
©
©
µ
»
Ë
Í
Ð
Ó
ì
ì
ì
ì
í
í
î
î
ñ
ñ
ñ
õ
õ
ö
ö
ö
ú
š
©
©
©
¯
³
³
³
µ
¸
¸
¾
¾
¾
Å
Å
Å
É
É
É
Ò
Ò
Ò
Ø
Ø
Ú
Ú
Ú
á
á
á
:K˜¿c££¤Ã6¦ˆ 
2šÁ]îC4¥¿c004²5æ `::+d¼þ8¥¡:¼À½À¾ÀË¿ÀÀÀÌÁÀÂÀGÃÀÄÀFÅÀÆÀ×`šÁ¬S øB:™E™EKÅDK
ÑÛÑÛ MaybeUninitÁÓÛuninitÁÝÔÛ»ÝÍõƒ«%9ÅDÌìppVrËsÖ»(xÑÑÄÅD ÿF¿cÿFÎcÿFØÿF³ÿFéÿFÆÆÈËÉÖ$zF–Е5ÉÅDéÿFžBoxÁ¡ˆˆ¢ˆl }.xÏÅDçEçEèEÕ) ¿±‡§í#éÿFÅDéppVrËsÖ»(xÑÑćEüüÃÿËÖDe—è­×ë
‡EéÿF ÅDÂñGÅDŒ"ñG¿cñGØñGé!ñGö!ñGéñGÅDéñG¶H ñGÅD£ñGÅDàñGÅDãñGÅDØüüÃÿËÖDe—è­×8‡EŠ ÎKÂÎK‡EéÎK ‡EµßêIêIÎKíßêIêIºÎK¿cÎKÎcÎK³ÎKÌ캺»˜ÉÈ\Ácä ŠM³ŠMØŠM¿cŠMµßŠMŠMŠMŒ"ÊÊË®D_ú6xƒgt¿cþM¿cßßµ!àÑÔáËÔâÖÔÌ¡÷—ì=Š ªªþ6«Ëïì·>ƒ‡amÛ‰O؉O³‰O¿c‰O‰OÐì‰Oµß‰O‰O³¹¹â7ºËï:ºm¨©V¬G¿c‰PŒ"œÙ%ˆ Ê=*K”©Œ"—$Š®þšl{ÈÅ0¿cQ §§¨¿&©ˆ fZR{˜ýLÌìÎΧ(ϲ(¬Ñ¬87úÆ]T§œ³ùQŒ"ùQ¿cùQ³¿¿–8ÀÅ"¬Á¯8¬ÒÊ訉Ü¿cØR ØR˜ííß*îì*¬ïجð+ñŒ+¬òŸ+¬ó³+¬ôÅ"¬:ÁÁ£ÏFV$­S¿cÆÆÔ8Çó ç¾3èlD9…¿cÊÊö8Í÷.ÎÖñ$ƒ[ë΂çÅDÐìÓÔÕÐ9ìGµß¬U¬U¿c¬U³¬TŒ"áTùM³.¡£¢ß.£ë.¤÷.¥Ö¥ªç\¨ŒWë
‡E ÀÀ×0Âï0¼Ã»¼Mɾš5½žÅDÌìùVŒ"ùV¿cÛÛƒ:Ý÷.ÔÞ :ÔP Ãn­ƒ•zÅD ÒWÌìÒWŒ"ÒW§£6ƪüźÒÊãß²ª½¹¤ÝÎÄ¿ÈÆÏÊÙÓßÛ=¼À@
Tf tºÒÎÆÀçÛvºª§ß¿ÄÀåÛ©ü¬Æüú®ª¯ü¾º°ª»¹ØÎ¿¦Æ²p¿ÆíÆšüÊÆüÚÆÐÊž¢ÛβÊÑÀøÛãÆçÆðÆóÆöÆùÆü¬ªüǺ·ª×Ó¡üɺ´ª£ü§ü­ªªÖÓˆí¿cÆ:tK Ìì !Îc(Ø
³"é7Â3Œ"é!8ö! £à㊠µßíߺÛÐì˜ùMüù%#$—&
#ìù%
õ0ÅD3E &üî%/ £ÅD œ&«&üª%”DlÎ%ÅD$Â%î0î0Ã6ð0»Ì-·}—KEüC£ÅDÛÅDÙËHw¤Ó3
 ”Ó3
ÊÅD%ü¾3*V,Ë3$Ã`Ü©>
 Ì©>
Ê^^M`aÐ&°Ô{-i–‚ÅDXü”>1hÃ`,¡>$œïU
„ïU
ŒÄ €VÃ`>\™V  ÅDüÖUY pÅD ®VµVü«UŠÿFLÂU¤]¤]V¦]Á‚]üß3ø¤”&Ã`á PhantomDataÁFu\»Ÿåb×Ã`Ã`
DATA_WORDSÁ
ç ¬Ó
œÓ
òÃ`Ã`9\ÿ  eüœy ß üËÑæ¼N‰eßÑÛÑÛ±EÓÛÆEÝÔÛ»ÝÍõƒ«%9¸eù€cFu\»ŸéeéŸ@Ã`64Á@Ã` MAX_OBJECTSÁ@Ã` MAX_OBJECTSÁÃ`Ã`128Á 
 
þ8'üÓ& ¬ã 
ϋ 
òÅD+8
? 
õ0¥FO` ø üšj ÀÅD ƒ Š Êüîœ ùV$ ï8ï8OnceÁð8innerÁé8ãTPàVça!î0î0Ã6ð0»Ì-·}—KEüC£¥F,¥F+ùW·e

éW·e
¾þMùWÕúeäÛ¼ݼÞ¼©ß¼à¼ÛἈcSñŸ«‡zÙ Û¼ݼÞ¼©ß¼à¼ÛἈcSñŸ«‡zÙþM þMûk±ßùVfaâ®®£°Ói¨it§ÅLS¶þMáV¢faXäûkûkùWðe
éWðe
ÐþM/5ùW¦®e  å€l“me/ûk W¿eùWíÔeùW‚!­e  ço…oe#ûk W!eM WÀ$eùWÛôeäûkå‚o…oeåç‚o…oeŸSüæ  £ÅD¤)”D4§_;BŒr
œ%ÈP0 ­S9@œ——
§¨&¿Q1Q8?³Ô﬌ŒíÀû¤,‰+Ò
”æ/,üà¬ú/:ýV4ê0p¤ò00,ˆ1Æ¢L1Kƒ<š1ÂÃ4£1üL¼1º… \Ç1ʈ¬&\á1 ¦Š—$,î1î5ŒÐ2  ­ Lã2 ¡ÿ
î2 ¢üó2ü# Epoch-based memory reclamation.Á$úü(\Y An interesting problem concurrent collections deal with comes from the remove operation.Áü…b_ Suppose that a thread removes an element from a lock-free map, while another thread is readingÁüè`] that same element at the same time. The first thread must wait until the second thread stopsÁüÉ=: reading the element. Only then it is safe to destruct it.Áúü‹]Z Programming languages that come with garbage collectors solve this problem trivially. TheÁüéa^ garbage collector will destruct the removed element when no thread can hold a reference to itÁ anymore.ÁØúüÜa^ This crate implements a basic memory reclamation mechanism, which is based on epochs. When anÁü¾`] element gets removed from a concurrent collection, it is inserted into a pile of garbage andÁüŸc` marked with the current epoch. Every time a thread accesses a collection, it checks the currentÁüƒa^ epoch, attempts to increment it, and destructs some garbage that became so old that no threadÁüå" can be referencing it anymore.ÁˆúüŒb_ That is the general mechanism behind epoch-based memory reclamation, but the details are a bitÁüï`] more complicated. Anyhow, memory reclamation is designed to be fully automatic and somethingÁüÐ C@ users of concurrent collections don't have to worry much about.Á
út˜
# PointersÁ§
úü«
b_ Concurrent collections are built using atomic pointers. This module provides [`Atomic`], whichÁüŽ ^[ is just a shared atomic pointer to a heap-allocated object. Loading an [`Atomic`] yields aÁüí a^ [`Shared`], which is an epoch-protected pointer through which the loaded object can be safelyÁ  read.ÁÙ ú
# PinningÁë úüï b_ Before an [`Atomic`] can be loaded, a participant must be [`pin`]ned. By pinning a participantÁüÒ
XU we declare that any object that gets removed from now on must not be destructed justÁü«\Y yet. Garbage collection of newly removed objects is suspended until the participant getsÁlˆ
unpinned.Áú
# GarbageÁ¨úü¬a^ Objects that get removed from concurrent collections must be stashed away until all currentlyÁüŽ^[ pinned participants get unpinned. Such objects can be stored into a thread-local or globalÁüíRO storage, where they are kept until the right time for their destruction comes.ÁÀúüÄkh There is a global shared instance of garbage queue. You can [`defer`](Guard::defer) the execution of anÁü°_\ arbitrary function until the global epoch is advanced enough. Most notably, concurrent dataÁü74 structures may defer the deallocation of an object.ÁÈú # APIsÁ×úüÛa^ For majority of use cases, just use the default garbage collector by invoking [`pin`]. If youÁü½IF want to create your own garbage collector, use the [`Collector`] API.ÁüÇ üñ6³Ô﬌Œí¢
À£
¤¢
Ò
¡
,üà 
:ýVŸ
pž
0
Æ¢œ
Kƒ
ÂÚ
ü
º˜
ʈ¬&
¦Š—$
î5
 ­ 
¡ÿ

¢ËÎÑ„îÈóµ Ì¢üœ!„ÇܾL‚ d±*µœ’ £¤¬ð$¥ÍìÅD õ$”D 
üª%1¾%ÅD”D
ÅDËŒüÏ&@$Ý&é é”DÜ ££
Ü 
  å&Íìé’ â&Íìä’Ôï&"ä’µJ¬ô&ä’É“˜"é’ ˆ'
ÅDé’ä’$æ&± ì&_a[]üã'BDñ'ê ê”D é’£
 
 ý'œ“ ú'ÍìÕ”ć(–"Õ”åbœŒ(Õ”¯•˜"é’ ž(
ÅDé’Õ”$þ'± „(_a[]œê($ù(KÆ)†JÌ 4î)]„¹)'”â)Œ¬*¾”ü*µTË+»¤Œ›+óµ Ì®+üš+.ü‘+94Ï+*,0:CEGIK^pÂÆüÄG 4(èØY4C ZLK£a×p `€c\‡€cíë±E\ªÑÛr,Èé!!DerefMutÁDÏö!"µ ä#ž‰f$—$,% AtomicUsizeÁ\¹„Ä'®¼À(
AtomicConsumeÁlîœqœed4Y\NQL[ELj9Ìy-L˜žùûâäLÞ×\íÊœÿ½ô˜¥§—üÕ&}ü–8Ô™™E™E
*ordÁ´ü‡%üå;8 The error returned on failed compare-and-set operation.Á"Use `CompareExchangeError` insteadÁüà$üÌ:‡›ë
-¥.¡/-./Íì‡E §ÍìE ª004²5æ `::+d¼þë
‡EE£UWRTüIüÐ<9 The error returned on failed compare-and-swap operation.Á¤˜ë
1¥2¡3321Îì‡E ± ÈK‡EÂE‡E‡Eë
žÍ`::+d¼þ45­[]`bÔª üÝHE The value in the atomic pointer at the time of the failed operation.Á<® 00êIT‡
üË 74 The new value, which the operation failed to store.Á
00Eü–
Q8ë¥7¡88ë7òœ
 ž
•Ÿ
¿cE
ÒD9Àc9/146üî
8ñ
ìíî ìÒD í c cˆ¢cµ
 `£cbufÁ `àB¤GS
îÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
eŸÈŸÈ ÈErrorÁ O˜éBL6 õ
6
98‡EE
± ü
üÛüÉ 41 Memory orderings for compare-and-set operations.Áþ úü‚
[X A compare-and-set operation can have different memory orderings depending on whether itÁüÞ
\Y succeeds or fails. This trait generalizes different ways of specifying memory orderings.Á»úü¿A> The two ways of specifying orderings for compare-and-set are:Áúü…^[ 1. Just one `Ordering` for the success case. In case of failure, the strongest appropriateÁÔä ordering is chosen.Áüÿ\Y 2. A pair of `Ordering`s. The first one is for the success case, while the second one isÁäÜ for the failure case.ÁŠ`compare_and_set` and `compare_and_set_weak` that use this trait are deprecated, use `compare_exchange` or `compare_exchange_weak instead`Áü½šü¤¬å…©::ÎìüÛß:īī;<;<<;ô¹ü30 The ordering of the operation when it succeeds.Á<¼…©Ìï ïÌ«™E: Ä:
;Ì«ôšüÝ0- The ordering of the operation when it fails.Áúüš]Z The failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker thanÁÌü the success ordering.Á<…©ùð ðÌ«™E: ¥:
<Ì«üÑ'™E>?;<>?ì<ñ ñ™E™E= ˜=
>$™ìÔ<×ò ò™E™E= ß=
?ü¼3ŽFAB;<ABì„<‡ó óŽF™E@ @
A$ìÌô ôŽF™E@ ×@
Büï-Ã`¥DDÎìÅD ûKÅDL‡
CÅDüŠ4tÃ`e¥FF„³ œ”³
EÅD@³ü¯GÃ`Ã`Ã`¥HH„³ ¾”³
GÅD˯â#%üƒFl†Ã`Ã`Ã`¥JJ„³ ”³
IÅDËœÈ'ü… /, Types that are pointed to by a single word.Áµ úü¹ b_ In concurrent programming, it is necessary to represent an object within a word because atomicÁüœ!_\ operations (e.g., reads, writes, read-modify-writes) support only single words. This traitÁüü!>; qualifies such types that are pointed to by a single word.Á»"úü¿"\Y The trait generalizes `Box<T>` for a sized type `T`. In a box, an object of type `T` isÁüœ#c` allocated in heap and it is owned by a single-word pointer. This trait is also implemented forÁü€$da `[MaybeUninit<T>]` by storing its size along with its elements and pointing to the pair of arrayÁ´å$ size and elements.Áü$úü€%]Z Pointers to `Pointable` types can be stored in [`Atomic`], [`Owned`], and [`Shared`]. InÁüÞ%GD particular, Crossbeam supports dynamically sized slices as follows.Á¦&ú<ª& ```Áô²& use std::mem::MaybeUninit;ÁüÑ& use crossbeam_epoch::Owned;Áñ&úüõ&JG let o = Owned::<[MaybeUninit<i32>]>::init(10); // allocating [i32; 10]Á<À'©¼LÒ'KKÄ«üÈ'Ö KīīLMNOQSLMNOQSÍìÌ«MTÀ(»¿QONS”„(ìâ' The alignment of pointer.Á,Š(KKÃ`LÀ(ô( The type for initializers.Á$Å(KKü×)*üÐ(-* Initializes a with the given initializer.Á)údŠ) # SafetyÁ)úü£)/, The result should be a multiple of `ALIGN`.Á$á)ÿÃ`KK
NÌ«É$æ)üÇ,,ü‡*# Dereferences the given pointer.Á¯*úd·*³ÀÈ*úüÐ*LI - The given `ptr` should have been initialized with [`Pointable::init`].Áü¡+DA - `ptr` should not have yet been dropped by [`Pointable::drop`].Áüê+XU - `ptr` should not be mutably der
`Shared`.Áœlúü¤lZÏãtƒm²ä–mútžmÖÛ±mú<¹m©¼üÅm96 use crossbeam_epoch::{self as epoch, Atomic, Shared};Áüƒn,·å´núô¼n¼Üôßn…æü‚o2/ let p = a.swap(Shared::null(), SeqCst, guard);Áü¹o41 # unsafe { drop(p.into_owned()); } // avoid leakÁ<òo©¼$…pø øÿFÉõ™E QüüÃÿËÖDe—è­×ÅD{¡ˆˆŠp{õõ Žp†öT‘p
ÅDÉõ$žpæ ¤p«š¬p »pCE;=üê~Šü´q`] Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the currentÁü™r^[ value is the same as `current`. The tag is also taken into account, so two pointers to theÁüürGD same object, but with different tags, will not be considered equal.ÁÈsúüÐs_\ The return value is a result indicating whether the new pointer was written. On success theÁü´t[X pointer that was written is returned. On failure the actual current value and `new` areÁl”u
returned.Á¦uúü®uEB This method takes two `Ordering` arguments to describe the memoryÁüøuQN ordering of this operation. `success` describes the required ordering for theÁüÎv[X read-modify-write operation that takes place if the comparison with `current` succeeds.Áü®wZW `failure` describes the required ordering for the load operation that takes place whenÁüxRO the comparison fails. Using `Acquire` as success ordering makes the store partÁüäxNK of this operation `Relaxed`, and using `Release` makes the successful loadÁü·yPM `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed`ÁüŒzB? and must be equivalent to or weaker than the success ordering.ÁÓzútÛzÖÛîzú<öz©¼ü‚{@= use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared};ÁüÇ{,·åø{úô€|¼Ü£|úô«|…æüÎ|%" let curr = a.load(SeqCst, guard);Áüø|OL let res1 = a.compare_exchange(curr, Shared::null(), SeqCst, SeqCst, guard);ÁüÌ}QN let res2 = a.compare_exchange(curr, Owned::new(5678), SeqCst, SeqCst, guard);Áü¢~74 # unsafe { drop(curr.into_owned()); } // avoid leakÁ<Þ~©¼„ñ~Šùú ùÿFüüÃÿËÖDe—è­×úÅDÉõ™E™E ŠQÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
üüÃÿËÖDe—è­×ŠÅD004²5æ `::+d¼þŠÅDÉõ{¡{õõ †öTé€
ÅDÉõ$“²æ ÁüŠ ‡€TVLN<closure_kind>ÁŒ<closure_signature>ÁŒ<upvars>ÁŒŒŒÅDÉõÃ`üüÃÿËÖDe—è­×ÅD Ã`Lʂ쌣ÅDÉõÔŽ004²5æ `::+d¼þÅDÉõ˜üÝ—ü—„`¢ûüü„^Œüüß…Gôü«†úü³†_\ Unlike [`compare_exchange`], this method is allowed to spuriously fail even when comparisonÁü—‡_\ succeeds, which can result in more efficient code on some platforms. The return value is aÁüû‡ZW result indicating whether the new pointer was written. On success the pointer that wasÁüÚˆTQ written is returned. On failure the actual current value and `new` are returned.Á³‰úü»‰EÁÿü…ŠQüÛŠ[ë€ü»‹ZÐüšŒR´‚üñŒNƒüÄPèƒü™ŽB„àŽúüèŽ2/ [`compare_exchange`]: Atomic::compare_exchangeÁŸúÖÛºú©¼üÎ@À…ü“,·åÄúô̼Üôï…æ’‘úüš‘# let mut new = Owned::new(5678);Áü‘(% let mut ptr = a.load(SeqCst, guard);Áüï‘HE # unsafe { drop(a.load(SeqCst, guard).into_owned()); } // avoid leakÁT¼’ loop {ÁüË’HE match a.compare_exchange_weak(ptr, new, SeqCst, SeqCst, guard) {Á´˜“ Ok(p) => {Áij“ ptr = p;Á´Ð“ break;Álë“
Ìý“ Err(err) => {Áü›”" ptr = err.current;Áô” new = err.new;Álå”ü˜L÷”,…•úü—•)& let mut curr = a.load(SeqCst, guard);ÁTÅ•³—üÔ•TQ match a.compare_exchange_weak(curr, Shared::null(), SeqCst, SeqCst, guard) {ÁÜ­ Ok(_) => break,ÁüÍ–+( Err(err) => curr = err.current,ÁLý–™š,‹—¬šü•—7­ˆ<Ñ—©¼¬ä—ûü ûÿFüüÃÿËÖDe—è­×üÅDÉõ™E™E QÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
üüÃÿËÖDe—è­×ÅD004²5æ `::+d¼þÅDÉõ{¡ú—{õõ þ—†öTá™
ŽÅDÉõ$‹˜²<™˜æ ¹˜ü<ɘŠ<ä˜ ÿ˜[]RTŠ›ŽìŒ£ŽÅDÉõÑŽ˜LÇ›ŽìŒ£ŽÅDÉõý˜üì«ü”TQ Fetches the pointer, and then applies a function to it that returns a new value.Áüí^[ Returns a `Result` of `Ok(previous_value)` if the function returned `Some`, else `Err(_)`.ÁОúüØž^[ Note that the given function may be called multiple times if the value has been changed byÁü»Ÿ^[ other threads in the meantime, as long as the function returns `Some(_)`, but the functionÁüž 96 will have been applied only once to the stored value.ÁÜ úüä JG `fetch_update` takes two [`Ordering`] arguments to describe the memoryÁü³¡MJ ordering of this operation. The first describes the required ordering forÁü…¢FC when the operation finally succeeds while the second describes theÁüТLI required ordering for loads. These correspond to the success and failureÁü¡£;8 orderings of [`Atomic::compare_exchange`] respectively.Áá£úüé£FC Using [`Acquire`] as success ordering makes the store part of thisÁü´¤KH operation [`Relaxed`], and using [`Release`] makes the final successfulÁü„¥HE load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],ÁüÑ¥KH [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than theÁ¬¡¦ success ordering.Á»¦úüæ" [`Relaxed`]: Ordering::RelaxedÁüê¦" [`Acquire`]: Ordering::AcquireÁü‘§" [`Release`]: Ordering::ReleaseÁü¸§  [`SeqCst`]: Ordering::SeqCstÁݧútå§ÖÛø§ú<€¨©¼üŒ¨1üäü¨,·åó¨úôû¨¼Üôž©…æÁ©úüÉ©NK let res1 = a.fetch_update(SeqCst, SeqCst, guard, |x| Some(x.with_tag(1)));ÁÔœª assert!(res1.is_ok());Á»ªúüê?< let res2 = a.fetch_update(SeqCst, SeqCst, guard, |x| None);Á܇« assert!(res2.is_err());Áü§«4äÜ<à«©¼dó«ý ýÿF™E™E ë
QÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
üüÃÿËÖDe—è­×ë
ÅD¥³{ë
 ¬{ÍìÒ² „¬“"Ò²¥³üÄ­-Ò²·´˜"Û¼ݼÞ¼©ß¼à¼ÛἈcSñŸ«‡zÙ¥³¬Ü­
ÅDë
Ò²$‘¬ set_orderÁLŸ¬
fail_orderÁT¼¬£,Ú¬funcÁ$ø¬€¬ÖØü¯¾ŠüÔ°`¢ûü¹±^Œüüœ²Gôüè²úüð²_ÑýüÔ³[ºþl´´žÿÆ´úüδUR This method takes a [`CompareAndSetOrdering`] argument which describes the memoryÁü¨µ ordering of this operation.Á̵úüÔµ%" # Migrating to `compare_exchange`Áþµúü†¶XU `compare_and_set` is equivalent to `compare_exchange` with the following mapping forÁ¬ã¶ memory orderings:Áý¶úü…·  Original | Success | FailureÁüª·  -------- | ------- | -------ÁüÏ·  Relaxed | Relaxed | RelaxedÁüô·  Acquire | Acquire | AcquireÁü™¸  Release | Release | RelaxedÁü¾¸  AcqRel | AcqRel | AcquireÁü㸠SeqCst | SeqCst | SeqCstÁ‡¹út¹ÖÛ¢¹ú<ª¹©¼ܶ¹ # #![allow(deprecated)]ÁüÖ¹@À…ü›º,·å̺úôÔº¼Ü÷ºúôÿº…æü¢»%ʆüÌ»FC let res1 = a.compare_and_set(curr, Shared::null(), SeqCst, guard);Áü—¼HE let res2 = a.compare_and_set(curr, Owned::new(5678), SeqCst, guard);Áüä¼7­ˆ< ½©¼Use `compare_exchange` insteadÁüˆ¾ üô½6|¶¾–¾,þÿ þÿFüüÃÿËÖDe—è­×ÿÅDE  QÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
üüÃÿËÖDe—è­×ÅD004²5æ `::+d¼þÅDE{ ˜¡˜ƾ{ÍìÊÀ ʾ ;:ÊÀ¬ŒÀÂEÅDT®À
ÅDÊÀE$Ú¾²<è¾æ ˆ¿«š˜¿£,¨¿ƒqsuwü˜ÕüœÁ`¢ûüÂ^ŒüüäÂGôü°Ãúü¸Ã^[ Unlike [`compare_and_set`], this method is allowed to spuriously fail even when comparisonÁü›Ä_ùüÿÄZã‘üÞÅTÈ’·Æúü¿ÆUü™Çï¶½ÇúüÅÇ0- [`compare_and_set`]: Atomic::compare_and_setÁúÇúü‚È*' # Migrating to `compare_exchange_weak`Á±Èúü¹Èb_ `compare_and_set_weak` is equivalent to `compare_exchange_weak` with the following mapping forÁ¬ ÉŸºÉúüÂÉ ò¸üçÉ ¹üŒÊ ȹü±Ê ó¹üÖÊ žºüûÊ ɺü ËôºÄËútÌËÖÛßËú<çË©¼ÜóËÓ»ü“Ì@À…üØÌ,·å‰Íúô‘ͼÜô´Í…æ×ÍúüßÍ#€–ü‡Î(®–ü´ÎHá–Tϳ—üÏ?< match a.compare_and_set_weak(ptr, new, SeqCst, guard) {Á´ÔÏš˜ÄïϺ˜´ŒÐܘl§Ðü˜̹Г™ü×Ð"·™ôþÐã™l¡Ñü˜L³Ñ™š,ÁѬšËÑúüÓÑ)ÉšTÒ³—üÒKH match a.compare_and_set_weak(curr, Shared::null(), SeqCst, guard) {ÁÜàÒé›ü€Ó+œL°Ó™š,¾Ó¬šüÈÓ7­ˆ<„Ô©¼#Use `compare_exchange_weak` insteadÁüìÔ%üØÔ;¤ŸÕ„Í, ÿFüüÃÿËÖDe—è­×ÅDEÊÀ QÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
üüÃÿËÖDe—è­×ÅD004²5æ `::+d¼þÅDE{ œ¡œ´Õ{Þ ¸Õ »Õù¬úÖ‰ÃTœ×
šÅDÊÀE$ÈÕ²<ÖÕæ öÕ«š†Ö£,–Öik`bdfüãÝUüØ'$ Bitwise "and" with the current tag.Á»ØúüÃØ^[ Performs a bitwise "and" operation on the current tag and the argument `val`, and sets theÁü¦Ù85 new tag to the result. Returns the previous pointer.ÁãÙúüëÙZÏãtÊÚ²äÝÚútåÚÖÛøÚú<€Û©¼üŒÛ9ª÷üÊÛ,·åûÛúü
 `£c—¢ `àB¤GS
¾£¦ ß‚¦
¨ÅD$à‚± æ‚üü„6¥ªª„³ ”³LÿF«Ïc«ü¹…8¼…ˆŠ ˆÿF  c cˆ¢cµ
 `£c—¢ `àB¤GS
о£© À…©
«ÅD$Á…± Ç…ü•‡/¥­­„³ š‡”³L¦‡ÿF®Ù®¼úˆüˇ'$ Returns a copy of the atomic value.Á÷‡úüÿ‡[X Note that a `Relaxed` load is used here. If you need synchronization, use it with otherÁ´ßˆ atomics or fences.Á,ýˆ ÿFÿF¬ ƒ‰¬
®ÅD$„‰üô‰1¥°°„³ ù‰”³L…ŠÿF±´±¤¬Š<¯ŠÿF¯¯
±ÅDüãŠ8¥³³„³ 芔³LôŠÿF´ë´ü½ ü¢‹52 Returns a new atomic pointer pointing to `owned`.ÁÜ‹útä‹ÖÛ÷‹ú<ÿ‹©¼ü‹Œ)& use crossbeam_epoch::{Atomic, Owned};Á¹ŒúüÁŒ2/ let a = Atomic::<i32>::from(Owned::new(1234));ÁüøŒ4äÜ©¼ñGÿF²²
´ÅDownedÁ,ÅüÃŽ"¥Ç‘ ÈŽÿF·ë·ÔìŽ$HÿFµµ
·ÅD­ ôŽìµ¥¹¹Ç‘ ºÿFºëº¬ÙÅDÿF¸¸
ºÅD¿ áüAë
¼¥½½¼ïž ˜‡Ÿ´I¾ë¾#%ü½’#ü×30 Returns a new atomic pointer pointing to `ptr`.Áút—‘ÖÛª‘ú<²‘©¼ü¾‘*' use crossbeam_epoch::{Atomic, Shared};Áí‘úüõ‘74 let a = Atomic::<i32>::from(Shared::<i32>::null());Á<±’©¼$À’êI´I»»
¾ë
‡Eµ Å’ü$¥ÀÀÇ‘ ”“ÿFÁëÁô©•üº“30 Returns a new atomic pointer pointing to `raw`.Áò“útú“ÖÛú<•”©¼Œ¡” use std::ptr;Áü·” ‡ÜÜ”úüä”41 let a = Atomic::<i32>::from(ptr::null::<i32>());Á<©¼$¬•µJÿF¿¿
ÁÅD@±•ü¯–(üú•41 A trait for either `Owned` or `Shared` pointers.Á<¹–Â¥ÃÂÃÄ«ü¯–Ìïž Á–‡ŸLÍ–ÂÄ«-Ä«ÅÄÅÅÄ=?ì™—üÞ–63 Returns the machine representation of the pointer.ÁTœ—Ì«Ã`ÂÂ
ÄÌ«‡E$§—üÏ™*ü¼—@= Returns a new pointer pointing to the tagged pointer `data`.Á˜úd‰˜³Àš˜úü¢˜_\ The given `data` should have been created by `Pointer::into_usize()`, and one `data` shouldÁü†™DA not be converted back by `Pointer::from_usize()` multiple times.ÁTÙ™Ã`Ì«ÂÂ
ÅÌ«‡EË$ä™üâ›'üý™# An owned heap-allocated object.Á¡šúü¥š*' This type is very similar to `Box<T>`.ÁКúüÔšb˜Ôü·›*' least significant bits of the address.Á,훥ÇÇ„³ ó›”³Lÿ›ñG$zF–Е5ÉÈÉÜ,.\œ$œÆÆÃ`䡜<¡œÆÆ€cFu\»Ÿ¶Hüœ3¥ËË„³ Çœ”³LÓœñGÌÍÄÅÌÍ')äŠTñGÃ`ÊÊ
ÌÅDü Ÿ)üú@¨‹¿žúdÇž³åØžúüàž-* Panics if the data is zero in debug mode.ÁTªŸÃ`ñGÊÊ
ÍÅDË$µŸ„å ¥ÏÏÇ‘ ê ñGÐÑÒüÚ¦/üü 2/ Returns a new owned pointer pointing to `raw`.Á³¡úü»¡\Y This function is unsafe because improper use may lead to memory problems. Argument `raw`Áüœ¢]Z must be a valid pointer. Also, a double-free may occur if the function is called twice onÁÌþ¢ the same raw pointer.Áœ£úd¤£³åµ£úü½£,) Panics if `raw` is not properly aligned.Áî£údö£³À‡¤úü
 `£c—¢ `àB¤GS
¾£Ý ½Ý
ßÅD$‚½± ˆ½üí¾!¥ááÇ‘ ò¾ØÅD,õ¾ñGâÙâ#%¼•¿,˜¿ ñGñGà ž¿à
âÅD$Ÿ¿üò¿.¥ä䄳 ÷¿”³LƒÀñGåæê!ë!æ#%\§À4¬ÀããÅD¬½À,ÀÀ ñG ÅDã ÆÀã
æÅD$ÇÀüµÁ1¥è脳 ºÁ”³LÆÁñGé÷!éüíÁ!LðÁ ñG ÅDç úÁç
éÅD$ÿÁäõÂ¥ëëÇ‘ úÂñGìë쬘Ã$›ÃÅDñGêê
ìÅD¿  ÃüÏÃ!¥îîÇ‘ ÔÃñGïëïÔÂÆü÷Ã0- Returns a new owned pointer pointing to `b`.Á¬Äúd´Ä³åÅÄúüÍÄ>; Panics if the pointer (the `Box`) is not properly aligned.ÁÅút˜ÅÖÛ«Åú<³Å©¼ü¿Åá¼ãÅúüëÅFò™<¶Æ©¼$ÅÆ¶HñGíí
ïÅD­ ÊÆüœÇ2¥ññ„³ ¡Ç”³L­ÇñGò¢ò´ÕÇ4ØÇ ñG ÅDð ßÇð
òÅD$àÇüŒÈ5¥ôô„³ ‘È”³LÈñGõ¥õüÈÈ"TËÈ ñG ÅDó ÖÈó
õÅD$ÛÈüÉ1¥÷÷„³ ”É”³L ÉñGøâø´ÇÉ4ÊÉ ñG ÅDö ÑÉö
øÅD$ÒÉüþÉ1¥úú„³ ƒÊ”³LÊñGûåûô¶Ê4¹Ê ñG ÅDù ÀÊù
ûÅD$ÅÊü…Í1üùÊ52 A pointer to an object protected by the epoch GC.Á¯Ëúü³Ë?< The pointer is valid for use only during the lifetime `'g`.ÁóËúü÷Ëb˜ÔüÚÌ*®4Íë
ý¥þýþïž ›Í§Ÿ0O‡ŸL¬ÍêIDe—è­×ÿ—Í79ý\½Í$½ÍüüÃ`üÎÍ(<ÎÍüü€cFu\»Ÿ ë
e¯LüûÍ38˜¥˜ïž €Î‡ŸLŒÎÎKƒÙƒ¼µÎ,¸Î ÎKÎK ¾Î
ƒ8‡E$¿ÎüæÎ28š¥šïž ë·ŸL÷ÎÎKüÏ88¥ïž ¢Ï‡ŸL®ÏÎKˆÄň')äêÏTíÏÎKÃ`
ˆ8‡E$øÏü´Ð)T¾ÐÃ`ÎK
8‡EË$ÉÐ̸Ñë
¥ŒŒòœ ÁÑêI½ÑüàÕ üØÑ<9 Converts the pointer to a raw pointer (without the tag).Á™Òút¡ÒÖÛ´Òú<¼Ò©¼üÈÒ85 use crossbeam_epoch::{self as epoch, Atomic, Owned};Áü…Ó,·å¶Óúì¾Ó œôàÓ let raw = &*o as *const _;ÁäƒÔ let a = Atomic::from(o);Á¤Ôúô¬Ô…æüÏÔ"­æüöÔ  assert_eq!(p.as_raw(), raw);Áü›Õ4äÜ<ÔÕ©¼4çÕœ œêI¯LŠ îÕŠ
ë
‡E$ïÕüÚÖ-ë
¥ïž ãÖ‡ŸLïÖêI‘˜ßÖ35ôߨüŽ× Returns a new null pointer.Á²×útº×ÖÛÍ×ú<Õש¼üá×  use crossbeam_epoch::Shared;Á†ØúüŽØ" let p = Shared::<i32>::null();Á̵Ø assert!(p.is_null());Á<ÓØ©¼$æØêIŽŽ
ë
‡EìÉÝüÝÙ*' Returns `true` if the pointer is null.ÁŒÚút”ÚÖÛ§Úú<¯Ú©¼ü»Ú8ÈÆüøÚ,·å©ÛúܱÛ let a = Atomic::null();ÁôÑÛ…æ
,ä›ü¥œ08¦¥¢¦¢ïž ªœ‡ŸL¶œÎKüÚœKë
¤¥¥¤¥ïž 㜇ŸLïœêI¦ïߦߜ$&ü¬<§¨ §êI ¨êIÛ¼ݼÞ¼©ß¼à¼ÛἈcSñŸ«‡zÙ¿ßÀßÁßLessÁÂßÃßÄß~Å߯ßÇßGreaterÁÈßåºÝÈnûê7£ »£
¦ë
‡E¹
üŸž18©¥¨©¨ïž ¤ž‡ŸL°žÎK©»©üמ,Úžª« ªÎK «ÎK׃§ Þž§
©8‡E$ßž¹
,åžü²Ÿ88¬¥««¬ïž ·Ÿ‡ŸLßÎK¬Àc¬üñŸ8ôŸ­®¯ ­ÎK ® c cˆ¢cµ
 `£c—¢ `àB¤GS
¯¾£ª øŸª
¬8‡E$ùŸ± ÿŸüå¡:8°¥®°®ïž ꡇŸLö¡ÎK¯Ïc¯ü¦¢8©¢±²³ ±ÎK ² c cˆ¢cµ
 `£c—¢ `àB¤GS
³¾£­ ­¢­
¯8‡E$®¢± ´¢üÒ£58´¥±´±ïž ×£‡ŸLã£ÎK²´²¤Ž¤<‘¤ÎK°°
²8‡El‘,»¤Œá+óµ Ìô+üà+.ü×+9L•,ºÊ׳ `³´—$,˳µÕ)4èâ³·ß*,ðí³¸K†J³¹L­lœ½]|ÖNP=?Üü1¤Àüš%" An epoch-based garbage collector.ÁŠMÉÈ\Ácä»ôÛºº†J†JK‰Jµ 7ŠJphantomÁ7J¤7·0ØQdèââÕ)ãã)¬äñ)¬åÅ"ÏÝJv»&úHôþŠMô ŠMÔÊM¿´¿¤äŠM¾¾
¿ŠMÁ¤€äß Creates a new collector.ÁŠMÀÀ
Áüì%üº-* Registers a new handle for the collector.ÁDóµ µŠMþMÀ üÀ
ÂÄ»ŠMÄÙļ›üÚ<9 Creates another reference to the same garbage collector.Á,ž ŠMŠMà ¤Ã
Äì… ŠMÆÀcÆü© 8¬ ·¸¹ ·ŠM ¸ c cˆ¢cµ
 `£c—¢ `àB¤GS
¹¾£Å ° Å
Ʊ · ä
ŠMÈ·ßÈüî
%ü²
74 Checks if both handles point to the same collector.Áñ
º» ºŠM »ŠMÇ ô
Ç
È
rhsÁû
¬Í ŠM´Œ üç $! A handle to a garbage collector.Á\— þMD_ú6xƒgtËÑô©  ÊÊ€r„Ì þMÍÎÏÔŠ
¤ã  Pins the handle.Á
¼ ¼þMQÌ
Ì
Í$
ü—üÙ
+( Returns `true` if the handle is pinned.ÁLž½ ½þMÌ ¨Ì
Îü¼%üñ85 Returns the `Collector` associated with this handle.ÁLþ ¾þM ¾ŠMÌ ÍÌ
ÏÌšþMÑ"єȿ ¿þMeÐ ÐÐ
Ñü²þMÓÀcÓüØ8ÛÀÁ ÀþM Á c cˆ¢cµ
 `£c—¢ `àB¤GS
¾£Ò ßÒ
Ó± ædÚ,»¤Œª,óµ ̽,ü©,.ü ,9DÞ,ÜÝßÄGÔÕ×! `ÔÖ€c\8Ô×€cÔ×í$UëÔÙ±E\[ÑÛÔÚµ sÔÛŒŽLÌ*pLILO=?Lm/¼ôÔÃ`LËÔÃ`ÞÃ`Ô•¼NÌ¡÷—ì=àáâĶÔß߉e¼ÔÔßßÑÛÑÛ±EÓÛÆEÝÔÛ»ÝÍõƒ«%9— ìñÔßß“g䤼NäÀcäüÇCÊÃÄŠüN Ä c cˆ¢cµ
 `£c—¢ `àB¤GS
ž£ã Îã
ä± Õ¼NæèîäËåå¼NäôÔŒee„e_rawÁ$üÙ ,ç ¼NåééåÍìϤ ë –"ϤeϤe˜"e
èϤ± ø ;=üÍ )$× ÔŒeeëë÷¤ Ü ˆ¥ ›¥
êϤ@é "$üÊ)ÔŒeeíí÷¤ Ùˆ¥›¥
ìϤ@æ"$äì¼Neåå
îL¢-»¤Œò,óµ Ì…-üñ,.üè,9,¦-ñò󹪮D’¼Àïðüò(¤·ó Äœü– ï¤]¤]V¦]Á‚]üß3ø¤”&t„ó Äéüã L‰ï¤ùó ÄÞüØ ï ‰Oõö÷øùúüÏ

‰Oôô
õü†>d”‰O‰Oôô
ö‹–§üÛ%‰Oôô
÷üï#‰O‰Oôô
ø$„ü¡%‰O‰Oôô
ù$¸ü¥&‰O‰Oôô
ú„£‰Püýþÿüì'ú‰O‰Pûû
üÅ",þü§1Æ Æ‰P™E‰Oû ºû
ý«šÁüã7Ç Ç‰P‰O™Eeû ÷û
þÅ",þ«šŒü¬'®„º'È È‰P‰O‰O™E™EÖ¿Ù¿Ú¿«Û¿ˆÜ¿Ý¿Þ¿ˆ‚†f|Â
‰O‰Oû Ô'û
ÿ$Õ'²<ã'æ û'ü<(Š<ª(Lç-»¤Œ·-óµ ÌÊ-ü¶-.ü­-9,ë-¦×
 `í
ë¢L3
KÃ4>
üL]
ºµ!D}
ßß*,œ
íˆL
ŒL
}l#
np_aÜK
RÌl
C´‹
5„‚
ü¤1
. A guard that keeps the current thread pinned.ÁÖ
ú
Œƒè
úüìO
L The current thread is pinned by calling [`pin`], which returns a new guard:Á¼
ú
©¼üÈ!
 use crossbeam_epoch as epoch;Áê
úüîb
_ // It is often convenient to prefix a call to `pin` with a `&` in order to create a reference.矄\
Y // This is not really necessary, but makes passing references to the guard a bit easier.Áô®
…æ
©¼Õ
úüÙL
I When a guard gets dropped, the current thread is automatically unpinned.Á¦
úܪ
 # Pointers on the stackÁÆ
úüÊW
T Having a guard allows us to create pointers on the stack to heap-allocated objects.Á„¢
For example:Á³
ú
©¼ü¿1
üäüñ,
·åž
úü¢&
# // Create a heap-allocated number.瓃
 let a = Atomic::new(777);Áç
úôë
 // Pin the current thread.ÁôŠ
…æ©
úü­J
G // Load the heap-allocated object and create pointer `p` on the stack.Áüø"
­æ
úüŸ 3
0 // Dereference the pointer and print the value:ÁüÓ .
+ if let Some(num) = unsafe { p.as_ref() } {Áü‚
+
( println!("The number is {}.", num);Á
¬šü´
4
äÜ
©¼ñ
ú¬õ
 # Multiple guardsÁ
úü _
\ Pinning is reentrant and it is perfectly legal to create multiple guards. In that case, theÁüï b
_ thread will actually be pinned only when the first guard is created and unpinned when the lastÁœÒ
 one is dropped:Áæ
ú
©¼üò !
Û³
úô˜
 let guard1 = epoch::pin();Áô·
 let guard2 = epoch::pin();ÁüÖ
 assert!(epoch::is_pinned());ÁŒ÷
 drop(guard1);Áü‰
ῌª
 drop(guard2);Áü¼!
 assert!(!epoch::is_pinned());Á
©¼æ
ú¼ê
 [`pin`]: super::pinÁ,
Qþšl{ÈÅ0Š£ô™

€rT¼
˜ üÚ^
üÍY
V Stores a function so that it can be executed at some point after all currently pinnedÁÌ«
 threads get unpinned.ÁÉ
úüÑ]
Z This method first stores `f` into the thread-local (or handle-local) cache. If this cacheÁü³X
U becomes full, some functions are moved into the global cache. At the same time, someÁüZ
W functions from both local and global caches may get executed in order to incrementallyÁüï(
% clean up the caches as they fill up.Áœ
úü¤Z
W There is no guarantee when exactly `f` will be executed. The only guarantee is that itÁüƒ[
X won't be executed until all currently pinned threads get unpinned. In theory, `f` mightÁüãW
T never run, but the epoch-based garbage collection will make an effort to execute itÁ¤¿
 reasonably soon.ÁØ
úüàW
T If this method is called from an [`unprotected`] guard, the function will simply beÁ̼
 executed immediately.Á,á
É ÉQϤe£ŽŽ í
÷¤ ç
œ“ ê
ˆ¥l
Ϥe˜"é’ 
ÌìϤ
Ϥ
ŒϤé’
± ô
bdgiüÝ8T
üŠY
 ÂÌè
‚Ã
úüŽ]
±ÃüðX
˜ÄüÍZ
úÄü¬(
ÞÅÙ
úüáZ
œÆüÀ[
€Çü W
åǤü
ÅÈ
úüW
ïÈÌù
ÏÉ
ú
³À°
úü¸\
Y The given function must not hold reference onto the stack. It is highly recommended thatÁü™ W
T the passed function is **always** marked with `move` in order to prevent accidentalÁ
borrows.Á†!
ú<Ž!
©¼üš!!
Û³À!
úôÈ!
…æÜë!
 let message = "Hello!";Ád"
ÙØüœ"K
H // ALWAYS use `move` when sending a closure into `defer_unchecked`.Áüì"'
$ guard.defer_unchecked(move || {Áü˜#$
! println!("{}", message);Á\Á#
 });Á,Ñ#
¬š<Û#
©¼ç#
úüï#^
[ Apart from that, keep in mind that another thread may execute `f`, so anything accessed byÁüÒ$
 the closure must be `Send`.Áö$
úüþ$_
\ We intentionally didn't require `F: Send`, because Rust's type systems usually cannot proveÁüâ%\
Y `F: Send` for typical use cases. For example, consider the following code snippet, whichÁüÃ&Y
V exemplifies the typical use case of deferring the deallocation of a shared reference:Á¡'
úl©'
```ignoreÁü»'5
2 let shared = Owned::new(7i32).into_shared(guard);Áüõ'R
O guard.defer_unchecked(move || shared.into_owned()); // `Shared` is not `Send`!Á<Ì(
©¼Ø(
úüà(]
Z While `Shared` is not `Send`, it's safe for another thread to call the deferred function,ÁüÂ)_
\ because it's called only after the grace period and `shared` is no longer shared with otherÁü¦*<
9 threads. But we don't expect type systems to prove this.Áç*
útï*
ÖÛ+
úüŠ+V
S When a heap-allocated object in a data structure becomes unreachable, it has to beÁüå+^
[ deallocated. However, the current thread and other threads may be still holding referencesÁüÈ,`
] on the stack to that same object. Therefore it cannot be deallocated before those referencesÁü­-\
Y get dropped. This method can defer deallocation until all those threads get unpinned andÁüŽ.8
5 consequently drop all their references on the stack.ÁË.
ú<Ó.
©¼üß.8
ÈÆüœ/,
·åÍ/
úüÕ/
 let a = Atomic::new("foo");Áù/
úü0M
J // Now suppose that `a` is shared among multiple threads and concurrentlyÁüÓ0
 // accessed and modified...Á÷0
úôÿ0
¸¹ô¢1
…æÅ1
úüÍ1M
J // Steal the object currently stored in `a` and swap it with another one.ÁüŸ2H
E let p = a.swap(Owned::new("bar").into_shared(guard), SeqCst, guard);Áì2
ú¬ô2
 if !p.is_null() {ÁüŽ3<
9 // The object `p` is pointing to is now unreachable.ÁüÏ3R
O // Defer its deallocation until all currently pinned threads get unpinned.Á„¦4
unsafe {Áü»4O
L // ALWAYS use `move` when sending a closure into `defer_unchecked`.Áü5+
( guard.defer_unchecked(move || {Áü¿5D
A println!("{} is now being deallocated.", p.deref());Áüˆ6\
Y // Now we have unique access to the object pointed to by `p` and can turn itÁüé6T
Q // into an `Owned`. Dropping the `Owned` will deallocate the object.ÁüÂ7%
" drop(p.into_owned());Á|ì7
});ÁL€8
™š,Ž8
¬šü˜84
äÜ<Ñ8
©¼|ë8
Ê ÊQϤe£ 9
÷¤ û8
œ“ þ8
ˆ¥l£9
åË ¯9
Ϥé’$9
± ˆ9
8:=?<:
쌣Ϥé’eeϤü¨UM
üé:]
Z Stores a destructor for an object so that it can be deallocated and dropped at some pointÁüË;4
1 after all currently pinned threads get unpinned.Á„<
úüŒ<]
Z This method first stores the destructor into the thread-local (or handle-local) cache. IfÁüî<Z
W this cache becomes full, some destructors are moved into the global cache. At the sameÁüÍ=Y
V time, some destructors from both local and global caches may get executed in order toÁü«>6
3 incrementally clean up the caches as they fill up.Áæ>
úüî>]
Z There is no guarantee when exactly the destructor will be executed. The only guarantee isÁüÐ?]
Z that it won't be executed until all currently pinned threads get unpinned. In theory, theÁü²@]
Z destructor might never run, but the epoch-based garbage collection will make an effort toÁü”A
 execute it reasonably soon.Á¸A
úüÀAY
V If this method is called from an [`unprotected`] guard, the destructor will simply beÁÌžB
ÏɼB
údÄB
³ÀÕB
úüÝB]
Z The object must not be reachable by other threads anymore, otherwise it might be still inÁü¿C!
 use when the destructor runs.ÁåC
úüíC_
\ Apart from that, keep in mind that another thread may execute the destructor, so the object矄D&
# must be sendable to other threads.ÁüD
úü„E_
\ We intentionally didn't require `T: Send`, because Rust's type systems usually cannot proveÁüèE\
Y `T: Send` for typical use cases. For example, consider the following code snippet, which矃FY
ñÔ§G
úl¯G
ßÕüÁG5
öÕüûG;
8 guard.defer_destroy(shared); // `Shared` is not `Send`!Á<»H
©¼ÇH
úüÏH^
[ While `Shared` is not `Send`, it's safe for another thread to call the destructor, becauseÁü²IW
T it's called only after the grace period and `shared` is no longer shared with otherÁüŽJ<
úØÏJ
út×J
ÖÛêJ
úüòJV
åÙüÍK^
ÅÚü°L`
­Ûü•M\
—ÜüöM8
ýܳN
ú<»N
©¼üÇN8
ÈÆü„O,
·åµO
úü½O
€ÞáO
úüéOM
µÞü»P
ŒßßP
úôçP
¸¹ôŠQ
…æ­Q
úüµQM
çßü‡RH
¾àÔR
ú¬ÜR
›áüöR<
ºáü·SR
€â„ŽT
󉟣T#
guard.defer_destroy(p);ÁLËT
™š,ÙT
¬šüãT4
äÜ<œU
©¼l¶U
ËÌ ËQüüÃÿËÖDe—è­×ÌÅDe¥ ÛU
„³ ÄU
”³LÐU
ÅD$ÜU
µ âU
#%<•V
쌣ÅDeñGØŽœÂ\
ü»V_
\ Clears up the thread-local cache of deferred functions by executing them or moving into theÁŒŸW
 global cache.ÁµW
úü½W^
[ Call this method after deferring execution of a function if you want to get it executed asÁü XY
V soon as possible. Flushing will make sure it is residing in the global cache, so thatÁüþXD
A any thread has a chance of taking the function and executing it.ÁÇY
úüÏY\
Y If this method is called from an [`unprotected`] guard, it is a no-op (nothing happens).Á°Z
út¸Z
ÖÛËZ
ú<ÓZ
©¼üßZ!
Û³…[
úô[
…æ̰[
 guard.defer(move || {ÁüÎ[@
= println!("This better be printed as soon as possible!");Á<“\
 });Á”Ÿ\
 guard.flush();Á<¶\
©¼,É\
Í ÍQe Ï\

$Ð\
¼Šf
üÊ]3
0 Unpins and then immediately re-pins the thread.Á^
úüŠ^Z
W This method is useful when you don't want delay the advancement of the global epoch byÁüé^^
[ holding an old epoch. For safety, you should not maintain any guard-based reference acrossÁüÌ_^
[ the call (the latter is enforced by `&mut self`). The thread will only be repinned if thisÁü¯`4
1 is the only active guard for the current thread.Áè`
úüð`]
Z If this method is called from an [`unprotected`] guard, then the call will be just no-op.ÁÒa
útÚa
ÖÛía
ú<õa
©¼üb1
üäü·b,
·åèb
úìðb
†¹ü’c!
 let mut guard = epoch::pin();Á,¸c
üÂc'
$ let p = a.load(SeqCst, &guard);Áüîc6
3 assert_eq!(unsafe { p.as_ref() }, Some(&777));Á,©d
¬š”³d
 guard.repin();Á,Êd
œ‹üÔd'
«‹ü€e6
Ü‹,»e
¬šüÅe4
äÜ<þe
©¼,f
Î ÎQe —f

$œf
ü÷pR
ü’g[
X Temporarily unpins the thread, executes the given function and then re-pins the thread.Áòg
úüúg[
X This method is useful when you need to perform a long-running operation (e.g. sleeping)ÁüÚh`
] and don't need to maintain any guard-based reference across the call (the latter is enforcedÁü¿i^
[ by `&mut self`). The thread will only be unpinned if this is the only active guard for theÁœ¢j
 current thread.Áºj
úüÂj^
[ If this method is called from an [`unprotected`] guard, then the passed function is called矴k*
' directly without unpinning the thread.ÁÔk
útÜk
ÖÛïk
ú<÷k
©¼üƒl1
üäü¹l,
·å¤êl
 use std::thread;Áäƒm
 use std::time::Duration;Á¤m
úì¬m
†¹üÎm!
òŠ,ôm
œ‹üþm'
«‹üªn6
Ü‹,ån
¬šüïnC
@ guard.repin_after(|| thread::sleep(Duration::from_millis(50)));Á,·o
œ‹üÁo'
«‹üío6
Ü‹,¨p
¬šü²p4
äÜ<ëp
©¼\þp
Ï ÏQϤé’£šš q
÷¤ Šq
œ“ q
ˆ¥l»q
åË Çq
˜Ϥé’$•q
± q
8:=?L8T¤r
ÈPÊ=*‘K”©œ€rÈPŸL89€rÈP
œd¯r
€rÄÆr
ÈPŸ"Ÿ”ír
$ðr
Ð ÐÈPež õr
ž
Ÿ$úr
ü {-
üŠw7
4 Returns the `Collector` associated with this guard.ÁÆw
úüÎwK
H This method is useful when you need to ensure that all guards used withÁüžx2
/ a data structure come from the same collector.ÁÕx
úüÝxT
Q If this method is called from an [`unprotected`] guard, then `None` is returned.Á¶y
út¾y
ÖÛÑy
ú<Ùy
©¼üåy!
Û³z
úô“z
’¿ô¶z
¹¿üÙz6
3 assert!(guard1.collector() == guard2.collector());Á<”{
©¼L§{
Ñ ÑQÛ¼ݼÞ¼©ß¼à¼ÛἈcSñŸ«‡zÙ ÑŠM ±{

 $²{
<ù{
 ìŒ¡¡£¡¡ ¡ ­S ŠMeœŸ|
"£”Ç|
$Ê|
Ò ÒQe¢ Ï|
¢
£$Ô|
ÌÈ}
Àc¥üè}8
ë}
ÓÔÕ ÓQ Ô c cˆ¢cµ
 `£c—¢ `àB¤GS
Õ¾£¤ ï}
¤
¥$ð}
± ö}
üœ•-
üÊ~W
T Returns a reference to a dummy guard that allows unprotected access to [`Atomic`]s.Á¢
úü¦_
\ This guard should be used in special occasions only. Note that it doesn't actually keep anyÁü†€Y
V thread pinned - it's just a fake guard that allows loading from [`Atomic`]s unsafely.Áà€
úüä€]
Z Note that calling [`defer`] with a dummy guard will not defer the function - it will justÁüÂ%
" execute the function immediately.Áè
úüì`
] If necessary, it's possible to create more dummy guards by cloning: `unprotected().clone()`.ÁÍ‚
údÑ‚
³ÀÞ‚
úüâ‚Z
W Loading and dereferencing data from an [`Atomic`] using this guard is safe only if theÁü½ƒC
@ [`Atomic`] is not being concurrently modified by other threads.Á
út…„
ÖÛ”„
ú<˜„
©¼ü „1
üäüÒ„-
* use std::sync::atomic::Ordering::Relaxed;Á€…
úÜ„…
 let a = Atomic::new(7);Á …
úd¤…
ÙØü±…7
4 // Load `a` without pinning the current thread.Áüé….
+ a.load(Relaxed, epoch::unprotected());Á˜†
úüœ†5
2 // It's possible to create more dummy guards.ÁüÒ†)
& let dummy = epoch::unprotected();矠
ú쀇
 dummy.defer(move || {Áüž‡8