openthread/ot/singleton/backing.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use super::*;
use std::cell::{Cell, RefCell};
use std::task::Waker;
/// Backing struct for OpenThread instances. This type contains information
/// related to the rust API implementation.
#[allow(clippy::type_complexity)]
pub(crate) struct InstanceBacking {
pub waker: Cell<Waker>,
pub platform: RefCell<std::boxed::Box<dyn Platform>>,
pub state_change_fn: Cell<Option<std::boxed::Box<dyn FnMut(ot::ChangedFlags)>>>,
pub cli_output_fn: Cell<Option<std::boxed::Box<dyn FnMut(&CStr)>>>,
pub ip6_receive_fn: Cell<Option<std::boxed::Box<dyn FnMut(OtMessageBox<'_>)>>>,
pub ip6_address_fn: Cell<Option<std::boxed::Box<dyn FnMut(Ip6AddressInfo<'_>, bool)>>>,
pub multicast_listener_callback:
Cell<Option<std::boxed::Box<dyn FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address)>>>,
pub active_scan_fn: Cell<Option<std::boxed::Box<dyn FnMut(Option<&ActiveScanResult>)>>>,
pub energy_scan_fn: Cell<Option<std::boxed::Box<dyn FnMut(Option<&EnergyScanResult>)>>>,
pub joiner_fn: Cell<Option<std::boxed::Box<dyn FnOnce(Result)>>>,
pub srp_server_service_update_fn: Cell<
Option<std::boxed::Box<dyn FnMut(ot::SrpServerServiceUpdateId, &ot::SrpServerHost, u32)>>,
>,
pub dnssd_query_sub_unsub_fn: Cell<Option<std::boxed::Box<dyn FnMut(bool, &CStr)>>>,
pub nat64_receive_fn: Cell<Option<std::boxed::Box<dyn FnMut(OtMessageBox<'_>)>>>,
pub dhcp6pd_state_change_callback_fn:
Cell<Option<std::boxed::Box<dyn FnMut(BorderRoutingDhcp6PdState)>>>,
}
impl InstanceBacking {
pub(crate) fn new<T: Platform + 'static>(platform: T) -> Self {
Self {
waker: Cell::new(futures::task::noop_waker()),
platform: RefCell::new(Box::new(platform) as std::boxed::Box<dyn Platform>),
cli_output_fn: Cell::new(None),
ip6_receive_fn: Cell::new(None),
ip6_address_fn: Cell::new(None),
state_change_fn: Cell::new(None),
active_scan_fn: Cell::new(None),
energy_scan_fn: Cell::new(None),
joiner_fn: Cell::new(None),
srp_server_service_update_fn: Cell::new(None),
dnssd_query_sub_unsub_fn: Cell::new(None),
multicast_listener_callback: Cell::new(None),
nat64_receive_fn: Cell::new(None),
dhcp6pd_state_change_callback_fn: Cell::new(None),
}
}
}
impl InstanceBacking {
unsafe fn glob() -> &'static mut Option<InstanceBacking> {
static mut SINGLETON_BACKING: Option<InstanceBacking> = None;
// TODO(b/319328255) -- Fix usage so lint no longer applies
#[allow(static_mut_refs)]
&mut SINGLETON_BACKING
}
/// Returns a reference to the global singleton `InstanceBacking`.
///
/// If you are tempted to use this method, consider using `Instance::borrow_backing()`
/// instead.
///
/// ## Safety ##
///
/// The behavior of this method is undefined when called at the same
/// time that `InstanceBacking::set_singleton()`/`InstanceBacking::drop_singleton()`
/// is being called from a different thread.
///
/// In order to keep things safe and straightforward, this method should
/// only be called by the implementation of `Instance::borrow_backing()`.
pub(crate) unsafe fn as_ref() -> &'static InstanceBacking {
Self::glob().as_ref().expect("otInstance is uninitialized")
}
/// Initializes the singleton instance backing with the given value.
/// Will panic if this is called twice without calling
/// `InstanceBacking::finalize` in between.
///
/// ## Safety ##
///
/// The behavior of this method is undefined when called at the same
/// time that `InstanceBacking::as_ref()`/`InstanceBacking::drop_singleton()`
/// is being called from a different thread.
///
/// In order to keep things safe and straightforward, this method should
/// only be called by the implementation of `Instance::new()`.
pub(crate) unsafe fn set_singleton(backing: InstanceBacking) {
trace!("Setting Singleton InstanceBacking");
assert!(Self::glob().replace(backing).is_none(), "Tried to make two OpenThread instances");
}
/// Finalizes and drops the singleton instance backing. After this
/// method is called, [`InstacnceBacking::set`] may be called again.
///
/// ## Safety ##
///
/// The behavior of this method is undefined when called at the same
/// time that `InstanceBacking::set_singleton()`/`InstanceBacking::as_ref()`
/// is being called from a different thread.
///
/// In order to keep things safe and straightforward, this method should
/// only be called by the implementation of `Instance::finalize()`.
pub(crate) unsafe fn drop_singleton() {
trace!("Dropping Singleton InstanceBacking");
assert!(Self::glob().take().is_some(), "Tried to drop singleton that was never allocated");
}
}