@@ -322,6 +322,8 @@ use core::{
322
322
cmp, fmt,
323
323
hash:: { Hash , Hasher } ,
324
324
marker:: PhantomData ,
325
+ mem,
326
+ ops:: Deref ,
325
327
} ;
326
328
327
329
/// Trait implemented by types which have a span `Id`.
@@ -379,7 +381,36 @@ pub(crate) struct Inner {
379
381
#[ must_use = "once a span has been entered, it should be exited" ]
380
382
pub struct Entered < ' a > {
381
383
span : & ' a Span ,
382
- _not_send : PhantomData < * mut ( ) > ,
384
+
385
+ /// ```compile_fail
386
+ /// use tracing::span::*;
387
+ /// trait AssertSend: Send {}
388
+ ///
389
+ /// impl AssertSend for Entered<'_> {}
390
+ /// ```
391
+ _not_send : PhantomNotSend ,
392
+ }
393
+
394
+ /// An owned version of [`Entered`], a guard representing a span which has been
395
+ /// entered and is currently executing.
396
+ ///
397
+ /// When the guard is dropped, the span will be exited.
398
+ ///
399
+ /// This is returned by the [`Span::entered`] function.
400
+ ///
401
+ /// [`Span::entered`]: super::Span::entered()
402
+ #[ derive( Debug ) ]
403
+ #[ must_use = "once a span has been entered, it should be exited" ]
404
+ pub struct EnteredSpan {
405
+ span : Span ,
406
+
407
+ /// ```compile_fail
408
+ /// use tracing::span::*;
409
+ /// trait AssertSend: Send {}
410
+ ///
411
+ /// impl AssertSend for EnteredSpan {}
412
+ /// ```
413
+ _not_send : PhantomNotSend ,
383
414
}
384
415
385
416
/// `log` target for all span lifecycle (creation/enter/exit/close) records.
@@ -758,7 +789,25 @@ impl Span {
758
789
/// [`Collect::exit`]: super::collect::Collect::exit()
759
790
/// [`Id`]: super::Id
760
791
pub fn enter ( & self ) -> Entered < ' _ > {
761
- if let Some ( ref inner) = self . inner . as_ref ( ) {
792
+ self . do_enter ( ) ;
793
+ Entered {
794
+ span : self ,
795
+ _not_send : PhantomNotSend ,
796
+ }
797
+ }
798
+
799
+ /// An owned version of [`Entered`].
800
+ pub fn entered ( self ) -> EnteredSpan {
801
+ self . do_enter ( ) ;
802
+ EnteredSpan {
803
+ span : self ,
804
+ _not_send : PhantomNotSend ,
805
+ }
806
+ }
807
+
808
+ #[ inline]
809
+ fn do_enter ( & self ) {
810
+ if let Some ( inner) = self . inner . as_ref ( ) {
762
811
inner. collector . enter ( & inner. id ) ;
763
812
}
764
813
@@ -767,11 +816,23 @@ impl Span {
767
816
self . log( ACTIVITY_LOG_TARGET , log:: Level :: Trace , format_args!( "-> {}" , meta. name( ) ) ) ;
768
817
}
769
818
} }
819
+ }
770
820
771
- Entered {
772
- span : self ,
773
- _not_send : PhantomData ,
821
+ // Called from [`Entered`] and [`EnteredSpan`] drops.
822
+ //
823
+ // Running this behaviour on drop rather than with an explicit function
824
+ // call means that spans may still be exited when unwinding.
825
+ #[ inline]
826
+ fn do_exit ( & self ) {
827
+ if let Some ( inner) = self . inner . as_ref ( ) {
828
+ inner. collector . exit ( & inner. id ) ;
774
829
}
830
+
831
+ if_log_enabled ! { crate :: Level :: TRACE , {
832
+ if let Some ( ref _meta) = self . meta {
833
+ self . log( ACTIVITY_LOG_TARGET , log:: Level :: Trace , format_args!( "<- {}" , _meta. name( ) ) ) ;
834
+ }
835
+ } }
775
836
}
776
837
777
838
/// Executes the given function in the context of this span.
@@ -1223,42 +1284,65 @@ impl Clone for Inner {
1223
1284
1224
1285
// ===== impl Entered =====
1225
1286
1226
- /// # Safety
1227
- ///
1228
- /// Technically, `Entered` _can_ implement both `Send` *and* `Sync` safely. It
1229
- /// doesn't, because it has a `PhantomData<*mut ()>` field, specifically added
1230
- /// in order to make it `!Send`.
1287
+ impl EnteredSpan {
1288
+ /// Exits this span, returning the underlying [`Span`].
1289
+ #[ inline]
1290
+ pub fn exit ( mut self ) -> Span {
1291
+ // One does not simply move out of a struct with `Drop`.
1292
+ let span = mem:: replace ( & mut self . span , Span :: none ( ) ) ;
1293
+ span. do_exit ( ) ;
1294
+ span
1295
+ }
1296
+ }
1297
+
1298
+ impl Deref for EnteredSpan {
1299
+ type Target = Span ;
1300
+
1301
+ #[ inline]
1302
+ fn deref ( & self ) -> & Span {
1303
+ & self . span
1304
+ }
1305
+ }
1306
+
1307
+ impl < ' a > Drop for Entered < ' a > {
1308
+ #[ inline]
1309
+ fn drop ( & mut self ) {
1310
+ self . span . do_exit ( )
1311
+ }
1312
+ }
1313
+
1314
+ impl Drop for EnteredSpan {
1315
+ #[ inline]
1316
+ fn drop ( & mut self ) {
1317
+ self . span . do_exit ( )
1318
+ }
1319
+ }
1320
+
1321
+ /// Technically, `Entered` (or `EnteredSpan`) _can_ implement both `Send` *and*
1322
+ /// `Sync` safely. It doesn't, because it has a `PhantomNotSend` field,
1323
+ /// specifically added in order to make it `!Send`.
1231
1324
///
1232
1325
/// Sending an `Entered` guard between threads cannot cause memory unsafety.
1233
1326
/// However, it *would* result in incorrect behavior, so we add a
1234
- /// `PhantomData<*mut ()> ` to prevent it from being sent between threads. This
1235
- /// is because it must be *dropped* on the same thread that it was created;
1327
+ /// `PhantomNotSend ` to prevent it from being sent between threads. This is
1328
+ /// because it must be *dropped* on the same thread that it was created;
1236
1329
/// otherwise, the span will never be exited on the thread where it was entered,
1237
1330
/// and it will attempt to exit the span on a thread that may never have entered
1238
1331
/// it. However, we still want them to be `Sync` so that a struct holding an
1239
1332
/// `Entered` guard can be `Sync`.
1240
1333
///
1241
1334
/// Thus, this is totally safe.
1242
- unsafe impl < ' a > Sync for Entered < ' a > { }
1243
-
1244
- impl < ' a > Drop for Entered < ' a > {
1245
- #[ inline]
1246
- fn drop ( & mut self ) {
1247
- // Dropping the guard exits the span.
1248
- //
1249
- // Running this behaviour on drop rather than with an explicit function
1250
- // call means that spans may still be exited when unwinding.
1251
- if let Some ( inner) = self . span . inner . as_ref ( ) {
1252
- inner. collector . exit ( & inner. id ) ;
1253
- }
1254
-
1255
- if let Some ( ref _meta) = self . span . meta {
1256
- if_log_enabled ! { crate :: Level :: TRACE , {
1257
- self . span. log( ACTIVITY_LOG_TARGET , log:: Level :: Trace , format_args!( "<- {}" , _meta. name( ) ) ) ;
1258
- } }
1259
- }
1260
- }
1335
+ #[ derive( Debug ) ]
1336
+ struct PhantomNotSend {
1337
+ ghost : PhantomData < * mut ( ) > ,
1261
1338
}
1339
+ #[ allow( non_upper_case_globals) ]
1340
+ const PhantomNotSend : PhantomNotSend = PhantomNotSend { ghost : PhantomData } ;
1341
+
1342
+ /// # Safety
1343
+ ///
1344
+ /// Trivially safe, as `PhantomNotSend` doesn't have any API.
1345
+ unsafe impl Sync for PhantomNotSend { }
1262
1346
1263
1347
#[ cfg( feature = "log" ) ]
1264
1348
struct FmtValues < ' a > ( & ' a Record < ' a > ) ;
@@ -1301,4 +1385,6 @@ mod test {
1301
1385
1302
1386
trait AssertSync : Sync { }
1303
1387
impl AssertSync for Span { }
1388
+ impl AssertSync for Entered < ' _ > { }
1389
+ impl AssertSync for EnteredSpan { }
1304
1390
}
0 commit comments