Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split reader and writer #967

Open
Ddystopia opened this issue Aug 3, 2024 · 3 comments
Open

Split reader and writer #967

Ddystopia opened this issue Aug 3, 2024 · 3 comments

Comments

@Ddystopia
Copy link

Hello,

It is common in async rust to have split method on sockets to get read and write halves. For example, tokio. While reading the docs, I didn't find anything like this. While reading your code for tcp::Socket read and write operations, I didn't find anything that would block it.

Embassy TcpSocket wraps your tcp::Socket and provides that split api, but they are using RefCell.

There is also picoserve, embedded web server, that requires separate Read and Write halves.

Do you have any particular reason to not have such useful API? If it is just because nobody implemented it, I can do it.

@Dirbaio
Copy link
Member

Dirbaio commented Aug 4, 2024

in smoltcp the socket needs to be owned by the SocketSet. Your own code only owns the handle, every time you need to do something with the socket you have to use the handle to look it up in the SocketSet and get temporary access to it.

Given this, I'm not sure what "split" in smoltcp itself would do. You can already clone the handle and access it from multiple places in your own code, for example for reading in some place and writing in another.

@Ddystopia
Copy link
Author

SocketSet can only return shared reference to the socket if you have a shared reference to the SocketSet. But to read or write you need a mutable reference to the socket. So you must have mutable reference to the SocketSet to read or write. That way I'm not sure how to concurrently read and write from different locations without something like refcell.

Am I reading the docs correctly?

As I've seen in source code (tcp), read is not mutating any state relating to writing, and writing is not mutating any state related to reading. There are separate tx_buffer and rx_buffer, and separate wakers.

@Dirbaio
Copy link
Member

Dirbaio commented Aug 4, 2024

But to read or write you need a mutable reference to the socket. So you must have mutable reference to the SocketSet to read or write. That way I'm not sure how to concurrently read and write from different locations without something like refcell.

You can either write your application as a single giant main loop like the examples do, so there's no need for shared mutable access at all. Or yes, you can put the SocketSet in a RefCell.

As I've seen in source code (tcp), read is not mutating any state relating to writing, and writing is not mutating any state related to reading. There are separate tx_buffer and rx_buffer, and separate wakers.

But processing packets for the socket (when you call Interface::poll()) requires full access to the entire TCP state, both the read and write half. So even if we had split you'd still need a RefCell somewhere to share the state between the read half and the interface, and between the write half and the interface.

In a network stack you'll always have some "background task" processing packets, so you always need some mechanism for "sharing" state between the background task and user code. In desktop Linux the kernel does it for you, in embassy-net it does the RefCell for you, in smoltcp this is intentionally left to the user.

If the user has to do their own sharing they can already do their own split.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants