These files implement the homa_interest struct, which is used to wait for incoming messages. Signed-off-by: John Ousterhout --- Changes for v11: * Clean up sparse annotations Changes for v10: none Changes for v9: * Remove unused field homa_interest->core --- net/homa/homa_interest.c | 121 +++++++++++++++++++++++++++++++++++++++ net/homa/homa_interest.h | 96 +++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 net/homa/homa_interest.c create mode 100644 net/homa/homa_interest.h diff --git a/net/homa/homa_interest.c b/net/homa/homa_interest.c new file mode 100644 index 000000000000..42df499f12a2 --- /dev/null +++ b/net/homa/homa_interest.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BSD-2-Clause + +/* This file contains functions for managing homa_interest structs. */ + +#include "homa_impl.h" +#include "homa_interest.h" +#include "homa_rpc.h" +#include "homa_sock.h" + +/** + * homa_interest_init_shared() - Initialize an interest and queue it up on + * a socket. + * @interest: Interest to initialize + * @hsk: Socket on which the interests should be queued. Must be locked + * by caller. + */ +void homa_interest_init_shared(struct homa_interest *interest, + struct homa_sock *hsk) + __must_hold(hsk->lock) +{ + interest->rpc = NULL; + atomic_set(&interest->ready, 0); + interest->blocked = 0; + init_waitqueue_head(&interest->wait_queue); + interest->hsk = hsk; + list_add(&interest->links, &hsk->interests); +} + +/** + * homa_interest_init_private() - Initialize an interest that will wait + * on a particular (private) RPC, and link it to that RPC. + * @interest: Interest to initialize. + * @rpc: RPC to associate with the interest. Must be private, and + * caller must have locked it. + * + * Return: 0 for success, otherwise a negative errno. + */ +int homa_interest_init_private(struct homa_interest *interest, + struct homa_rpc *rpc) + __must_hold(rpc->bucket->lock) +{ + if (rpc->private_interest) + return -EINVAL; + + interest->rpc = rpc; + atomic_set(&interest->ready, 0); + interest->blocked = 0; + init_waitqueue_head(&interest->wait_queue); + interest->hsk = rpc->hsk; + rpc->private_interest = interest; + return 0; +} + +/** + * homa_interest_wait() - Wait for an interest to have an actionable RPC, + * or for an error to occur. + * @interest: Interest to wait for; must previously have been initialized + * and linked to a socket or RPC. On return, the interest + * will have been unlinked if its ready flag is set; otherwise + * it may still be linked. + * @nonblocking: Nonzero means return without blocking if the interest + * doesn't become ready immediately. + * + * Return: 0 for success (there is an actionable RPC in the interest), or + * a negative errno. + */ +int homa_interest_wait(struct homa_interest *interest, int nonblocking) +{ + struct homa_sock *hsk = interest->hsk; + int result = 0; + int iteration; + int wait_err; + + interest->blocked = 0; + + /* This loop iterates in order to poll and/or reap dead RPCS. */ + for (iteration = 0; ; iteration++) { + if (iteration != 0) + /* Give NAPI/SoftIRQ tasks a chance to run. */ + schedule(); + + if (atomic_read_acquire(&interest->ready) != 0) + goto done; + + /* See if we can cleanup dead RPCs while waiting. */ + if (homa_rpc_reap(hsk, false) != 0) + continue; + + if (nonblocking) { + result = -EAGAIN; + goto done; + } + + break; + } + + interest->blocked = 1; + wait_err = wait_event_interruptible_exclusive(interest->wait_queue, + atomic_read_acquire(&interest->ready) != 0); + if (wait_err == -ERESTARTSYS) + result = -EINTR; + +done: + return result; +} + +/** + * homa_interest_notify_private() - If a thread is waiting on the private + * interest for an RPC, wake it up. + * @rpc: RPC that may (potentially) have a private interest. Must be + * locked by the caller. + */ +void homa_interest_notify_private(struct homa_rpc *rpc) + __must_hold(rpc->bucket->lock) +{ + if (rpc->private_interest) { + atomic_set_release(&rpc->private_interest->ready, 1); + wake_up(&rpc->private_interest->wait_queue); + } +} + diff --git a/net/homa/homa_interest.h b/net/homa/homa_interest.h new file mode 100644 index 000000000000..ad0c697a2949 --- /dev/null +++ b/net/homa/homa_interest.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* This file defines struct homa_interest and related functions. */ + +#ifndef _HOMA_INTEREST_H +#define _HOMA_INTEREST_H + +#include "homa_rpc.h" +#include "homa_sock.h" + +/** + * struct homa_interest - Holds info that allows applications to wait for + * incoming RPC messages. An interest can be either private, in which case + * the application is waiting for a single specific RPC response and the + * interest is referenced by an rpc->private_interest, or shared, in which + * case the application is waiting for any incoming message that isn't + * private and the interest is present on hsk->interests. + */ +struct homa_interest { + /** + * @rpc: If ready is set, then this holds an RPC that needs + * attention, or NULL if this is a shared interest and hsk has + * been shutdown. If ready is not set, this will be NULL if the + * interest is shared; if it's private, it holds the RPC the + * interest is associated with. If non-NULL, a reference has been + * taken on the RPC. + */ + struct homa_rpc *rpc; + + /** + * @ready: Nonzero means the interest is ready for attention: either + * there is an RPC that needs attention or @hsk has been shutdown. + */ + atomic_t ready; + + /** + * @blocked: Zero means a handoff was received without the thread + * needing to block; nonzero means the thread blocked. + */ + int blocked; + + /** + * @wait_queue: Used to block the thread while waiting (will never + * have more than one queued thread). + */ + struct wait_queue_head wait_queue; + + /** @hsk: Socket that the interest is associated with. */ + struct homa_sock *hsk; + + /** + * @links: If the interest is shared, used to link this object into + * @hsk->interests. + */ + struct list_head links; +}; + +/** + * homa_interest_unlink_shared() - Remove an interest from the list for a + * socket. Note: this can race with homa_rpc_handoff, so on return it's + * possible that the interest is ready. + * @interest: Interest to remove. Must have been initialized with + * homa_interest_init_shared. + */ +static inline void homa_interest_unlink_shared(struct homa_interest *interest) +{ + if (!list_empty(&interest->links)) { + homa_sock_lock(interest->hsk); + list_del_init(&interest->links); + homa_sock_unlock(interest->hsk); + } +} + +/** + * homa_interest_unlink_private() - Detach a private interest from its + * RPC. Note: this can race with homa_rpc_handoff, so on return it's + * possible that the interest is ready. + * @interest: Interest to remove. Must have been initialized with + * homa_interest_init_private. Its RPC must be locked by + * the caller. + */ +static inline void homa_interest_unlink_private(struct homa_interest *interest) + __must_hold(interest->rpc->bucket->lock) +{ + if (interest == interest->rpc->private_interest) + interest->rpc->private_interest = NULL; +} + +void homa_interest_init_shared(struct homa_interest *interest, + struct homa_sock *hsk); +int homa_interest_init_private(struct homa_interest *interest, + struct homa_rpc *rpc); +void homa_interest_notify_private(struct homa_rpc *rpc); +int homa_interest_wait(struct homa_interest *interest, int nonblocking); + +#endif /* _HOMA_INTEREST_H */ -- 2.43.0