chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.85k stars 1.21k forks source link

Asynchronous io_control? #1212

Closed ceggers-arri closed 1 year ago

ceggers-arri commented 1 year ago

I just upgraded from boost-1.78.0 to boost-1.81.0 in order to get support for asynchronous I/O with "files". In my case, "files" also means "Linux device nodes which perform blocking I/O via ioctl() calls" like i2c-dev [1] or spidev [2]. Examples are the I2C_RDWR or SPI_IOC_MESSAGE [3] ioctl calls.

Can support for "async_io_control" be added to boost asio? I guess that this could only be used together with io_uring. Currently I have to emulate asynchronous I/O here by posting the ioctl calls to an application wide thread pool.

thanks,\ Christian

[1] https://www.kernel.org/doc/Documentation/i2c/dev-interface [2] https://docs.kernel.org/spi/spidev.html#full-duplex-character-device-api [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/spi/spidev_fdx.c#n68

vinipsmaker commented 1 year ago

Ioctls are used to configure the devices and query internal data structures promptly available. They're a poor choice to drive programs dealing with high-throughput concurrent IO operations. In fact, I don't even see the io_uring opcode for ioctls in the manpages: https://www.mankier.com/2/io_uring_enter#Description-IORING_OP_NOP

Can you elaborate more on your needs?

ceggers-arri commented 1 year ago

As I haven't worked with io_uring yet, so I didn't know that only particular syscalls are supported. It seems that there is currently no support for using ioctl() with io_uring (only https://lwn.net/Articles/844875/), so I'll close this issue.

My motivation was to get rid of some extra threads in my application (they perform blocking i/o) in favor of using asynchronous i/o in the main thread. But in my case the device is neither a stream nor a regular file. So I'll have to continue with emulating async io by posting work to an (application wide) thread pool.

The I2C and SPI subsystems in the kernel allow writing client drivers (drivers for devices connected via I2C/SPI bus to the processor) either in kernel or in user space. User space drivers use i2c-dev or spidev for getting direct access to the bus where the peripheral is connected.

The SPI bus is often full-duplex which means that any transfer which writes data to the bus also reads data at the same time (but usually, not every single received / transmitted byte is actually meaningful). The I2C bus in turn is half-duplex, but very often an i/o operation is composed by multiple write+read where the bus must not be released in between (releasing the bus in hardware often resets the register address which was set in last write operation).

Probably for these reasons, I2C and SPI transfers via i2c-dev/spidev are not modeled as read() or write() call.