openthread/ot/singleton/
instance.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::*;
6
7use std::task::{Context, Waker};
8
9/// OpenThread instance.
10///
11/// This type cannot be instantiated directly: owned instances are
12/// passed around in an [`ot::Box<ot::Instance>`](crate::ot::Box), or
13/// [`OtInstanceBox`](crate::OtInstanceBox) for short.
14#[repr(transparent)]
15pub struct Instance(otInstance, PhantomData<*mut otMessage>);
16
17// SAFETY: Instances of `ot::Instance` may be safely moved across threads.
18//         OpenThread does not use thread-local storage.
19unsafe impl Send for Instance {}
20
21// SAFETY: `Instance` transparently wraps around an opaque type and is
22//         never used by value nor passed by value.
23unsafe impl ot::Boxable for Instance {
24    type OtType = otInstance;
25    unsafe fn finalize(&mut self) {
26        if self.srp_server_is_enabled() {
27            debug!("Instance::finalize(): Turning off SRP server...");
28            self.srp_server_set_enabled(false);
29        }
30
31        // Make sure all of the UDP ports are closed. This shouldn't
32        // strictly be necessary, but we've seen some cases where it
33        // appears to not be happening in `otInstanceFinalize`, as
34        // seen here: <b/296886787#comment53>
35        debug!("Instance::finalize(): Forcing all remaining UDP sockets to close...");
36        for socket in self.udp_get_sockets() {
37            // SAFETY: We need to pass a mutable pointer to clean this up.
38            //         This is safe because we are the only thread interacting
39            //         with these objects and subsequent calls to any of the
40            //         `otPlatUdp*` methods will simply fail with an error,
41            //         including `otPlatUdpClose`. In general, we only get away
42            //         with this because we are finalizing.
43            otPlatUdpClose(socket.as_ot_ptr() as *mut _);
44        }
45
46        debug!("Instance::finalize(): Finalizing otInstance...");
47        otInstanceFinalize(self.as_ot_ptr());
48
49        debug!("Instance::finalize(): Dropping singleton backing...");
50        InstanceBacking::drop_singleton();
51    }
52}
53
54impl InstanceInterface for Instance {}
55
56impl std::fmt::Debug for Instance {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        f.debug_tuple("otInstance").field(&self.as_ot_ptr()).finish()
59    }
60}
61
62impl Instance {
63    /// Initializes and returns a new boxed singleton OpenThread instance.
64    ///
65    /// If called twice without dropping the first instance, this method will panic.
66    pub fn new<T: Platform + 'static>(platform: T) -> ot::Box<Instance> {
67        unsafe {
68            // OpenThread is inherently thread-unsafe, just as `set_singleton()` is below.
69            // For singleton instances it only makes sense to call this method once.
70            InstanceBacking::set_singleton(InstanceBacking::new(platform));
71
72            // The ot::Box will take ownership of the instance
73            // pointer and manage its lifetime.
74            ot::Box::from_ot_ptr(otInstanceInitSingle()).unwrap()
75        }
76    }
77}
78
79impl Instance {
80    /// Returns a reference to the backing structure.
81    pub(crate) fn borrow_backing(&self) -> &InstanceBacking {
82        unsafe {
83            // SAFETY: We are making a call to one unsafe methods here,
84            //         `InstanceBacking::as_ref()`. This method must
85            //         only be called from the same thread that the OpenThread
86            //         instance is being used on. Since the OpenThread instance
87            //         does not implement `Sync`, the self reference is neither
88            //         `Send` nor `Sync`, so it is is safe to call here.
89            InstanceBacking::as_ref()
90        }
91    }
92
93    pub(crate) fn platform_poll(&self, cx: &mut Context<'_>) -> Result<(), anyhow::Error> {
94        unsafe {
95            // SAFETY: The underlying unsafe call, process_poll(), must
96            //         only be called from the same thread that the OpenThread
97            //         instance is being used on. Since the OpenThread instance
98            //         does not implement `Sync`, the self reference is neither
99            //         `Send` nor `Sync`, so it is is safe to call here.
100            self.borrow_backing().platform.borrow_mut().process_poll(self, cx)
101        }
102    }
103}
104
105impl ot::Tasklets for Instance {
106    fn set_waker(&self, waker: Waker) {
107        self.borrow_backing().waker.set(waker);
108    }
109
110    fn wake_waker(&self) {
111        self.borrow_backing().waker.replace(futures::task::noop_waker()).wake()
112    }
113
114    fn process(&self) {
115        unsafe { otTaskletsProcess(self.as_ot_ptr()) }
116    }
117
118    fn has_pending(&self) -> bool {
119        unsafe { otTaskletsArePending(self.as_ot_ptr()) }
120    }
121}