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

Interface poll requires the SocketSet to be mutable as a whole #959

Open
cavivie opened this issue Jul 26, 2024 · 1 comment
Open

Interface poll requires the SocketSet to be mutable as a whole #959

cavivie opened this issue Jul 26, 2024 · 1 comment

Comments

@cavivie
Copy link

cavivie commented Jul 26, 2024

The following issue arises when managing a global SocketSet across multiple threads. If one thread performs a poll operation on the SocketSet with the Interface, other threads will need to acquire locks to perform socket operations. When the entire SocketSet is locked, accessing individual sockets becomes costly due to lock overhead, as the granularity of the lock is at the SocketSet level, not the individual socket level. In smoltcp, processing each socket involves traversing the entire SocketSet, which requires the whole set to be mutable during the operation. This is less common in other implementations (e.g., in kernel netstack, you can avoid locking the entire SocketSet by using a read-write lock on individual sockets).

What is smoltcp's solution to this problem in a multi-threaded environment?

Currently, I aim to abstract the SocketSet into a trait, which would allow finer-grained locking on individual sockets rather than locking the entire SocketSet. This approach could help avoid significant performance drops during traversal (please correct me if this approach is flawed).

@cavivie
Copy link
Author

cavivie commented Jul 26, 2024

Let this SocketSet trait to return mutable socket references, but not require the SocketSet itself to be mutable, which allows us to achieve our goal.

pub trait AnySocketSet<'a> {
    /// Returns an iterator over the items in the socket set, immutable version..
    fn items<'s>(&'s self) -> impl Iterator<Item = &'s SocketStorage<'a>>
    where
        'a: 's;

    // Not using mutable self
    //
    // /// Returns an iterator over the items in the socket set, mutable version.
    // fn items_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut SocketStorage<'a>>
    // where
    //     'a: 's;

    // Using immutable self
    //
    /// Returns an iterator over the items in the socket set, mutable version.
    fn items_mut<'s>(&'s self) -> impl Iterator<Item = &'s mut SocketStorage<'a>>
    where
        'a: 's;
}

For single-thread, the key to implement this trait is to use RefCell on each SocketStorage to avoid locks.

For multi-thread, the implementation needs read/write locks/mutex locks, otherwise we can't get a mut SocketStorage.

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

1 participant