Skip to content

Commit 10b6ff0

Browse files
committed
backend: Add destroy_object method
This is needed for implementing the `wl_fixes` protocol. It should also make it possible to handle the requirement in `zwlr_output_configuration_v1::destroy` to destroy the `wlr_output_configuration_head`.
1 parent c23ed41 commit 10b6ff0

File tree

8 files changed

+119
-27
lines changed

8 files changed

+119
-27
lines changed

wayland-backend/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
### Additions
6+
- backend: Added a `destroy_object` method
7+
58
### Bugfixes
69

710
- backend/rs: Prevent a potential deadlock during client cleanup

wayland-backend/src/client_api.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,17 @@ impl Backend {
214214
self.backend.info(id)
215215
}
216216

217+
/// Destroy an object
218+
///
219+
/// For most protocols, this is handled automatically when a destructor
220+
/// message is sent or received.
221+
///
222+
/// This corresponds to `wl_proxy_destroy` in the C API. Or a `_destroy`
223+
/// method generated for an object without a destructor request.
224+
pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
225+
self.backend.destroy_object(id)
226+
}
227+
217228
/// Sends a request to the server
218229
///
219230
/// Returns an error if the sender ID of the provided message is no longer valid.

wayland-backend/src/rs/client_impl/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,19 @@ impl InnerBackend {
298298
ObjectId { id: InnerObjectId { serial: 0, id: 0, interface: &ANONYMOUS_INTERFACE } }
299299
}
300300

