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}