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