1use std::{
2 os::unix::io::AsRawFd,
3 os::unix::io::{BorrowedFd, OwnedFd},
4 sync::{Arc, Mutex},
5};
6
7use super::{
8 handle::State, ClientId, Data, GlobalHandler, GlobalId, Handle, InnerClientId, InnerGlobalId,
9 InnerHandle, InnerObjectId, ObjectId,
10};
11use crate::{
12 core_interfaces::{WL_DISPLAY_INTERFACE, WL_REGISTRY_INTERFACE},
13 protocol::{same_interface, Argument, Message},
14 rs::map::Object,
15 types::server::InitError,
16};
17
18#[cfg(any(target_os = "linux", target_os = "android"))]
19use rustix::event::epoll;
20
21#[cfg(any(
22 target_os = "dragonfly",
23 target_os = "freebsd",
24 target_os = "netbsd",
25 target_os = "openbsd",
26 target_os = "macos"
27))]
28use rustix::event::kqueue::*;
29use smallvec::SmallVec;
30
31#[derive(Debug)]
32pub struct InnerBackend<D: 'static> {
33 state: Arc<Mutex<State<D>>>,
34}
35
36impl<D> InnerBackend<D> {
37 pub fn new() -> Result<Self, InitError> {
38 #[cfg(any(target_os = "linux", target_os = "android"))]
39 let poll_fd = epoll::create(epoll::CreateFlags::CLOEXEC)
40 .map_err(Into::into)
41 .map_err(InitError::Io)?;
42
43 #[cfg(any(
44 target_os = "dragonfly",
45 target_os = "freebsd",
46 target_os = "netbsd",
47 target_os = "openbsd",
48 target_os = "macos"
49 ))]
50 let poll_fd = kqueue().map_err(Into::into).map_err(InitError::Io)?;
51
52 Ok(Self { state: Arc::new(Mutex::new(State::new(poll_fd))) })
53 }
54
55 pub fn flush(&self, client: Option<ClientId>) -> std::io::Result<()> {
56 self.state.lock().unwrap().flush(client)
57 }
58
59 pub fn handle(&self) -> Handle {
60 Handle { handle: InnerHandle { state: self.state.clone() as Arc<_> } }
61 }
62
63 pub fn poll_fd(&self) -> BorrowedFd {
64 let raw_fd = self.state.lock().unwrap().poll_fd.as_raw_fd();
65 // This allows the lifetime of the BorrowedFd to be tied to &self rather than the lock guard,
66 // which is the real safety concern
67 unsafe { BorrowedFd::borrow_raw(raw_fd) }
68 }
69
70 pub fn dispatch_client(
71 &self,
72 data: &mut D,
73 client_id: InnerClientId,
74 ) -> std::io::Result<usize> {
75 let ret = self.dispatch_events_for(data, client_id);
76 let cleanup = self.state.lock().unwrap().cleanup();
77 cleanup(&self.handle(), data);
78 ret
79 }
80
81 #[cfg(any(target_os = "linux", target_os = "android"))]
82 pub fn dispatch_all_clients(&self, data: &mut D) -> std::io::Result<usize> {
83 use std::os::unix::io::AsFd;
84
85 let poll_fd = self.poll_fd();
86 let mut dispatched = 0;
87 loop {
88 let mut events = epoll::EventVec::with_capacity(32);
89 epoll::wait(poll_fd.as_fd(), &mut events, 0)?;
90
91 if events.is_empty() {
92 break;
93 }
94
95 for event in events.iter() {
96 let id = InnerClientId::from_u64(event.data.u64());
97 // remove the cb while we call it, to gracefully handle reentrancy
98 if let Ok(count) = self.dispatch_events_for(data, id) {
99 dispatched += count;
100 }
101 }
102 let cleanup = self.state.lock().unwrap().cleanup();
103 cleanup(&self.handle(), data);
104 }
105
106 Ok(dispatched)
107 }
108
109 #[cfg(any(
110 target_os = "dragonfly",
111 target_os = "freebsd",
112 target_os = "netbsd",
113 target_os = "openbsd",
114 target_os = "macos"
115 ))]
116 pub fn dispatch_all_clients(&self, data: &mut D) -> std::io::Result<usize> {
117 use std::time::Duration;
118
119 let poll_fd = self.poll_fd();
120 let mut dispatched = 0;
121 loop {
122 let mut events = Vec::with_capacity(32);
123 let nevents = unsafe { kevent(&poll_fd, &[], &mut events, Some(Duration::ZERO))? };
124
125 if nevents == 0 {
126 break;
127 }
128
129 for event in events.iter().take(nevents) {
130 let id = InnerClientId::from_u64(event.udata() as u64);
131 // remove the cb while we call it, to gracefully handle reentrancy
132 if let Ok(count) = self.dispatch_events_for(data, id) {
133 dispatched += count;
134 }
135 }
136 let cleanup = self.state.lock().unwrap().cleanup();
137 cleanup(&self.handle(), data);
138 }
139
140 Ok(dispatched)
141 }
142
143 pub(crate) fn dispatch_events_for(
144 &self,
145 data: &mut D,
146 client_id: InnerClientId,
147 ) -> std::io::Result<usize> {
148 let mut dispatched = 0;
149 let handle = self.handle();
150 let mut state = self.state.lock().unwrap();
151 loop {
152 let action = {
153 let state = &mut *state;
154 if let Ok(client) = state.clients.get_client_mut(client_id.clone()) {
155 let (message, object) = match client.next_request() {
156 Ok(v) => v,
157 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
158 if dispatched > 0 {
159 break;
160 } else {
161 return Err(e);
162 }
163 }
164 Err(e) => return Err(e),
165 };
166 dispatched += 1;
167 if same_interface(object.interface, &WL_DISPLAY_INTERFACE) {
168 client.handle_display_request(message, &mut state.registry);
169 continue;
170 } else if same_interface(object.interface, &WL_REGISTRY_INTERFACE) {
171 if let Some((client, global, object, handler)) =
172 client.handle_registry_request(message, &mut state.registry)
173 {
174 DispatchAction::Bind { client, global, object, handler }
175 } else {
176 continue;
177 }
178 } else {
179 let object_id = InnerObjectId {
180 id: message.sender_id,
181 serial: object.data.serial,
182 interface: object.interface,
183 client_id: client.id.clone(),
184 };
185 let opcode = message.opcode;
186 let (arguments, is_destructor, created_id) =
187 match client.process_request(&object, message) {
188 Some(args) => args,
189 None => continue,
190 };
191 // Return the whole set to invoke the callback while handle is not borrower via client
192 DispatchAction::Request {
193 object,
194 object_id,
195 opcode,
196 arguments,
197 is_destructor,
198 created_id,
199 }
200 }
201 } else {
202 return Err(std::io::Error::new(
203 std::io::ErrorKind::InvalidInput,
204 "Invalid client ID",
205 ));
206 }
207 };
208 match action {
209 DispatchAction::Request {
210 object,
211 object_id,
212 opcode,
213 arguments,
214 is_destructor,
215 created_id,
216 } => {
217 // temporarily unlock the state Mutex while this request is dispatched
218 std::mem::drop(state);
219 let ret = object.data.user_data.clone().request(
220 &handle.clone(),
221 data,
222 ClientId { id: client_id.clone() },
223 Message {
224 sender_id: ObjectId { id: object_id.clone() },
225 opcode,
226 args: arguments,
227 },
228 );
229 if is_destructor {
230 object.data.user_data.clone().destroyed(
231 &handle.clone(),
232 data,
233 ClientId { id: client_id.clone() },
234 ObjectId { id: object_id.clone() },
235 );
236 }
237 // acquire the lock again and continue
238 state = self.state.lock().unwrap();
239 if is_destructor {
240 if let Ok(client) = state.clients.get_client_mut(client_id.clone()) {
241 client.send_delete_id(object_id);
242 }
243 }
244 match (created_id, ret) {
245 (Some(child_id), Some(child_data)) => {
246 if let Ok(client) = state.clients.get_client_mut(client_id.clone()) {
247 client
248 .map
249 .with(child_id.id, |obj| obj.data.user_data = child_data)
250 .unwrap();
251 }
252 }
253 (None, None) => {}
254 (Some(child_id), None) => {
255 // Allow the callback to not return any data if the client is already dead (typically
256 // if the callback provoked a protocol error)
257 if let Ok(client) = state.clients.get_client(client_id.clone()) {
258 if !client.killed {
259 panic!(
260 "Callback creating object {} did not provide any object data.",
261 child_id
262 );
263 }
264 }
265 }
266 (None, Some(_)) => {
267 panic!("An object data was returned from a callback not creating any object");
268 }
269 }
270 }
271 DispatchAction::Bind { object, client, global, handler } => {
272 // temporarily unlock the state Mutex while this request is dispatched
273 std::mem::drop(state);
274 let child_data = handler.bind(
275 &handle.clone(),
276 data,
277 ClientId { id: client.clone() },
278 GlobalId { id: global },
279 ObjectId { id: object.clone() },
280 );
281 // acquire the lock again and continue
282 state = self.state.lock().unwrap();
283 if let Ok(client) = state.clients.get_client_mut(client.clone()) {
284 client.map.with(object.id, |obj| obj.data.user_data = child_data).unwrap();
285 }
286 }
287 }
288 }
289 Ok(dispatched)
290 }
291}
292
293enum DispatchAction<D: 'static> {
294 Request {
295 object: Object<Data<D>>,
296 object_id: InnerObjectId,
297 opcode: u16,
298 arguments: SmallVec<[Argument<ObjectId, OwnedFd>; 4]>,
299 is_destructor: bool,
300 created_id: Option<InnerObjectId>,
301 },
302 Bind {
303 object: InnerObjectId,
304 client: InnerClientId,
305 global: InnerGlobalId,
306 handler: Arc<dyn GlobalHandler<D>>,
307 },
308}
309