Re: [PATCH v1 6/7] rust: workqueue: add safe API to workqueue

From: Alice Ryhl
Date: Wed May 31 2023 - 10:17:03 EST


Andreas Hindborg <nmi@xxxxxxxxxxxx> writes:
> Alice Ryhl <aliceryhl@xxxxxxxxxx> writes:
>> +unsafe impl<T> WorkItem for Arc<T>
>> +where
>> + T: ArcWorkItem + HasWork<Self> + ?Sized,
>> +{
>> + type EnqueueOutput = Result<(), Self>;
>> +
>> + unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
>> + where
>> + F: FnOnce(*mut bindings::work_struct) -> bool,
>> + {
>> + let ptr = Arc::into_raw(self);
>> +
>> + // Using `get_work_offset` here for object-safety.
>> + //
>> + // SAFETY: The pointer is valid since we just got it from `into_raw`.
>> + let off = unsafe { (&*ptr).get_work_offset() };
>> +
>> + // SAFETY: The `HasWork` impl promises that this offset gives us a field of type
>> + // `Work<Self>` in the same allocation.
>> + let work_ptr = unsafe { (ptr as *const u8).add(off) as *const Work<Self> };
>
> We have this functionality in the default impl of
> `HasWork<T>::raw_get_work() where Self: Sized`. I am uncertain about the
> `Sized` bound. If it is sound to do the offset calculation here where
> `T: ?Sized`, it should also be sound in the default implementation of
> `HasWork<T>`. Should we not be able to change the bound on
> `HasWork<T>::raw_get_work()` to `Self: ?Sized` and call into that from
> here?
>
> let work_ptr = unsafe { <T as HasWork<Self>>::raw_get_work(ptr as _) };
>
> Same for Box.
>
> BR Andreas

I looked into this, and it seems like we can remove `Self: Sized` bound
from `raw_get_work`, so I am able to simplify this code somewhat.
However, it cannot be removed from `container_of`.

Thanks,
Alice