On Fri, Jul 21, 2023 at 09:58:52AM +0000, Tage Johansson wrote: > > On 7/19/2023 4:47 PM, Richard W.M. Jones wrote: > > On Wed, Jul 19, 2023 at 09:09:53AM +0000, Tage Johansson wrote: > > Create another handle type: `AsyncHandle`, which makes use of Rust's > builtin asynchronous functions (see > <https://doc.rust-lang.org/std/keyword.async.html>) and runs on top of > the Tokio runtime (see <https://docs.rs/tokio>). For every > asynchronous > command, like `aio_connect()`, a corresponding `async` method is > created > on the handle. In this case it would be: > async fn connect(...) -> Result<(), ...> > When called, it will poll the file descriptor until the command is > complete, and then return with a result. All the synchronous > counterparts (like `nbd_connect()`) are excluded from this handle type > as they are unnecessary and since they might interfear with the > polling > made by the Tokio runtime. For more details about how the asynchronous > commands are executed, please see the comments in > rust/src/async_handle.rs. > > This is an interesting (and good) approach, layering a more natural > API for Rust users on top of the "low level" API. > > > --- > generator/Rust.ml | 232 > +++++++++++++++++++++++++++++++++++++++ > generator/Rust.mli | 2 + > generator/generator.ml | 1 + > rust/Cargo.toml | 1 + > rust/Makefile.am | 1 + > rust/src/async_handle.rs | 222 +++++++++++++++++++++++++++++++++++++ > rust/src/lib.rs | 4 + > 7 files changed, 463 insertions(+) > create mode 100644 rust/src/async_handle.rs > > diff --git a/generator/Rust.ml b/generator/Rust.ml > index 96095a9..1048831 100644 > --- a/generator/Rust.ml > +++ b/generator/Rust.ml > @@ -601,3 +601,235 @@ let generate_rust_bindings () = > pr "impl Handle {\n"; > List.iter print_rust_handle_method handle_calls; > pr "}\n\n" > + > +(*********************************************************) > +(* The rest of the file conserns the asynchronous API. *) > +(* *) > +(* See the comments in rust/src/async_handle.rs for more *) > +(* information about how it works. *) > +(*********************************************************) > + > +let excluded_handle_calls : NameSet.t = > + NameSet.of_list > + [ > + "aio_get_fd"; > + "aio_get_direction"; > + "aio_notify_read"; > + "aio_notify_write"; > + "clear_debug_callback"; > + "get_debug"; > + "poll"; > + "poll2"; > + "set_debug"; > + "set_debug_callback"; > + ] > > This is a "code smell" since all information that is specific to APIs > should (usually) go in generator/API.ml. > > It's reasonable for aio_get_{fd,direction} aio_notify_{read,write} > since those are very special APIs, but I don't understand why the poll > and debug functions are listed here. What's the real meaning of this > list of functions, ie. why can each one not be included in the tokio > bindings? > > > The debug functions are used for setting up logging with the log crate in > rust/ > src/handle.rs:
Interesting .. Is this used for all libnbd Rust handles? > ```Rust > > impl Handle { > pub fn new() -> Result<Self> { > let handle = unsafe { sys::nbd_create() }; > if handle.is_null() { > Err(unsafe { Error::Fatal(ErrorKind::get_error().into()) }) > } else { > // Set a debug callback communicating with any logging > // implementation as defined by the log crate. > #[allow(unused_mut)] > let mut nbd = Handle { handle }; > #[cfg(feature = "log")] > { > nbd.set_debug_callback(|func_name, msg| { > log::debug!( > target: func_name.to_string_lossy().as_ref(), > "{}", > msg.to_string_lossy() > ); > 0 > })?; > nbd.set_debug(true)?; > } > Ok(nbd) > } > } > > ``` > > > So if the user would set another debug callback this functionality would stop > working. And since the documentation is automaticly generated for > `nbd_set_debug_callback()`, the user might not expect that logging just stops > working because they set a debug callback. But I guess that I can add a note > about that to the documentation of the `Handle` struct and include the debug > callbacks, if you want? I'm a bit unclear if the debugging is necessary or not. In the other bindings we don't set up a log handler by default, it just works the same way as the C API. > Regarding the other methods, it's a bit more complicated. The > problem is that calling any `aio_notify_*` method might cause any > ongoing command to finish. For example, the `connect()` method on > `AsyncHandle` will not return until `aio_is_connecting()` returns > false. In order not to have to check that in a busy loop, the > function is woken up only when the polling task makes a call to any > `aio_notify_*` function. So whenever the polling task calls > `aio_notify_*`, it notifies the waiting command that the handle > might has changed state. But if the user calls `aio_notify_*` > (directly or indirectly) while `aio_connect` is in flight, it might > happen that the connection completes without the call to `connect()` > gets notified about that. > > This means that any function that calls any `aio_notify_*` function > should not be implemented on `AsyncHandle`. A better approach than > the current would probably be to add a field to the `call`-structure > in API.ml. Something like `notifies_fd : bool` (sure someone can > come up with a better name). This would be set to true for any > function that calls `aio_notify_*`, including `aio_notify_read()`, > `poll()`, and all synchronous commands like `nbd_connect() `. What > do you think about that? Yup, it was already clear to me why these wouldn't work after I thought about it a bit more. My issue for maintenance is that if we add a new "poll-like" function to the API then the Rust bindings would need a special change. > I have written some more explonations about how the asynchronous > handle works in rust/src/async_handle.rs, but it is somewhat > complicated so please ask if there are more unclear things. Sure, thanks! Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs