Messages in this thread | | | Date | Thu, 18 May 2023 20:18:54 -0300 | Subject | Re: [PATCH v1 5/7] rust: workqueue: add helper for defining work_struct fields | From | Martin Rodriguez Reboredo <> |
| |
On 5/17/23 17:31, Alice Ryhl wrote: > The main challenge with defining `work_struct` fields is making sure > that the function pointer stored in the `work_struct` is appropriate for > the work item type it is embedded in. It needs to know the offset of the > `work_struct` field being used (even if there are several!) so that it > can do a `container_of`, and it needs to know the type of the work item > so that it can call into the right user-provided code. All of this needs > to happen in a way that provides a safe API to the user, so that users > of the workqueue cannot mix up the function pointers. > > There are three important pieces that are relevant when doing this. This > commit will use traits so that they know about each other according to > the following cycle: > > * The pointer type. It knows the type of the work item struct. > * The work item struct. It knows the offset of its `work_struct` field. > * The `work_struct` field. It knows the pointer type. > > There's nothing special about making the pointer type know the type of > the struct it points at. Pointers generally always know that > information. > > However, making the `work_struct` field know about the pointer type is > less commonly seen. This is done by using a generic parameter: the > `work_struct` field will have the type `Work<T>`, where T will be the > pointer type in use. The pointer type is required to implement the > `WorkItemAdapter` trait, which defines the function pointer to store in > the `work_struct` field. The `Work<T>` type guarantees that the > `work_struct` inside it uses `<T as WorkItemAdapter>::run` as its > function pointer. > > Finally, to make the work item struct know the offset of its > `work_struct` field, we use a trait called `HasWork<T>`. If a type > implements this trait, then the type declares that, at the given offset, > there is a field of type `Work<T>`. The trait is marked unsafe because > the OFFSET constant must be correct, but we provide an `impl_has_work!` > macro that can safely implement `HasWork<T>` on a type. The macro > expands to something that only compiles if the specified field really > has the type `Work<T>`. It is used like this: > > ``` > struct MyWorkItem { > work_field: Work<Arc<MyWorkItem>>, > } > > impl_has_work! { > impl HasWork<Arc<MyWorkItem>> for MyWorkItem { self.work_field } > } > ``` > > So to summarize, given a pointer to an allocation containing a work > item, you can use the `HasWork<T>` trait to offset the pointer to the > `work_struct` field. The function pointer in the `work_struct` field is > guaranteed to be a function that knows what the original pointer type > was, and using that information, it can undo the offset operation by > looking up what the offset was via the `HasWork<T>` trait. > > This design supports work items with multiple `work_struct` fields by > using different pointer types. For example, you might define structs > like these: > > ``` > struct MyPointer1(Arc<MyWorkItem>); > struct MyPointer2(Arc<MyWorkItem>); > > struct MyWorkItem { > work1: Work<MyPointer1>, > work2: Work<MyPointer2>, > } > ``` > > Then, the wrapper structs `MyPointer1` and `MyPointer2` will take the > role as the pointer type. By using one or the other, you tell the > workqueue which `work_struct` field to use. This pattern is called the > "newtype" pattern. > > Signed-off-by: Alice Ryhl <aliceryhl@google.com> > --- > [...]
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
| |