301+
pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
302+
let mut guard = self.state.lock_protocol();
303+
let object = guard.get_object(id.id.clone())?;
304+
guard
305+
.map
306+
.with(id.id.id, |obj| {
307+
obj.data.client_destroyed = true;
308+
})
309+
.unwrap();
310+
object.data.user_data.destroyed(id.clone());
311+
Ok(())
312+
}
313+
301314
pub fn send_request(
302315
&self,
303316
Message { sender_id: ObjectId { id }, opcode, args }: Message<ObjectId, RawFd>,

wayland-backend/src/rs/server_impl/client.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ impl<D> Client<D> {
101101
InnerObjectId { id, serial, client_id: self.id.clone(), interface }
102102
}
103103

104+
pub(crate) fn destroy_object(
105+
&mut self,
106+
id: InnerObjectId,
107+
pending_destructors: &mut Vec<super::handle::PendingDestructor<D>>,
108+
) -> Result<(), InvalidId> {
109+
let object = self.get_object(id.clone())?;
110+
pending_destructors.push((object.data.user_data.clone(), self.id.clone(), id.clone()));
111+
self.send_delete_id(id.clone());
112+
Ok(())
113+
}
114+
104115
pub(crate) fn object_info(&self, id: InnerObjectId) -> Result<ObjectInfo, InvalidId> {
105116
let object = self.get_object(id.clone())?;
106117
Ok(ObjectInfo { id: id.id, interface: object.interface, version: object.version })
@@ -201,7 +212,6 @@ impl<D> Client<D> {
201212

202213
// Handle destruction if relevant
203214
if message_desc.is_destructor {
204-
self.map.remove(object_id.id.id);
205215
if let Some(vec) = pending_destructors {
206216
vec.push((object.data.user_data.clone(), self.id.clone(), object_id.id.clone()));
207217
}
@@ -378,7 +388,7 @@ impl<D> Client<D> {
378388
}
379389
}
380390

381-
fn get_object(&self, id: InnerObjectId) -> Result<Object<Data<D>>, InvalidId> {
391+
pub(crate) fn get_object(&self, id: InnerObjectId) -> Result<Object<Data<D>>, InvalidId> {
382392
let object = self.map.find(id.id).ok_or(InvalidId)?;
383393
if object.data.serial != id.serial {
384394
return Err(InvalidId);

wayland-backend/src/rs/server_impl/handle.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@ impl InnerHandle {
165165
Ok(ObjectId { id: client.create_object(interface, version, data) })
166166
}
167167

168+
pub fn destroy_object<D: 'static>(&self, id: &ObjectId) -> Result<(), InvalidId> {
169+
let mut state = self.state.lock().unwrap();
170+
let state = (&mut *state as &mut dyn ErasedState)
171+
.downcast_mut::<State<D>>()
172+
.expect("Wrong type parameter passed to Handle::destroy_object().");
173+
let client = state.clients.get_client_mut(id.id.client_id.clone())?;
174+
client.destroy_object(id.id.clone(), &mut state.pending_destructors)
175+
}
176+
168177
pub fn null_id() -> ObjectId {
169178
ObjectId {
170179
id: InnerObjectId {

wayland-backend/src/server_api.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,21 @@ impl Handle {
359359
self.handle.create_object(client_id.id, interface, version, data)
360360
}
361361

362+
/// Destroy an object
363+
///
364+
/// For most protocols, this is handled automatically when a destructor
365+
/// message is sent or received.
366+
///
367+
/// This corresponds to `wl_resource_destroy` in the C API.
368+
///
369+
/// # Panics
370+
///
371+
/// This method will panic if the type parameter `D` is not same to the same type as the
372+
/// one the backend was initialized with.
373+
pub fn destroy_object<D: 'static>(&self, id: &ObjectId) -> Result<(), InvalidId> {
374+
self.handle.destroy_object::<D>(id)
375+
}
376+
362377
/// Send an event to the client
363378
///
364379
/// Returns an error if the sender ID of the provided message is no longer valid.

wayland-backend/src/sys/client_impl/mod.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,43 @@ impl InnerBackend {
491491
}
492492
}
493493

494+
fn destroy_object_inner(&self, guard: &mut MutexGuard<ConnectionState>, id: &ObjectId) {
495+
if let Some(ref alive) = id.id.alive {
496+
let udata = unsafe {
497+
Box::from_raw(ffi_dispatch!(
498+
wayland_client_handle(),
499+
wl_proxy_get_user_data,
500+
id.id.ptr
501+
) as *mut ProxyUserData)
502+
};
503+
unsafe {
504+
ffi_dispatch!(
505+
wayland_client_handle(),
506+
wl_proxy_set_user_data,
507+
id.id.ptr,
508+
std::ptr::null_mut()
509+
);
510+
}
511+
alive.store(false, Ordering::Release);
512+
udata.data.destroyed(id.clone());
513+
}
514+
515+
guard.known_proxies.remove(&id.id.ptr);
516+
517+
unsafe {
518+
ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.id.ptr);
519+
}
520+
}
521+
522+
pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
523+
if !id.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
524+
return Err(InvalidId);
525+
}
526+
527+
self.destroy_object_inner(&mut self.lock_state(), id);
528+
Ok(())
529+
}
530+
494531
pub fn send_request(
495532
&self,
496533
Message { sender_id: ObjectId { id }, opcode, args }: Message<ObjectId, RawFd>,
@@ -685,31 +722,7 @@ impl InnerBackend {
685722
};
686723

687724
if message_desc.is_destructor {
688-
if let Some(ref alive) = id.alive {
689-
let udata = unsafe {
690-
Box::from_raw(ffi_dispatch!(
691-
wayland_client_handle(),
692-
wl_proxy_get_user_data,
693-
id.ptr
694-
) as *mut ProxyUserData)
695-
};
696-
unsafe {
697-
ffi_dispatch!(
698-
wayland_client_handle(),
699-
wl_proxy_set_user_data,
700-
id.ptr,
701-
std::ptr::null_mut()
702-
);
703-
}
704-
alive.store(false, Ordering::Release);
705-
udata.data.destroyed(ObjectId { id: id.clone() });
706-
}
707-
708-
guard.known_proxies.remove(&id.ptr);
709-
710-
unsafe {
711-
ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.ptr);
712-
}
725+
self.destroy_object_inner(&mut guard, &ObjectId { id })
713726
}
714727

715728
Ok(child_id)

wayland-backend/src/sys/server_impl/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,24 @@ impl InnerHandle {
564564
Ok(ObjectId { id: unsafe { init_resource(resource, interface, Some(data)).0 } })
565565
}
566566

567+
pub fn destroy_object<D: 'static>(&self, id: &ObjectId) -> Result<(), InvalidId> {
568+
let mut state = self.state.lock().unwrap();
569+
// Keep this guard alive while the code is run to protect the C state
570+
let state = (&mut *state as &mut dyn ErasedState)
571+
.downcast_mut::<State<D>>()
572+
.expect("Wrong type parameter passed to Handle::destroy_object().");
573+
574+
if !id.id.alive.load(Ordering::Acquire) {
575+
return Err(InvalidId);
576+
}
577+
578+
PENDING_DESTRUCTORS.set(&(&mut state.pending_destructors as *mut _ as *mut _), || unsafe {
579+
ffi_dispatch!(wayland_server_handle(), wl_resource_destroy, id.id.ptr);
580+
});
581+
582+
Ok(())
583+
}
584+
567585
pub fn null_id() -> ObjectId {
568586
ObjectId {
569587
id: InnerObjectId {

0 commit comments

Comments
 (0)