openthread/ot/singleton/instance.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 112 113 114 115 116 117 118 119 120 121
// Copyright 2021 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::task::{Context, Waker};
/// OpenThread instance.
///
/// This type cannot be instantiated directly: owned instances are
/// passed around in an [`ot::Box<ot::Instance>`](crate::ot::Box), or
/// [`OtInstanceBox`](crate::OtInstanceBox) for short.
#[repr(transparent)]
pub struct Instance(otInstance, PhantomData<*mut otMessage>);
// SAFETY: Instances of `ot::Instance` may be safely moved across threads.
// OpenThread does not use thread-local storage.
unsafe impl Send for Instance {}
// SAFETY: `Instance` transparently wraps around an opaque type and is
// never used by value nor passed by value.
unsafe impl ot::Boxable for Instance {
type OtType = otInstance;
unsafe fn finalize(&mut self) {
if self.srp_server_is_enabled() {
debug!("Instance::finalize(): Turning off SRP server...");
self.srp_server_set_enabled(false);
}
// Make sure all of the UDP ports are closed. This shouldn't
// strictly be necessary, but we've seen some cases where it
// appears to not be happening in `otInstanceFinalize`, as
// seen here: <b/296886787#comment53>
debug!("Instance::finalize(): Forcing all remaining UDP sockets to close...");
for socket in self.udp_get_sockets() {
// SAFETY: We need to pass a mutable pointer to clean this up.
// This is safe because we are the only thread interacting
// with these objects and subsequent calls to any of the
// `otPlatUdp*` methods will simply fail with an error,
// including `otPlatUdpClose`. In general, we only get away
// with this because we are finalizing.
otPlatUdpClose(socket.as_ot_ptr() as *mut _);
}
debug!("Instance::finalize(): Finalizing otInstance...");
otInstanceFinalize(self.as_ot_ptr());
debug!("Instance::finalize(): Dropping singleton backing...");
InstanceBacking::drop_singleton();
}
}
impl InstanceInterface for Instance {}
impl std::fmt::Debug for Instance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("otInstance").field(&self.as_ot_ptr()).finish()
}
}
impl Instance {
/// Initializes and returns a new boxed singleton OpenThread instance.
///
/// If called twice without dropping the first instance, this method will panic.
pub fn new<T: Platform + 'static>(platform: T) -> ot::Box<Instance> {
unsafe {
// OpenThread is inherently thread-unsafe, just as `set_singleton()` is below.
// For singleton instances it only makes sense to call this method once.
InstanceBacking::set_singleton(InstanceBacking::new(platform));
// The ot::Box will take ownership of the instance
// pointer and manage its lifetime.
ot::Box::from_ot_ptr(otInstanceInitSingle()).unwrap()
}
}
}
impl Instance {
/// Returns a reference to the backing structure.
pub(crate) fn borrow_backing(&self) -> &InstanceBacking {
unsafe {
// SAFETY: We are making a call to one unsafe methods here,
// `InstanceBacking::as_ref()`. This method must
// only be called from the same thread that the OpenThread
// instance is being used on. Since the OpenThread instance
// does not implement `Sync`, the self reference is neither
// `Send` nor `Sync`, so it is is safe to call here.
InstanceBacking::as_ref()
}
}
pub(crate) fn platform_poll(&self, cx: &mut Context<'_>) -> Result<(), anyhow::Error> {
unsafe {
// SAFETY: The underlying unsafe call, process_poll(), must
// only be called from the same thread that the OpenThread
// instance is being used on. Since the OpenThread instance
// does not implement `Sync`, the self reference is neither
// `Send` nor `Sync`, so it is is safe to call here.
self.borrow_backing().platform.borrow_mut().process_poll(self, cx)
}
}
}
impl ot::Tasklets for Instance {
fn set_waker(&self, waker: Waker) {
self.borrow_backing().waker.set(waker);
}
fn wake_waker(&self) {
self.borrow_backing().waker.replace(futures::task::noop_waker()).wake()
}
fn process(&self) {
unsafe { otTaskletsProcess(self.as_ot_ptr()) }
}
fn has_pending(&self) -> bool {
unsafe { otTaskletsArePending(self.as_ot_ptr()) }
}
}