wayland_backend/rs/server_impl/
common_poll.rs1use std::{
2 os::unix::io::{AsRawFd, BorrowedFd, OwnedFd},
3 sync::{Arc, Mutex},
4};
5
6use super::{
7 handle::State, ClientId, Data, GlobalHandler, GlobalId, Handle, InnerClientId, InnerGlobalId,
8 InnerHandle, InnerObjectId, ObjectId,
9};
10use crate::{
11 core_interfaces::{WL_DISPLAY_INTERFACE, WL_REGISTRY_INTERFACE},
12 protocol::{same_interface, Argument, Message},
13 rs::map::Object,
14 types::server::InitError,
15};
16
17#[cfg(any(target_os = "linux", target_os = "android", target_os = "redox"))]
18use rustix::event::{epoll, Timespec};
19
20#[cfg(any(
21 target_os = "dragonfly",
22 target_os = "freebsd",
23 target_os = "netbsd",
24 target_os = "openbsd",
25 target_os = "macos"
26))]
27use rustix::event::kqueue::*;
28use smallvec::SmallVec;
29
30#[derive(Debug)]
31pub struct InnerBackend<D: 'static> {
32 state: Arc<Mutex<State<D>>>,
33}
34
35impl<D> InnerBackend<D> {
36 pub fn new() -> Result<Self, InitError> {
37 #[cfg(any(target_os = "linux", target_os = "android", target_os = "redox"))]
38 let poll_fd = epoll::create(epoll::CreateFlags::CLOEXEC)
39 .map_err(Into::into)
40 .map_err(InitError::Io)?;
41
42 #[cfg(any(
43 target_os = "dragonfly",
44 target_os = "freebsd",
45 target_os = "netbsd",
46 target_os = "openbsd",
47 target_os = "macos"
48 ))]
49 let poll_fd = kqueue().map_err(Into::into).map_err(InitError::Io)?;
50
51 Ok(Self { state: Arc::new(Mutex::new(State::new(poll_fd))) })
52 }
53
54 pub fn flush(&self, client: Option<ClientId>) -> std::io::Result<()> {
55 self.state.lock().unwrap().flush(client)
56 }
57
58 pub fn handle(&self) -> Handle {
59 Handle { handle: InnerHandle { state: self.state.clone() as Arc<_> } }
60 }
61
62 pub fn poll_fd(&self) -> BorrowedFd<'_> {
63 let raw_fd = self.state.lock().unwrap().poll_fd.as_raw_fd();
64 unsafe { BorrowedFd::borrow_raw(raw_fd) }
67 }
68
69 pub fn dispatch_client(
70 &self,
71 data: &mut D,
72 client_id: InnerClientId,
73 ) -> std::io::Result<usize> {
74 let ret = self.dispatch_events_for(data, client_id);
75 let cleanup = self.state.lock().unwrap().cleanup();
76 cleanup(&self.handle(), data);
77 ret
78 }
79
80 #[cfg(any(target_os = "linux", target_os = "android", target_os = "redox"))]
81 pub fn dispatch_all_clients(&self, data: &mut D) -> std::io::Result<usize> {
82 use std::os::unix::io::AsFd;
83
84 let poll_fd = self.poll_fd();
85 let mut dispatched = 0;
86 let mut events = Vec::<epoll::Event>::with_capacity(32);
87 loop {
88 let buffer = rustix::buffer::spare_capacity(&mut events);
89 epoll::wait(poll_fd.as_fd(), buffer, Some(&Timespec::default()))?;
90
91 if events.is_empty() {
92 break;
93 }
94
95 for event in events.drain(..) {
96 let id = InnerClientId::from_u64(event.data.u64());
97 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 let mut events = Vec::<Event>::with_capacity(32);
122 loop {
123 let buffer = rustix::buffer::spare_capacity(&mut events);
124 let nevents = unsafe { kevent(&poll_fd, &[], buffer, Some(Duration::ZERO))? };
125
126 if nevents == 0 {
127 break;
128 }
129
130 for event in events.drain(..) {
131 let id = InnerClientId::from_u64(event.udata() as u64);
132 if let Ok(count) = self.dispatch_events_for(data, id) {
134 dispatched += count;
135 }
136 }
137 let cleanup = self.state.lock().unwrap().cleanup();
138 cleanup(&self.handle(), data);
139 }
140
141 Ok(dispatched)
142 }
143
144 pub(crate) fn dispatch_events_for(
145 &self,
146 data: &mut D,
147 client_id: InnerClientId,
148 ) -> std::io::Result<usize> {
149 let mut dispatched = 0;
150 let handle = self.handle();
151 let mut state = self.state.lock().unwrap();
152 loop {
153 let action = {
154 let state = &mut *state;
155 if let Ok(client) = state.clients.get_client_mut(client_id.clone()) {
156 let (message, object) = match client.next_request() {
157 Ok(v) => v,
158 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
159 if dispatched > 0 {
160 break;
161 } else {
162 return Err(e);
163 }
164 }
165 Err(e) => {
166 #[cfg(any(
167 target_os = "linux",
168 target_os = "android",
169 target_os = "redox"
170 ))]
171 {
172 epoll::delete(&state.poll_fd, client)?;
173 }
174
175 #[cfg(any(
176 target_os = "dragonfly",
177 target_os = "freebsd",
178 target_os = "netbsd",
179 target_os = "openbsd",
180 target_os = "macos"
181 ))]
182 {
183 use rustix::event::kqueue::*;
184 use std::os::unix::io::{AsFd, AsRawFd};
185
186 let evt = Event::new(
187 EventFilter::Read(client.as_fd().as_raw_fd()),
188 EventFlags::DELETE,
189 client_id.as_u64() as *mut _,
190 );
191
192 let events: &mut [Event] = &mut [];
193 unsafe {
194 kevent(&state.poll_fd, &[evt], events, None).map(|_| ())?;
195 }
196 }
197 return Err(e);
198 }
199 };
200 dispatched += 1;
201 if same_interface(object.interface, &WL_DISPLAY_INTERFACE) {
202 client.handle_display_request(message, &mut state.registry);
203 continue;
204 } else if same_interface(object.interface, &WL_REGISTRY_INTERFACE) {
205 if let Some((client, global, object, handler)) =
206 client.handle_registry_request(message, &mut state.registry)
207 {
208 DispatchAction::Bind { client, global, object, handler }
209 } else {
210 continue;
211 }
212 } else {
213 let object_id = InnerObjectId {
214 id: message.sender_id,
215 serial: object.data.serial,
216 interface: object.interface,
217 client_id: client.id.clone(),
218 };
219 let opcode = message.opcode;
220 let (arguments, is_destructor, created_id) =
221 match client.process_request(&object, message) {
222 Some(args) => args,
223 None => continue,
224 };
225 DispatchAction::Request {
227 object,
228 object_id,
229 opcode,
230 arguments,
231 is_destructor,
232 created_id,
233 }
234 }
235 } else {
236 return Err(std::io::Error::new(
237 std::io::ErrorKind::InvalidInput,
238 "Invalid client ID",
239 ));
240 }
241 };
242 match action {
243 DispatchAction::Request {
244 object,
245 object_id,
246 opcode,
247 arguments,
248 is_destructor,
249 created_id,
250 } => {
251 std::mem::drop(state);
253 let ret = object.data.user_data.clone().request(
254 &handle.clone(),
255 data,
256 ClientId { id: client_id.clone() },
257 Message {
258 sender_id: ObjectId { id: object_id.clone() },
259 opcode,
260 args: arguments,
261 },
262 );
263 if is_destructor {
264 object.data.user_data.clone().destroyed(
265 &handle.clone(),
266 data,
267 ClientId { id: client_id.clone() },
268 ObjectId { id: object_id.clone() },
269 );
270 }
271 state = self.state.lock().unwrap();
273 if is_destructor {
274 if let Ok(client) = state.clients.get_client_mut(client_id.clone()) {
275 client.send_delete_id(object_id);
276 }
277 }
278 match (created_id, ret) {
279 (Some(child_id), Some(child_data)) => {
280 if let Ok(client) = state.clients.get_client_mut(client_id.clone()) {
281 client
282 .map
283 .with(child_id.id, |obj| obj.data.user_data = child_data)
284 .unwrap();
285 }
286 }
287 (None, None) => {}
288 (Some(child_id), None) => {
289 if let Ok(client) = state.clients.get_client(client_id.clone()) {
292 if !client.killed {
293 panic!(
294 "Callback creating object {child_id} did not provide any object data."
295 );
296 }
297 }
298 }
299 (None, Some(_)) => {
300 panic!("An object data was returned from a callback not creating any object");
301 }
302 }
303 std::mem::drop(state);
306 std::mem::drop(object);
307 state = self.state.lock().unwrap();
308 }
309 DispatchAction::Bind { object, client, global, handler } => {
310 std::mem::drop(state);
312 let child_data = handler.bind(
313 &handle.clone(),
314 data,
315 ClientId { id: client.clone() },
316 GlobalId { id: global },
317 ObjectId { id: object.clone() },
318 );
319 state = self.state.lock().unwrap();
321 if let Ok(client) = state.clients.get_client_mut(client.clone()) {
322 client.map.with(object.id, |obj| obj.data.user_data = child_data).unwrap();
323 }
324 }
325 }
326 }
327 Ok(dispatched)
328 }
329}
330
331enum DispatchAction<D: 'static> {
332 Request {
333 object: Object<Data<D>>,
334 object_id: InnerObjectId,
335 opcode: u16,
336 arguments: SmallVec<[Argument<ObjectId, OwnedFd>; 4]>,
337 is_destructor: bool,
338 created_id: Option<InnerObjectId>,
339 },
340 Bind {
341 object: InnerObjectId,
342 client: InnerClientId,
343 global: InnerGlobalId,
344 handler: Arc<dyn GlobalHandler<D>>,
345 },
346}