Messages in this thread | | | Date | Wed, 17 May 2023 22:22:19 +0000 | Subject | Re: [PATCH v1 0/7] Bindings for the workqueue | From | Alice Ryhl <> |
| |
On Wed, 17 May 2023 11:48:19 -1000, Tejun Heo wrote: > I tried to read the patches but am too dumb to understand much.
The patch is more complicated than I would have liked, unfortunately. However, as I mentioned in the cover letter, simplifications should be on their way.
Luckily, using the workqueue bindings is simpler than the bindings themselves.
> Any chance you can provide some examples so that I can at least > imagine how workqueue would be used from rust side?
Yes, of course!
The simplest way to use the workqueue is to use the `try_spawn` method introduced by the last patch in the series. With this function, you just pass a function pointer to the `try_spawn` method, and it schedules the function for execution. Unfortunately this allocates memory, making it a fallible operation.
To avoid allocation memory, we do something else. As an example, we can look at the Rust binder driver that I am currently working on. Here is how it will be used in the binder driver: First, the `Process` struct will be given a `work_struct` field:
#[pin_data] pub(crate) struct Process { // Work node for deferred work item. #[pin] defer_work: Work<Arc<Process>>,
// Other fields follow... }
Here, we use the type `Work<Arc<Process>>` for our field. This type is the Rust wrapper for `work_struct`. The generic parameter to `Work` should be the pointer type used to access `Process`, and in this case it is `Arc<Process>`. The pointer type `Arc` is used for reference counting, and its a pointer type that owns a ref-count to the inner value. (So e.g., it decrements the ref-cout when the arc goes out of scope.) Arc is an abbreviation of "atomic reference count". This means that while it is enqueued in the workqueue, the workqueue owns a ref-count to the process.
Next, binder will use the `impl_has_work!` macro to declare that it wants to use `defer_work` as its `work_struct` field. That looks like this:
kernel::impl_has_work! { impl HasWork<Arc<Process>> for Process { self.defer_work } }
To define the code that should run when the work item is executed on the workqueue, binder does the following:
impl workqueue::ArcWorkItem for Process { fn run(self: Arc<Process>) { // this runs when the work item is executed } }
Finally to schedule it to the system workqueue, it does the following:
let _ = workqueue::system().enqueue(process);
Here, the `enqueue` call is fallible, since it might fail if the process has already been enqueued to a work queue. However, binder just uses `let _ =` to ignore the failure, since it doesn't need to do anything special in that case.
I hope that helps, and let me know if you have any further questions.
Alice
| |