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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use super::{Message, MessageId, MessageSender};
use crate::CID;
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Envelope {
pub sender: MessageSender,
pub body: Message,
}
unsafe impl Send for Envelope {}
impl Envelope {
pub fn to_usize(&self) -> [usize; 7] {
let body_usize = self.body.to_usize();
[
self.sender.to_usize(),
body_usize[0],
body_usize[1],
body_usize[2],
body_usize[3],
body_usize[4],
body_usize[5],
]
}
/// Take the message, throwing away the sender information. If the message is
/// Blocking (i.e. if message.is_blocking() is `true`), then the process that
/// sent this message will not automatically get a response. You will need to
/// manually send a response.
///
/// If the message is non-blocking, then this has no side effects.
///
/// This is equivalent to "leaking" the message, which is not strictly unsafe.
pub fn take_message(self) -> Message {
use core::mem::ManuallyDrop;
// Convert `Self` into something that won't have its "Drop" method called
let manual_self = ManuallyDrop::new(self);
// This function only works on memory messages
unsafe { core::ptr::read(&manual_self.body) }
}
pub fn id(&self) -> MessageId { self.body.id() }
/// Take this message and forward it to another server.
///
/// **Note**: For blocking messages, this will block until the other server responds to
/// the message. In the future, this may be turned into a nonblocking operation where
/// this will return immediately and allow the target Server to respond directly.
///
/// ## Result
///
/// If the result is successful, then nothing is returned.
///
/// If there is an error, then the original Envelope is returned along with the resulting
/// error.
pub fn forward(mut self, connection: CID, id: MessageId) -> Result<(), (Envelope, crate::Error)> {
use core::mem::ManuallyDrop;
// Update our ID to match the newly-sent message. Reuse the same message struct.
self.body.set_id(id);
// Convert `Self` into something that won't have its "Drop" method called
let manual_self = ManuallyDrop::new(self);
// Unsafe because there are now two things that are pointing at "self.body". However,
// this is fine since these two pointers are never used at the same time.
let body = unsafe { core::ptr::read(&manual_self.body) };
let sender = unsafe { core::ptr::read(&manual_self.sender) };
// Different messages have different kinds of lifetimes, so they must all be
// handled differently.
match body {
Message::Move(_) => {
let result = crate::send_message(connection, body);
// If the Move was successful, return so.
if let Ok(crate::Result::Ok) = result {
// `self` goes out of scope here without having `Drop` called on it
return Ok(());
}
// If there's an error, reconstitute ourselves and return.
if let Err(e) = result {
return Err((ManuallyDrop::into_inner(manual_self), e));
}
Err((ManuallyDrop::into_inner(manual_self), crate::Error::MemoryInUse))
}
Message::BlockingScalar(_) => {
let result = crate::send_message(connection, body);
// If there's an error, reconstitute ourselves and return.
if let Err(e) = result {
return Err((ManuallyDrop::into_inner(manual_self), e));
} else if let Ok(crate::Result::Scalar1(v)) = result {
if let Err(e) = crate::return_scalar(sender, v) {
return Err((ManuallyDrop::into_inner(manual_self), e));
}
return Ok(());
} else if let Ok(crate::Result::Scalar2(v1, v2)) = result {
if let Err(e) = crate::return_scalar2(sender, v1, v2) {
return Err((ManuallyDrop::into_inner(manual_self), e));
}
return Ok(());
}
Err((ManuallyDrop::into_inner(manual_self), crate::Error::MemoryInUse))
}
Message::Borrow(_) | Message::MutableBorrow(_) | Message::Scalar(_) => {
let result = crate::send_message(connection, body);
let new_self = ManuallyDrop::into_inner(manual_self);
match result {
// `new_self` will have its Drop() called
Ok(crate::Result::Ok) | Ok(crate::Result::MemoryReturned(_, _)) => Ok(()),
// If there's an error, reconstitute ourselves and return.
Err(e) => Err((new_self, e)),
// Any other value is a bug in the kernel
o => panic!("unrecognized return from send_message: {:?}", o),
}
}
}
}
}
#[cfg(not(feature = "forget-memory-messages"))]
/// When a MessageEnvelope goes out of scope, return the memory. It must either
/// go to the kernel (in the case of a Move), or back to the borrowed process
/// (in the case of a Borrow). Ignore Scalar messages.
impl Drop for Envelope {
fn drop(&mut self) {
match &self.body {
Message::Borrow(x) | Message::MutableBorrow(x) => {
crate::syscall::return_memory_offset_valid(self.sender, x.buf, x.offset, x.valid)
.expect("couldn't return memory")
}
Message::Move(msg) => {
crate::syscall::unmap_memory(msg.buf).expect("couldn't free memory message")
}
_ => (),
}
}
}