| 1 | //! The `Notification` trait for specifying notification. |
| 2 | |
| 3 | use crate::sync::atomic::{self, Ordering}; |
| 4 | #[cfg (feature = "std" )] |
| 5 | use core::fmt; |
| 6 | |
| 7 | pub(crate) use __private::Internal; |
| 8 | |
| 9 | /// The type of notification to use with an [`Event`]. |
| 10 | /// |
| 11 | /// This is hidden and sealed to prevent changes to this trait from being breaking. |
| 12 | /// |
| 13 | /// [`Event`]: crate::Event |
| 14 | #[doc (hidden)] |
| 15 | pub trait NotificationPrivate { |
| 16 | /// The tag data associated with a notification. |
| 17 | type Tag; |
| 18 | |
| 19 | /// Emit a fence to ensure that the notification is visible to the listeners. |
| 20 | fn fence(&self, internal: Internal); |
| 21 | |
| 22 | /// Whether or not the number of currently waiting listeners should be subtracted from `count()`. |
| 23 | fn is_additional(&self, internal: Internal) -> bool; |
| 24 | |
| 25 | /// Get the number of listeners to wake. |
| 26 | fn count(&self, internal: Internal) -> usize; |
| 27 | |
| 28 | /// Get a tag to be associated with a notification. |
| 29 | /// |
| 30 | /// This method is expected to be called `count()` times. |
| 31 | fn next_tag(&mut self, internal: Internal) -> Self::Tag; |
| 32 | } |
| 33 | |
| 34 | /// A notification that can be used to notify an [`Event`]. |
| 35 | /// |
| 36 | /// This type is used by the [`Event::notify()`] function to determine how many listeners to wake up, whether |
| 37 | /// or not to subtract additional listeners, and other properties. The actual internal data is hidden in a |
| 38 | /// private trait and is intentionally not exposed. This means that users cannot manually implement the |
| 39 | /// [`Notification`] trait. However, it also means that changing the underlying trait is not a semver breaking |
| 40 | /// change. |
| 41 | /// |
| 42 | /// Users can create types that implement notifications using the combinators on the [`IntoNotification`] type. |
| 43 | /// Typical construction of a [`Notification`] starts with a numeric literal (like `3usize`) and then optionally |
| 44 | /// adding combinators. |
| 45 | /// |
| 46 | /// # Example |
| 47 | /// |
| 48 | /// ``` |
| 49 | /// use event_listener::{Event, IntoNotification, Notification}; |
| 50 | /// |
| 51 | /// fn notify(ev: &Event, notify: impl Notification<Tag = ()>) { |
| 52 | /// ev.notify(notify); |
| 53 | /// } |
| 54 | /// |
| 55 | /// notify(&Event::new(), 1.additional()); |
| 56 | /// ``` |
| 57 | /// |
| 58 | /// [`Event`]: crate::Event |
| 59 | pub trait Notification: NotificationPrivate {} |
| 60 | impl<N: NotificationPrivate + ?Sized> Notification for N {} |
| 61 | |
| 62 | /// Notify a given number of unnotifed listeners. |
| 63 | #[derive (Debug, Clone)] |
| 64 | #[doc (hidden)] |
| 65 | pub struct Notify(usize); |
| 66 | |
| 67 | impl Notify { |
| 68 | /// Create a new `Notify` with the given number of listeners to notify. |
| 69 | fn new(count: usize) -> Self { |
| 70 | Self(count) |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | impl NotificationPrivate for Notify { |
| 75 | type Tag = (); |
| 76 | |
| 77 | fn is_additional(&self, _: Internal) -> bool { |
| 78 | false |
| 79 | } |
| 80 | |
| 81 | fn fence(&self, _: Internal) { |
| 82 | full_fence(); |
| 83 | } |
| 84 | |
| 85 | fn count(&self, _: Internal) -> usize { |
| 86 | self.0 |
| 87 | } |
| 88 | |
| 89 | fn next_tag(&mut self, _: Internal) -> Self::Tag {} |
| 90 | } |
| 91 | |
| 92 | /// Make the underlying notification additional. |
| 93 | #[derive (Debug, Clone)] |
| 94 | #[doc (hidden)] |
| 95 | pub struct Additional<N: ?Sized>(N); |
| 96 | |
| 97 | impl<N> Additional<N> { |
| 98 | /// Create a new `Additional` with the given notification. |
| 99 | fn new(inner: N) -> Self { |
| 100 | Self(inner) |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | impl<N> NotificationPrivate for Additional<N> |
| 105 | where |
| 106 | N: Notification + ?Sized, |
| 107 | { |
| 108 | type Tag = N::Tag; |
| 109 | |
| 110 | fn is_additional(&self, _: Internal) -> bool { |
| 111 | true |
| 112 | } |
| 113 | |
| 114 | fn fence(&self, i: Internal) { |
| 115 | self.0.fence(internal:i); |
| 116 | } |
| 117 | |
| 118 | fn count(&self, i: Internal) -> usize { |
| 119 | self.0.count(internal:i) |
| 120 | } |
| 121 | |
| 122 | fn next_tag(&mut self, i: Internal) -> Self::Tag { |
| 123 | self.0.next_tag(internal:i) |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | /// Don't emit a fence for this notification. |
| 128 | #[derive (Debug, Clone)] |
| 129 | #[doc (hidden)] |
| 130 | pub struct Relaxed<N: ?Sized>(N); |
| 131 | |
| 132 | impl<N> Relaxed<N> { |
| 133 | /// Create a new `Relaxed` with the given notification. |
| 134 | fn new(inner: N) -> Self { |
| 135 | Self(inner) |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | impl<N> NotificationPrivate for Relaxed<N> |
| 140 | where |
| 141 | N: Notification + ?Sized, |
| 142 | { |
| 143 | type Tag = N::Tag; |
| 144 | |
| 145 | fn is_additional(&self, i: Internal) -> bool { |
| 146 | self.0.is_additional(internal:i) |
| 147 | } |
| 148 | |
| 149 | fn fence(&self, _: Internal) { |
| 150 | // Don't emit a fence. |
| 151 | } |
| 152 | |
| 153 | fn count(&self, i: Internal) -> usize { |
| 154 | self.0.count(internal:i) |
| 155 | } |
| 156 | |
| 157 | fn next_tag(&mut self, i: Internal) -> Self::Tag { |
| 158 | self.0.next_tag(internal:i) |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | /// Use a tag to notify listeners. |
| 163 | #[cfg (feature = "std" )] |
| 164 | #[derive (Debug, Clone)] |
| 165 | #[doc (hidden)] |
| 166 | pub struct Tag<N: ?Sized, T> { |
| 167 | tag: T, |
| 168 | inner: N, |
| 169 | } |
| 170 | |
| 171 | #[cfg (feature = "std" )] |
| 172 | impl<N: ?Sized, T> Tag<N, T> { |
| 173 | /// Create a new `Tag` with the given tag and notification. |
| 174 | fn new(tag: T, inner: N) -> Self |
| 175 | where |
| 176 | N: Sized, |
| 177 | { |
| 178 | Self { tag, inner } |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | #[cfg (feature = "std" )] |
| 183 | impl<N, T> NotificationPrivate for Tag<N, T> |
| 184 | where |
| 185 | N: Notification + ?Sized, |
| 186 | T: Clone, |
| 187 | { |
| 188 | type Tag = T; |
| 189 | |
| 190 | fn is_additional(&self, i: Internal) -> bool { |
| 191 | self.inner.is_additional(internal:i) |
| 192 | } |
| 193 | |
| 194 | fn fence(&self, i: Internal) { |
| 195 | self.inner.fence(internal:i); |
| 196 | } |
| 197 | |
| 198 | fn count(&self, i: Internal) -> usize { |
| 199 | self.inner.count(internal:i) |
| 200 | } |
| 201 | |
| 202 | fn next_tag(&mut self, _: Internal) -> Self::Tag { |
| 203 | self.tag.clone() |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /// Use a function to generate a tag to notify listeners. |
| 208 | #[cfg (feature = "std" )] |
| 209 | #[doc (hidden)] |
| 210 | pub struct TagWith<N: ?Sized, F> { |
| 211 | tag: F, |
| 212 | inner: N, |
| 213 | } |
| 214 | |
| 215 | #[cfg (feature = "std" )] |
| 216 | impl<N: fmt::Debug, F> fmt::Debug for TagWith<N, F> { |
| 217 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 218 | struct Ellipses; |
| 219 | |
| 220 | impl fmt::Debug for Ellipses { |
| 221 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 222 | f.write_str(data:".." ) |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | f&mut DebugStruct<'_, '_>.debug_struct("TagWith" ) |
| 227 | .field("tag" , &Ellipses) |
| 228 | .field(name:"inner" , &self.inner) |
| 229 | .finish() |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | #[cfg (feature = "std" )] |
| 234 | impl<N, F> TagWith<N, F> { |
| 235 | /// Create a new `TagFn` with the given tag function and notification. |
| 236 | fn new(tag: F, inner: N) -> Self { |
| 237 | Self { tag, inner } |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | #[cfg (feature = "std" )] |
| 242 | impl<N, F, T> NotificationPrivate for TagWith<N, F> |
| 243 | where |
| 244 | N: Notification + ?Sized, |
| 245 | F: FnMut() -> T, |
| 246 | { |
| 247 | type Tag = T; |
| 248 | |
| 249 | fn is_additional(&self, i: Internal) -> bool { |
| 250 | self.inner.is_additional(internal:i) |
| 251 | } |
| 252 | |
| 253 | fn fence(&self, i: Internal) { |
| 254 | self.inner.fence(internal:i); |
| 255 | } |
| 256 | |
| 257 | fn count(&self, i: Internal) -> usize { |
| 258 | self.inner.count(internal:i) |
| 259 | } |
| 260 | |
| 261 | fn next_tag(&mut self, _: Internal) -> Self::Tag { |
| 262 | (self.tag)() |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | /// A generic notification. |
| 267 | #[derive (Debug)] |
| 268 | pub(crate) struct GenericNotify<F> { |
| 269 | /// Number of listeners to notify. |
| 270 | count: usize, |
| 271 | |
| 272 | /// Whether this notification is additional. |
| 273 | additional: bool, |
| 274 | |
| 275 | /// Generate tags. |
| 276 | tags: F, |
| 277 | } |
| 278 | |
| 279 | impl<T, F: TagProducer<Tag = T>> GenericNotify<F> { |
| 280 | pub(crate) fn new(count: usize, additional: bool, tags: F) -> Self { |
| 281 | Self { |
| 282 | count, |
| 283 | additional, |
| 284 | tags, |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | impl<T, F: TagProducer<Tag = T>> NotificationPrivate for GenericNotify<F> { |
| 290 | type Tag = T; |
| 291 | |
| 292 | fn is_additional(&self, _: Internal) -> bool { |
| 293 | self.additional |
| 294 | } |
| 295 | |
| 296 | fn fence(&self, _: Internal) { |
| 297 | // Don't emit a fence. |
| 298 | } |
| 299 | |
| 300 | fn count(&self, _: Internal) -> usize { |
| 301 | self.count |
| 302 | } |
| 303 | |
| 304 | fn next_tag(&mut self, _: Internal) -> Self::Tag { |
| 305 | self.tags.next_tag() |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | /// The producer for a generic notification. |
| 310 | pub(crate) trait TagProducer { |
| 311 | type Tag; |
| 312 | |
| 313 | /// Get the next tag. |
| 314 | fn next_tag(&mut self) -> Self::Tag; |
| 315 | } |
| 316 | |
| 317 | impl<T, F: FnMut() -> T> TagProducer for F { |
| 318 | type Tag = T; |
| 319 | |
| 320 | fn next_tag(&mut self) -> T { |
| 321 | (self)() |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | /// A value that can be converted into a [`Notification`]. |
| 326 | /// |
| 327 | /// This trait adds onto the [`Notification`] trait by providing combinators that can be applied to all |
| 328 | /// notification types as well as numeric literals. This transforms what would normally be: |
| 329 | /// |
| 330 | /// ``` |
| 331 | /// use event_listener::Event; |
| 332 | /// |
| 333 | /// let event = Event::new(); |
| 334 | /// |
| 335 | /// // Note that each use case needs its own function, leading to bloat. |
| 336 | /// event.notify(1); |
| 337 | /// event.notify_additional(3); |
| 338 | /// event.notify_relaxed(5); |
| 339 | /// event.notify_additional_relaxed(2); |
| 340 | /// ``` |
| 341 | /// |
| 342 | /// into this: |
| 343 | /// |
| 344 | /// ``` |
| 345 | /// use event_listener::{Event, IntoNotification, Listener}; |
| 346 | /// |
| 347 | /// let event = Event::new(); |
| 348 | /// |
| 349 | /// event.notify(1); |
| 350 | /// event.notify(3.additional()); |
| 351 | /// event.notify(5.relaxed()); |
| 352 | /// event.notify(2.additional().relaxed()); |
| 353 | /// ``` |
| 354 | /// |
| 355 | /// This trait is implemented for all types that implement [`Notification`], as well as for non-floating-point |
| 356 | /// numeric literals (`usize`, `i32`, etc). |
| 357 | /// |
| 358 | /// This function can be thought of as being analogous to [`std::iter::IntoIterator`], but for [`Notification`]. |
| 359 | pub trait IntoNotification: __private::Sealed { |
| 360 | /// The tag data associated with a notification. |
| 361 | /// |
| 362 | /// By default, most [`Event`]s will use the unit type, `()`. However, this can be used to pass data along to |
| 363 | /// the listener. |
| 364 | type Tag; |
| 365 | |
| 366 | /// The notification type. |
| 367 | /// |
| 368 | /// Tells what kind of underlying type that the [`Notification`] is. You probably don't need to worry about |
| 369 | /// this. |
| 370 | type Notify: Notification<Tag = Self::Tag>; |
| 371 | |
| 372 | /// Convert this value into a notification. |
| 373 | /// |
| 374 | /// This allows the user to convert an [`IntoNotification`] into a [`Notification`]. |
| 375 | /// |
| 376 | /// # Panics |
| 377 | /// |
| 378 | /// This function panics if the value represents a negative number of notifications. |
| 379 | /// |
| 380 | /// # Examples |
| 381 | /// |
| 382 | /// ``` |
| 383 | /// use event_listener::IntoNotification; |
| 384 | /// |
| 385 | /// let _ = 3.into_notification(); |
| 386 | /// ``` |
| 387 | fn into_notification(self) -> Self::Notify; |
| 388 | |
| 389 | /// Convert this value into an additional notification. |
| 390 | /// |
| 391 | /// By default, notifications ignore listeners that are already notified. Generally, this happens when there |
| 392 | /// is an [`EventListener`] that has been woken up, but hasn't been polled to completion or waited on yet. |
| 393 | /// For instance, if you have three notified listeners and you call `event.notify(5)`, only two listeners |
| 394 | /// will be woken up. |
| 395 | /// |
| 396 | /// This default behavior is generally desired. For instance, if you are writing a `Mutex` implementation |
| 397 | /// powered by an [`Event`], you usually only want one consumer to be notified at a time. If you notified |
| 398 | /// a listener when another listener is already notified, you would have unnecessary contention for your |
| 399 | /// lock, as both listeners fight over the lock. Therefore, you would call `event.notify(1)` to make sure |
| 400 | /// *at least* one listener is awake. |
| 401 | /// |
| 402 | /// Sometimes, this behavior is not desired. For instance, if you are writing an MPMC channel, it is desirable |
| 403 | /// for multiple listeners to be reading from the underlying queue at once. In this case, you would instead |
| 404 | /// call `event.notify(1.additional())`. |
| 405 | /// |
| 406 | /// # Examples |
| 407 | /// |
| 408 | /// ``` |
| 409 | /// use event_listener::{Event, IntoNotification, Listener}; |
| 410 | /// |
| 411 | /// let event = Event::new(); |
| 412 | /// |
| 413 | /// let mut l1 = event.listen(); |
| 414 | /// let mut l2 = event.listen(); |
| 415 | /// |
| 416 | /// // This will only wake up the first listener, as the second call observes that there is already a |
| 417 | /// // notified listener. |
| 418 | /// event.notify(1); |
| 419 | /// event.notify(1); |
| 420 | /// |
| 421 | /// // This call wakes up the other listener. |
| 422 | /// event.notify(1.additional()); |
| 423 | /// ``` |
| 424 | fn additional(self) -> Additional<Self::Notify> |
| 425 | where |
| 426 | Self: Sized, |
| 427 | { |
| 428 | Additional::new(self.into_notification()) |
| 429 | } |
| 430 | |
| 431 | /// Don't emit a fence for this notification. |
| 432 | /// |
| 433 | /// Usually, notifications emit a `SeqCst` atomic fence before any listeners are woken up. This ensures |
| 434 | /// that notification state isn't inconsistent before any wakers are woken up. However, it may be |
| 435 | /// desirable to omit this fence in certain cases. |
| 436 | /// |
| 437 | /// - You are running the [`Event`] on a single thread, where no synchronization needs to occur. |
| 438 | /// - You are emitting the `SeqCst` fence yourself. |
| 439 | /// |
| 440 | /// In these cases, `relaxed()` can be used to avoid emitting the `SeqCst` fence. |
| 441 | /// |
| 442 | /// # Examples |
| 443 | /// |
| 444 | /// ``` |
| 445 | /// use event_listener::{Event, IntoNotification, Listener}; |
| 446 | /// use std::sync::atomic::{self, Ordering}; |
| 447 | /// |
| 448 | /// let event = Event::new(); |
| 449 | /// |
| 450 | /// let listener1 = event.listen(); |
| 451 | /// let listener2 = event.listen(); |
| 452 | /// let listener3 = event.listen(); |
| 453 | /// |
| 454 | /// // We should emit a fence manually when using relaxed notifications. |
| 455 | /// atomic::fence(Ordering::SeqCst); |
| 456 | /// |
| 457 | /// // Notifies two listeners. |
| 458 | /// // |
| 459 | /// // Listener queueing is fair, which means `listener1` and `listener2` |
| 460 | /// // get notified here since they start listening before `listener3`. |
| 461 | /// event.notify(1.relaxed()); |
| 462 | /// event.notify(1.relaxed()); |
| 463 | /// ``` |
| 464 | fn relaxed(self) -> Relaxed<Self::Notify> |
| 465 | where |
| 466 | Self: Sized, |
| 467 | { |
| 468 | Relaxed::new(self.into_notification()) |
| 469 | } |
| 470 | |
| 471 | /// Use a tag with this notification. |
| 472 | /// |
| 473 | /// In many cases, it is desired to send additional information to the listener of the [`Event`]. For instance, |
| 474 | /// it is possible to optimize a `Mutex` implementation by locking directly on the next listener, without |
| 475 | /// needing to ever unlock the mutex at all. |
| 476 | /// |
| 477 | /// The tag provided is cloned to provide the tag for all listeners. In cases where this is not flexible |
| 478 | /// enough, use [`IntoNotification::with_tag()`] instead. |
| 479 | /// |
| 480 | /// Tagging functions cannot be implemented efficiently for `no_std`, so this is only available |
| 481 | /// when the `std` feature is enabled. |
| 482 | /// |
| 483 | /// # Examples |
| 484 | /// |
| 485 | /// ``` |
| 486 | /// use event_listener::{IntoNotification, Listener, Event}; |
| 487 | /// |
| 488 | /// let event = Event::<bool>::with_tag(); |
| 489 | /// |
| 490 | /// let mut listener1 = event.listen(); |
| 491 | /// let mut listener2 = event.listen(); |
| 492 | /// |
| 493 | /// // Notify with `true` then `false`. |
| 494 | /// event.notify(1.additional().tag(true)); |
| 495 | /// event.notify(1.additional().tag(false)); |
| 496 | /// |
| 497 | /// assert_eq!(listener1.wait(), true); |
| 498 | /// assert_eq!(listener2.wait(), false); |
| 499 | /// ``` |
| 500 | #[cfg (feature = "std" )] |
| 501 | fn tag<T: Clone>(self, tag: T) -> Tag<Self::Notify, T> |
| 502 | where |
| 503 | Self: Sized + IntoNotification<Tag = ()>, |
| 504 | { |
| 505 | Tag::new(tag, self.into_notification()) |
| 506 | } |
| 507 | |
| 508 | /// Use a function to generate a tag with this notification. |
| 509 | /// |
| 510 | /// In many cases, it is desired to send additional information to the listener of the [`Event`]. For instance, |
| 511 | /// it is possible to optimize a `Mutex` implementation by locking directly on the next listener, without |
| 512 | /// needing to ever unlock the mutex at all. |
| 513 | /// |
| 514 | /// Tagging functions cannot be implemented efficiently for `no_std`, so this is only available |
| 515 | /// when the `std` feature is enabled. |
| 516 | /// |
| 517 | /// # Examples |
| 518 | /// |
| 519 | /// ``` |
| 520 | /// use event_listener::{IntoNotification, Listener, Event}; |
| 521 | /// |
| 522 | /// let event = Event::<bool>::with_tag(); |
| 523 | /// |
| 524 | /// let mut listener1 = event.listen(); |
| 525 | /// let mut listener2 = event.listen(); |
| 526 | /// |
| 527 | /// // Notify with `true` then `false`. |
| 528 | /// event.notify(1.additional().tag_with(|| true)); |
| 529 | /// event.notify(1.additional().tag_with(|| false)); |
| 530 | /// |
| 531 | /// assert_eq!(listener1.wait(), true); |
| 532 | /// assert_eq!(listener2.wait(), false); |
| 533 | /// ``` |
| 534 | #[cfg (feature = "std" )] |
| 535 | fn tag_with<T, F>(self, tag: F) -> TagWith<Self::Notify, F> |
| 536 | where |
| 537 | Self: Sized + IntoNotification<Tag = ()>, |
| 538 | F: FnMut() -> T, |
| 539 | { |
| 540 | TagWith::new(tag, self.into_notification()) |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | impl<N: Notification> IntoNotification for N { |
| 545 | type Tag = N::Tag; |
| 546 | type Notify = N; |
| 547 | |
| 548 | fn into_notification(self) -> Self::Notify { |
| 549 | self |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | macro_rules! impl_for_numeric_types { |
| 554 | ($($ty:ty)*) => {$( |
| 555 | impl IntoNotification for $ty { |
| 556 | type Tag = (); |
| 557 | type Notify = Notify; |
| 558 | |
| 559 | #[allow(unused_comparisons)] |
| 560 | fn into_notification(self) -> Self::Notify { |
| 561 | if self < 0 { |
| 562 | panic!("negative notification count" ); |
| 563 | } |
| 564 | |
| 565 | Notify::new(self.try_into().expect("overflow" )) |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | impl __private::Sealed for $ty {} |
| 570 | )*}; |
| 571 | } |
| 572 | |
| 573 | impl_for_numeric_types! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } |
| 574 | |
| 575 | /// Equivalent to `atomic::fence(Ordering::SeqCst)`, but in some cases faster. |
| 576 | #[inline ] |
| 577 | pub(super) fn full_fence() { |
| 578 | #[cfg (all(any(target_arch = "x86" , target_arch = "x86_64" ), not(miri), not(loom)))] |
| 579 | { |
| 580 | use core::{arch::asm, cell::UnsafeCell}; |
| 581 | // HACK(stjepang): On x86 architectures there are two different ways of executing |
| 582 | // a `SeqCst` fence. |
| 583 | // |
| 584 | // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction. |
| 585 | // 2. A `lock <op>` instruction. |
| 586 | // |
| 587 | // Both instructions have the effect of a full barrier, but empirical benchmarks have shown |
| 588 | // that the second one is sometimes a bit faster. |
| 589 | let a = UnsafeCell::new(0_usize); |
| 590 | // It is common to use `lock or` here, but when using a local variable, `lock not`, which |
| 591 | // does not change the flag, should be slightly more efficient. |
| 592 | // Refs: https://www.felixcloutier.com/x86/not |
| 593 | unsafe { |
| 594 | #[cfg (target_pointer_width = "64" )] |
| 595 | asm!("lock not qword ptr [{ 0}]" , in(reg) a.get(), options(nostack, preserves_flags)); |
| 596 | #[cfg (target_pointer_width = "32" )] |
| 597 | asm!("lock not dword ptr [{0:e}]" , in(reg) a.get(), options(nostack, preserves_flags)); |
| 598 | } |
| 599 | return; |
| 600 | } |
| 601 | #[allow (unreachable_code)] |
| 602 | { |
| 603 | atomic::fence(Ordering::SeqCst); |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | mod __private { |
| 608 | /// Make sure the NotificationPrivate trait can't be implemented outside of this crate. |
| 609 | #[doc (hidden)] |
| 610 | #[derive (Debug)] |
| 611 | pub struct Internal(()); |
| 612 | |
| 613 | impl Internal { |
| 614 | pub(crate) fn new() -> Self { |
| 615 | Self(()) |
| 616 | } |
| 617 | } |
| 618 | |
| 619 | #[doc (hidden)] |
| 620 | pub trait Sealed {} |
| 621 | impl<N: super::NotificationPrivate + ?Sized> Sealed for N {} |
| 622 | } |
| 623 | |