wl_client/proxy/low_level/owned/scope.rs
1#[expect(unused_imports)]
2use crate::Connection;
3#[expect(unused_imports)]
4use crate::proxy;
5use {
6 crate::{
7 DispatchLock, Queue,
8 builder::prelude::{CreateEventHandler, EventHandler, UntypedBorrowedProxy},
9 ffi::{wl_argument, wl_interface, wl_message},
10 proxy::{
11 OwnedProxy, get_owned,
12 low_level::{
13 OwnedProxyRegistry, ProxyDataDestruction,
14 owned::{UntypedOwnedProxyData, event_handler_func},
15 },
16 },
17 utils::{
18 on_drop::abort_on_panic,
19 sync_cell::{SyncCell, SyncUnsafeCell},
20 },
21 },
22 parking_lot::{Condvar, Mutex},
23 run_on_drop::on_drop,
24 std::{
25 any::TypeId,
26 ffi::{c_int, c_void},
27 future::poll_fn,
28 marker::PhantomData,
29 mem,
30 pin::pin,
31 ptr::NonNull,
32 sync::{Arc, atomic::Ordering::Relaxed},
33 },
34};
35
36#[cfg(test)]
37mod tests;
38
39/// A scope for event handlers with shorter than `'static` lifetime.
40///
41/// Scopes are created by calling [`Queue::dispatch_scope_blocking`] and
42/// [`Queue::dispatch_scope_async`].
43///
44/// Event handlers attached via a scope have the following, additional restriction: they
45/// will be dropped and therefore not be invoked after the lifetime of the scope has
46/// ended. The proxies can still be used to send requests or as arguments, but no event
47/// callbacks will be invoked. Instead, the [`OwnedProxy::NO_OP_EVENT_HANDLER`] will be
48/// invoked to prevent any memory leaks.
49///
50/// Async scopes created via [`Queue::dispatch_scope_async`] have one more restriction:
51/// event handlers will only be invoked while the returned future is being polled. Until
52/// the future completes, the queue should therefore only be dispatched from inside the
53/// future.
54///
55/// # Example
56///
57/// ```
58/// # use std::cell::Cell;
59/// # use wl_client::Libwayland;
60/// # use wl_client::test_protocols::core::wl_callback::WlCallback;
61/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
62/// #
63/// let lib = Libwayland::open().unwrap();
64/// let con = lib.connect_to_default_display().unwrap();
65/// let queue = con.create_local_queue(c"queue name");
66///
67/// let sync = queue.display::<WlDisplay>().sync();
68/// let done = Cell::new(false);
69/// queue.dispatch_scope_blocking(|scope| {
70/// scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
71/// queue.dispatch_roundtrip_blocking().unwrap();
72/// });
73/// assert!(done.get());
74/// ```
75pub struct Scope<'scope, 'env: 'scope> {
76 /// Shared data of the scope. This data is kept alive even after the scope has ended
77 /// so that proxies can continue to refer to it and check the may_dispatch field.
78 pub(super) data: Arc<ScopeData>,
79 /// Ensure that 'scope and 'env are invariant. If 'scope were covariant, applications
80 /// could use this to attach an event handler with a lifetime shorter than the
81 /// original 'scope. Non-contravariance and non-any-variance of 'env is not required
82 /// but keeps things in line with [`std::thread::Scope`].
83 _inv_scope: PhantomData<&'scope mut &'scope mut ()>,
84 _inv_env: PhantomData<&'env mut &'env mut ()>,
85}
86
87pub(super) struct ScopeData {
88 /// The queue that this scope belongs to.
89 queue: Queue,
90 /// This field is protected by the queue lock. We define the following terms:
91 ///
92 /// - A system stack frame is any stack frame defined by the functions
93 ///
94 /// - `dispatch_scope_blocking`
95 /// - `dispatch_scope_async`
96 ///
97 /// including any closures therein and the stack frame invoking the closures.
98 ///
99 /// - A user stack frame is any other stack frame.
100 ///
101 /// To simplify the invariants below, we coalesce all adjacent system stack frames.
102 /// That is, if we have system stack frames S1, S2, S3 where S1 calls S2 and S3, then
103 /// we treat S1, S2, and S3 as a single system stack frame. Here, S2 and S3 are the
104 /// closures defined in the functions above.
105 ///
106 /// This field has the following invariants:
107 ///
108 /// - It is only modified by system stack frames.
109 /// - If it is set to true by a system stack frame, then it is set back to false by
110 /// the same stack frame.
111 /// - If it is set to true, then it is not modified again before being set to false as
112 /// described in the previous bullet point.
113 ///
114 /// It follows that
115 ///
116 /// - For any user stack frame, the value of this field is constant during the
117 /// execution of the frame. (A child stack frame might modify the value but it will
118 /// be reset before returning.)
119 /// - If the value of the field is `false`, then it has always been false during the
120 /// execution of any user parent stack frame.
121 may_dispatch: SyncCell<bool>,
122 /// This field is protected by the queue lock. This field has the following invariant:
123 /// It is false if and only if
124 ///
125 /// - none of the event handlers attached via the scope are currently being referenced
126 /// by a dispatcher
127 /// - none of the event handlers attached via the scope will ever again be referenced
128 /// by a dispatcher
129 /// - we're still within 'scope or all of the event handlers attached via the scope
130 /// have already been dropped
131 defer_destruction: SyncCell<bool>,
132 /// This field is protected by the queue lock. This field contains the number of event
133 /// handlers attached through this scope that a) have a drop impl and b) have not yet
134 /// had their drop impl run. We use this to ensure the following invariant:
135 ///
136 /// - before the end of 'scope, all event handlers have been dropped or the remaining
137 /// event handlers are leaked.
138 live_event_handlers: SyncCell<u64>,
139 /// This field is protected by the queue lock. If, after the scope has performed
140 /// cleanup in [`Scope::drop`], live_event_handlers is still not 0, then other
141 /// threads must currently be destroying the remaining event handlers. In this case we
142 /// set this field to true to let those destructors know that they must set
143 /// last_event_handler_destroyed to true once live_event_handlers reaches 0.
144 awaiting_last_destruction: SyncCell<bool>,
145 /// See the destruction of awaiting_last_destruction for how the following two fields
146 /// are used.
147 last_event_handler_destroyed: Mutex<bool>,
148 last_event_handler_condvar: Condvar,
149 /// The registry that registers all `Drop`-able proxies that had an event handler
150 /// attached via this scope.
151 pub(super) registry: OwnedProxyRegistry,
152 /// This field is protected by the queue lock. No long-lived references must be
153 /// created to the vector to avoid conflicting access.
154 ///
155 /// The contained destructions have the following property: It must be safe to run the
156 /// destruction once there are no ongoing dispatches of the event handler.
157 destructions: SyncUnsafeCell<Vec<ProxyDataDestruction>>,
158}
159
160impl Queue {
161 /// Creates a blocking scope for event handlers with shorter than `'static` lifetime.
162 ///
163 /// The scope can be used to attach event handlers to proxies. The following
164 /// restriction applies: Such event handlers will only be invoked while inside this
165 /// function. Once this function returns, the [`OwnedProxy::NO_OP_EVENT_HANDLER`] of
166 /// the proxy is invoked instead.
167 ///
168 /// # Panic
169 ///
170 /// Panics if this is a [local queue](Connection::create_local_queue) and the current
171 /// thread is not the thread that this queue was created in.
172 ///
173 /// # Example
174 ///
175 /// ```
176 /// # use std::cell::Cell;
177 /// # use wl_client::Libwayland;
178 /// # use wl_client::test_protocols::core::wl_callback::WlCallback;
179 /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
180 /// #
181 /// let lib = Libwayland::open().unwrap();
182 /// let con = lib.connect_to_default_display().unwrap();
183 /// let queue = con.create_local_queue(c"queue name");
184 ///
185 /// let sync = queue.display::<WlDisplay>().sync();
186 /// let done = Cell::new(false);
187 /// queue.dispatch_scope_blocking(|scope| {
188 /// scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
189 /// queue.dispatch_roundtrip_blocking().unwrap();
190 /// });
191 /// assert!(done.get());
192 /// ```
193 pub fn dispatch_scope_blocking<'env, T, F>(&self, f: F) -> T
194 where
195 F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
196 {
197 let scope = Scope::new(self);
198 {
199 let _lock = self.lock_dispatch();
200 // SAFETY: - We're holding the queue lock.
201 // - _cleanup will set may_dispatch to false, or abort, before
202 // returning to the parent.
203 // - No other code modifies may_dispatch before this function call
204 // returns.
205 unsafe {
206 scope.data.may_dispatch.set(true);
207 }
208 }
209 let _cleanup = on_drop(|| {
210 let lock = abort_on_panic(|| self.lock_dispatch());
211 // SAFETY: - We're holding the queue lock.
212 unsafe {
213 scope.data.may_dispatch.set(false);
214 }
215 // SAFETY: - This function runs when dispatch_scope_blocking returns,
216 // therefore may_dispatch can never again become true.
217 unsafe {
218 scope.drop(Some(lock));
219 }
220 });
221 f(&scope)
222 }
223
224 /// Creates an async scope for event handlers with shorter than `'static` lifetime.
225 ///
226 /// The scope can be used to attach event handlers to proxies. The following
227 /// restriction applies: Such event handlers will only be invoked while the future is
228 /// being polled. If an event needs to be dispatched in any other situation, the
229 /// [`OwnedProxy::NO_OP_EVENT_HANDLER`] of the proxy is invoked instead.
230 ///
231 /// In particular, dispatching the queue from a outside this future while this future
232 /// exists is unlikely to have the desired effect.
233 ///
234 /// # Panic
235 ///
236 /// Panics if this is a [local queue](Connection::create_local_queue) and the thread
237 /// polling the future is not the thread that this queue was created in.
238 ///
239 /// # Example
240 ///
241 /// ```
242 /// # use std::cell::Cell;
243 /// # use wl_client::Libwayland;
244 /// # use wl_client::test_protocols::core::wl_callback::WlCallback;
245 /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
246 /// #
247 /// # tokio_test::block_on(async {
248 /// let lib = Libwayland::open().unwrap();
249 /// let con = lib.connect_to_default_display().unwrap();
250 /// let queue = con.create_local_queue(c"queue name");
251 ///
252 /// let sync = queue.display::<WlDisplay>().sync();
253 /// let done = Cell::new(false);
254 /// queue.dispatch_scope_async(async |scope| {
255 /// scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
256 /// queue.dispatch_roundtrip_async().await.unwrap();
257 /// }).await;
258 /// assert!(done.get());
259 /// # });
260 /// ```
261 pub async fn dispatch_scope_async<'env, T, F>(&self, f: F) -> T
262 where
263 F: for<'scope> AsyncFnOnce(&'scope Scope<'scope, 'env>) -> T,
264 {
265 let scope = Scope::new(self);
266 let _cleanup = on_drop(|| {
267 // SAFETY: - This function runs when the future created by
268 // dispatch_scope_async is dropped or completes, therefore
269 // may_dispatch can never again become true.
270 unsafe {
271 scope.drop(None);
272 }
273 });
274 let mut fut = pin!(f(&scope));
275 poll_fn(|ctx| {
276 {
277 let _lock = self.lock_dispatch();
278 // SAFETY: - We're holding the queue lock.
279 // - _cleanup will set may_dispatch to false, or abort, before the
280 // poll function returns.
281 // - The execution of this function implies `&mut` access to the
282 // future. Therefore may_dispatch is not modified again until
283 // this function returns.
284 unsafe {
285 scope.data.may_dispatch.set(true);
286 }
287 }
288 let _cleanup = on_drop(|| {
289 let _lock = abort_on_panic(|| self.lock_dispatch());
290 // SAFETY: - We're holding the queue lock.
291 unsafe {
292 scope.data.may_dispatch.set(false);
293 }
294 // SAFETY: - We're holding the queue lock.
295 // - We just set may_dispatch to false.
296 unsafe {
297 scope.run_destructions(true);
298 }
299 });
300 fut.as_mut().poll(ctx)
301 })
302 .await
303 }
304}
305
306impl<'scope> Scope<'scope, '_> {
307 fn new(queue: &Queue) -> Self {
308 Scope {
309 data: Arc::new(ScopeData {
310 queue: queue.clone(),
311 may_dispatch: SyncCell::new(false),
312 defer_destruction: SyncCell::new(true),
313 live_event_handlers: SyncCell::new(0),
314 awaiting_last_destruction: SyncCell::new(false),
315 last_event_handler_destroyed: Default::default(),
316 last_event_handler_condvar: Default::default(),
317 registry: Default::default(),
318 destructions: SyncUnsafeCell::new(Vec::new()),
319 }),
320 _inv_scope: Default::default(),
321 _inv_env: Default::default(),
322 }
323 }
324
325 /// # Safety
326 ///
327 /// - may_dispatch must be false and must always stay false.
328 unsafe fn drop(&'scope self, lock: Option<DispatchLock<'_>>) {
329 let lock = lock.unwrap_or_else(|| self.data.queue.lock_dispatch());
330 // SAFETY: - We are holding the queue lock.
331 // - Since we are holding the queue lock and may_dispatch is and stays
332 // false, event_handler_func_scoped prevents any future access to any
333 // of the event handlers attached via this scope.
334 // - Since may_dispatch is false, by the invariants of may_dispatch,
335 // may_dispatch has always been false in any parent user stack frame.
336 // Therefore, if any parent stack frame is an execution of
337 // event_handler_func_scoped, that execution is calling the no-op event
338 // handler. Therefore, there is currently no execution of any event
339 // handler attached via this scope.
340 // - This function will block until all event handlers have been dropped.
341 // Should this function panic, the following on_drop handler will set
342 // defer_destruction back to true before the end of 'scope.
343 unsafe {
344 self.data.defer_destruction.set(false);
345 }
346 // If this function panics, then we must reset defer_destruction before the end
347 // of 'scope. This ensures that event handler drop impls that have not yet run
348 // will be leaked.
349 let reset_defer_destruction = on_drop(|| {
350 self.data.queue.run_locked(|| {
351 // SAFETY: run_locked holds the queue lock.
352 unsafe {
353 self.data.defer_destruction.set(true);
354 }
355 });
356 });
357 // SAFETY: - All proxies in the registry belong to this scope.
358 // - We're holding a reference to &'scope self.
359 // - We're holding the queue lock.
360 // - By the same logic as in the previous safety comment, there are no
361 // ongoing dispatches and there won't be any in the future.
362 unsafe {
363 self.data.registry.destroy_event_handlers();
364 }
365 // SAFETY: - We're holding the queue lock.
366 // - By the safety requirements of this function, may_dispatch is false.
367 unsafe {
368 self.run_destructions(false);
369 }
370 // SAFETY: - We're holding the queue lock.
371 let live_event_handlers = unsafe { self.data.live_event_handlers.get() };
372 // This can only happen if a proxy was removed from the registry in another thread
373 // before destroy_event_handlers collected them but whose destruction has not yet
374 // run. Since defer_destruction is false, the destruction should run very soon.
375 // We have to block here until that has happened so that the drop impl completes
376 // before the end of 'scope.
377 if live_event_handlers > 0 {
378 // SAFETY: - We're holding the queue lock.
379 unsafe {
380 self.data.awaiting_last_destruction.set(true);
381 }
382 drop(lock);
383 let mut done = self.data.last_event_handler_destroyed.lock();
384 while !*done {
385 self.data.last_event_handler_condvar.wait(&mut done);
386 }
387 }
388 reset_defer_destruction.forget();
389 }
390
391 /// # Safety
392 ///
393 /// - The queue lock must be held.
394 /// - may_dispatch must be false
395 unsafe fn run_destructions(&self, re_use_memory: bool) {
396 let mut stash = vec![];
397 // SAFETY: - destructions is only ever accessed with the queue lock held
398 // - no long-lived references to destructions are ever created
399 mem::swap(&mut stash, unsafe { &mut *self.data.destructions.get() });
400 for destruction in stash.drain(..) {
401 // SAFETY: - destructions only contains destructions such that it is safe to
402 // run the destruction once there are no ongoing dispatches of the
403 // event handler.
404 // - Since may_dispatch is false, by the invariants of may_dispatch,
405 // it has always been false in any parent stack frame.
406 // Therefore, if any parent stack frame is an execution of
407 // event_handler_func_scoped, that execution is calling the no-op
408 // event handler. Therefore, there can be no dispatch referencing
409 // the event handler going on.
410 unsafe {
411 destruction.run();
412 }
413 }
414 if re_use_memory {
415 // SAFETY: - destructions is only ever accessed with the queue lock held
416 // - no long-lived references to destructions are ever created
417 mem::swap(&mut stash, unsafe { &mut *self.data.destructions.get() });
418 assert!(stash.is_empty());
419 }
420 }
421
422 /// Sets the event handler of the proxy.
423 ///
424 /// This function is the same as [`proxy::set_event_handler`] except that the event
425 /// handler does not have to implement `'static` and that the event handler will not
426 /// be invoked after `'scope`.
427 ///
428 /// The proxy must belong to the queue that was used to create this scope.
429 ///
430 /// # Panic
431 ///
432 /// This function panics whenever [`proxy::set_event_handler`] panics and also if the
433 /// proxy does not belong to the queue that was used to create this scope.
434 ///
435 /// # Example
436 ///
437 /// ```
438 /// # use std::sync::Arc;
439 /// # use std::sync::atomic::AtomicBool;
440 /// # use std::sync::atomic::Ordering::Relaxed;
441 /// # use wl_client::{proxy, Libwayland};
442 /// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
443 /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
444 /// #
445 /// let lib = Libwayland::open().unwrap();
446 /// let con = lib.connect_to_default_display().unwrap();
447 /// let queue = con.create_queue(c"queue name");
448 /// let display: WlDisplay = queue.display();
449 /// let sync = display.sync();
450 /// let done = AtomicBool::new(false);
451 ///
452 /// queue.dispatch_scope_blocking(|scope| {
453 /// // Attach the event handler.
454 /// scope.set_event_handler(&sync, WlCallback::on_done(|_, _| done.store(true, Relaxed)));
455 ///
456 /// // Wait for the compositor to send the `done` message.
457 /// queue.dispatch_roundtrip_blocking().unwrap();
458 /// });
459 ///
460 /// // The event handler sets the value to `true`.
461 /// assert!(done.load(Relaxed));
462 /// ```
463 #[inline]
464 pub fn set_event_handler<P, H>(&'scope self, proxy: &P, handler: H)
465 where
466 P: OwnedProxy,
467 P::Api: CreateEventHandler<H>,
468 <P::Api as CreateEventHandler<H>>::EventHandler: Send + 'scope,
469 {
470 // SAFETY: - The event handler is Send
471 unsafe {
472 set_event_handler(self, proxy, P::Api::create_event_handler(handler));
473 }
474 }
475
476 /// Sets the `!Send` event handler of the proxy.
477 ///
478 /// This function is the same as [`proxy::set_event_handler_local`] except that the
479 /// event handler does not have to implement `'static` and that the event handler will
480 /// not be invoked after `'scope`.
481 ///
482 /// The proxy must belong to the queue that was used to create this scope.
483 ///
484 /// # Panic
485 ///
486 /// This function panics whenever [`proxy::set_event_handler_local`] panics and also
487 /// if the proxy does not belong to the queue that was used to create this scope.
488 ///
489 /// # Example
490 ///
491 /// ```
492 /// # use std::cell::Cell;
493 /// # use std::rc::Rc;
494 /// # use std::sync::atomic::Ordering::Relaxed;
495 /// # use wl_client::{proxy, Libwayland};
496 /// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
497 /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
498 /// #
499 /// let lib = Libwayland::open().unwrap();
500 /// let con = lib.connect_to_default_display().unwrap();
501 /// let queue = con.create_local_queue(c"queue name");
502 /// let display: WlDisplay = queue.display();
503 /// let sync = display.sync();
504 /// let done = Cell::new(false);
505 ///
506 /// queue.dispatch_scope_blocking(|scope| {
507 /// // Attach the event handler.
508 /// scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
509 ///
510 /// // Wait for the compositor to send the `done` message.
511 /// queue.dispatch_roundtrip_blocking().unwrap();
512 /// });
513 ///
514 /// // The event handler sets the value to `true`.
515 /// assert!(done.get());
516 /// ```
517 #[inline]
518 pub fn set_event_handler_local<P, H>(&'scope self, proxy: &P, handler: H)
519 where
520 P: OwnedProxy,
521 P::Api: CreateEventHandler<H>,
522 <P::Api as CreateEventHandler<H>>::EventHandler: 'scope,
523 {
524 if self.data.queue.is_non_local() {
525 panic!("Queue is not a local queue");
526 }
527 // SAFETY: - We've checked that the queue is a local queue.
528 unsafe {
529 set_event_handler(self, proxy, P::Api::create_event_handler(handler));
530 }
531 }
532}
533
534struct ScopeEventHandler<H, D> {
535 event_handler: H,
536 _on_drop: D,
537}
538
539unsafe impl<H, D> EventHandler for ScopeEventHandler<H, D>
540where
541 H: EventHandler,
542{
543 const WL_INTERFACE: &'static wl_interface = H::WL_INTERFACE;
544
545 #[inline]
546 fn mutable_type() -> Option<(TypeId, &'static str)> {
547 H::mutable_type()
548 }
549
550 #[inline]
551 unsafe fn handle_event(
552 &self,
553 queue: &Queue,
554 data: *mut u8,
555 slf: &UntypedBorrowedProxy,
556 opcode: u32,
557 args: *mut wl_argument,
558 ) {
559 unsafe {
560 self.event_handler
561 .handle_event(queue, data, slf, opcode, args);
562 }
563 }
564}
565
566/// # Safety
567///
568/// - if T does not implement Send, then the queue must be a local queue
569unsafe fn set_event_handler<'scope, P, H>(
570 scope: &'scope Scope<'scope, '_>,
571 proxy: &P,
572 event_handler: H,
573) where
574 P: OwnedProxy,
575 H: EventHandler + 'scope,
576{
577 if mem::needs_drop::<H>() {
578 let data = scope.data.clone();
579 let event_handler = ScopeEventHandler {
580 event_handler,
581 _on_drop: on_drop(move || {
582 let d = &*data;
583 let leh = &d.live_event_handlers;
584 // SAFETY: the scope lock is held while dropping event handlers.
585 let live = unsafe { leh.get() };
586 // SAFETY: the scope lock is held while dropping event handlers.
587 unsafe {
588 leh.set(live - 1);
589 }
590 // SAFETY: the scope lock is held while dropping event handlers.
591 let awaiting_last_destruction = unsafe { d.awaiting_last_destruction.get() };
592 if live == 1 && awaiting_last_destruction {
593 *d.last_event_handler_destroyed.lock() = true;
594 d.last_event_handler_condvar.notify_all();
595 }
596 }),
597 };
598 scope.data.queue.run_locked(|| {
599 let leh = &scope.data.live_event_handlers;
600 // SAFETY: We're holding the queue lock.
601 unsafe {
602 leh.set(leh.get() + 1);
603 }
604 });
605 // SAFETY: The requirements are forwarded to the caller.
606 unsafe {
607 set_event_handler2(scope, proxy, event_handler);
608 }
609 } else {
610 // SAFETY: The requirements are forwarded to the caller.
611 unsafe {
612 set_event_handler2(scope, proxy, event_handler);
613 }
614 }
615}
616
617/// # Safety
618///
619/// - if T does not implement Send, then the queue must be a local queue
620unsafe fn set_event_handler2<'scope, P, H>(
621 scope: &'scope Scope<'scope, '_>,
622 proxy: &P,
623 event_handler: H,
624) where
625 P: OwnedProxy,
626 H: EventHandler + 'scope,
627{
628 let proxy = get_owned(proxy);
629 assert_eq!(proxy.queue(), &scope.data.queue);
630 // SAFETY: - all requirements except the callability of event_handler_func as part
631 // of a libwayland dispatch are trivially satisfied
632 // - libwayland only ever calls event handlers while preserving a
633 // valid pointer to the proxy and all pointers in args
634 // - set_event_handler4 checks that the interface of the proxy is
635 // H::WL_INTERFACE
636 // - by the safety requirements, P::WL_INTERFACE is compatible with the
637 // proxy's interface which is compatible with H::WL_INTERFACE by the
638 // previous point
639 // - libwayland ensures that opcode and args conform to the
640 // interface before calling the event handler
641 // - set_event_handler4 sets event_handler to a pointer to H
642 // - if T is not Send, then this function requires that this is a
643 // local queue which will panic when trying to call this function
644 // or any dispatching function on a thread other than the thread
645 // on which the queue was created
646 // - we always hold the queue lock while dispatching
647 // - set_event_handler4 sets the scope_data to a pointer to the scope data
648 // and stores a clone of the Arc so that the pointer will always remain
649 // valid
650 // - we only ever invalidate the self.event_handler or self.data
651 // pointers via handle_destruction which requires that it is safe to run
652 // the destruction.
653 // - handle_destruction does not run destructions unless defer_destruction is
654 // false or run_destructions is called.
655 // - run_destructions is only ever called within 'scope and
656 // - defer_destruction is only set to true in drop which blocks until all
657 // event handlers have been destroyed.
658 unsafe {
659 proxy.set_event_handler3(
660 event_handler,
661 event_handler_func_scoped::<P, H>,
662 Some(scope),
663 );
664 }
665}
666
667impl ScopeData {
668 /// Handles the destruction of proxies attached to this scope.
669 ///
670 /// If this is called within `'scope`, the destruction is either never runs or runs
671 /// also within `'scope`.
672 ///
673 /// # Safety
674 ///
675 /// - The proxy must be attached to this scope.
676 /// - It must be safe to run the destruction once there are no ongoing dispatches
677 /// of the event handler of the proxy.
678 pub(super) unsafe fn handle_destruction(&self, destruction: ProxyDataDestruction) {
679 let _lock = self.queue.lock_dispatch();
680 // SAFETY: - we're holding the queue lock
681 match unsafe { self.defer_destruction.get() } {
682 true => {
683 // SAFETY: - destructions is only ever accessed with the queue lock held
684 // - no long-lived references to destructions are ever created
685 let destructions = unsafe { &mut *self.destructions.get() };
686 // SAFETY: - the destructions in destructions are only run within
687 // 'scope, if ever.
688 destructions.push(destruction);
689 }
690 false => {
691 // SAFETY: - by the invariants, defer_destruction being false implies
692 // that all dispatcher uses of the event handler have
693 // ceased and if destruction contains an event handlers then we
694 // are still within 'scope
695 unsafe { destruction.run() }
696 }
697 }
698 }
699}
700
701/// The event handler function for scoped event handlers.
702///
703/// This function is the same as [`event_handler_func`] except that it additionally checks
704/// that [`ScopeData::may_dispatch`] is true. If it is not, then, instead of calling the
705/// normal event handler, [`P::NO_OP_EVENT_HANDLER`] is called.
706///
707/// This allows the event handler to be destroyed long before the proxy itself is
708/// destroyed as long as `may_dispatch` remains false afterwards.
709///
710/// # Safety
711///
712/// - event_handler_data must be a pointer to UntypedOwnedProxyData
713/// - the scope_data field in the UntypedOwnedProxy must contain a pointer to ScopeData
714/// - the queue lock of the proxy must be held
715/// - if scope_data.may_dispatch, then all safety requirements of event_handler_func::<T>
716/// must be satisfied
717/// - the interface of the proxy must be compatible with P::WL_INTERFACE
718/// - P::WL_INTERFACE and T::WL_INTERFACE must be compatible
719unsafe extern "C" fn event_handler_func_scoped<P, T>(
720 event_handler_data: *const c_void,
721 target: *mut c_void,
722 opcode: u32,
723 msg: *const wl_message,
724 args: *mut wl_argument,
725) -> c_int
726where
727 P: OwnedProxy,
728 T: EventHandler,
729{
730 // SAFETY: By the safety requirements of this function, event_handler is a valid pointer
731 // to UntypedOwnedProxyData.
732 let proxy_data = unsafe { &*(event_handler_data as *const UntypedOwnedProxyData) };
733 // SAFETY: Dito, scope_data is a valid pointer.
734 let scope_data = unsafe { &*proxy_data.scope_data.load(Relaxed) };
735 // SAFETY: Dito, the queue lock is being held.
736 if unsafe { scope_data.may_dispatch.get() } {
737 // SAFETY: Dito, since may_dispatch is true, all safety requirements of
738 // event_handler_func are satisfied.
739 return unsafe { event_handler_func::<T>(event_handler_data, target, opcode, msg, args) };
740 }
741 // SAFETY: Dito, target is and stays valid.
742 let target = unsafe { NonNull::new_unchecked(target.cast()) };
743 // SAFETY: Dito, target is and stays valid.
744 let target =
745 unsafe { UntypedBorrowedProxy::new_immutable(proxy_data.proxy.libwayland, target) };
746 // SAFETY: Dito, the queue lock is being held.
747 let data = unsafe { proxy_data.queue.data() };
748 // SAFETY: - Dito, the interface of the proxy is compatible with P::WL_INTERFACE
749 // - Dito, target is a valid pointer and stays valid
750 // - Dito, opcode and args conform to P::WL_INTERFACE
751 // - The mutable_type of the NO_OP_EVENT_HANDLER is required to be `None` or
752 // the type ID of `()`. If it is `None`, then there is nothing to show.
753 // Otherwise, Queue::data guarantees that `data` can be dereferenced to
754 // `T::mutable_type` or `()` if `mutable_type` returns None. Any non-null
755 // pointer can be dereferenced to `()`.
756 unsafe {
757 P::NO_OP_EVENT_HANDLER.handle_event(&proxy_data.queue, data, &target, opcode, args);
758 }
759 0
760}