From 2d52c6a15bed432e77a883d2aa174906a71fdbec Mon Sep 17 00:00:00 2001 From: Liu Xiaodong Date: Fri, 26 Feb 2021 08:23:00 -0500 Subject: [PATCH] thread: add spdk_thread_set_interrupt_mode func spdk_thread_set_interrupt_mode can get spdk_thread run between intr and poll mode. It is only valid when thread interrupt facility is enabled by spdk_interrupt_mode_enable(). Currently, this function is limited that no poller is registered to the spdk_thread. Change-Id: Iba54accd5976beb6f6e155014903928ce2858e36 Signed-off-by: Liu Xiaodong Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6708 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Reviewed-by: Changpeng Liu Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- CHANGELOG.md | 6 ++++++ include/spdk/thread.h | 10 +++++++++ lib/thread/spdk_thread.map | 1 + lib/thread/thread.c | 44 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54189ade4..99136b341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,12 @@ Removed the `pci_whitelist`, `pci_blacklist` and `master_core` members of struct Removed the `config_file`, `max_delay_us`, `pci_whitelist` and `pci_blacklist` members of struct `spdk_app_opts`. +### thread + +Added `spdk_thread_set_interrupt_mode` function in order to set present spdk_thead into +interrupt mode or back to poll mode. It is valid only when thread interrupt facility is +enabled by spdk_interrupt_mode_enable(). + ### iscsi A security vulnerability has been identified and fixed in the SPDK iSCSI target. diff --git a/include/spdk/thread.h b/include/spdk/thread.h index 71c620f23..57153afb3 100644 --- a/include/spdk/thread.h +++ b/include/spdk/thread.h @@ -513,6 +513,16 @@ int spdk_thread_send_critical_msg(struct spdk_thread *thread, spdk_msg_fn fn); */ void spdk_for_each_thread(spdk_msg_fn fn, void *ctx, spdk_msg_fn cpl); +/** + * Set current spdk_thread into interrupt mode or back to poll mode. + * + * Only valid when thread interrupt facility is enabled by + * spdk_interrupt_mode_enable(). + * + * \param enable_interrupt Set interrupt mode for true, or poll mode for false + */ +void spdk_thread_set_interrupt_mode(bool enable_interrupt); + /** * Register a poller on the current thread. * diff --git a/lib/thread/spdk_thread.map b/lib/thread/spdk_thread.map index 2b064f715..feedd551b 100644 --- a/lib/thread/spdk_thread.map +++ b/lib/thread/spdk_thread.map @@ -29,6 +29,7 @@ spdk_thread_send_msg; spdk_thread_send_critical_msg; spdk_for_each_thread; + spdk_thread_set_interrupt_mode; spdk_poller_register; spdk_poller_register_named; spdk_poller_unregister; diff --git a/lib/thread/thread.c b/lib/thread/thread.c index 7a66e2f71..17b87700b 100644 --- a/lib/thread/thread.c +++ b/lib/thread/thread.c @@ -720,6 +720,7 @@ spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now) { struct spdk_thread *orig_thread; int rc; + uint64_t notify = 1; orig_thread = _get_thread(); tls_thread = thread; @@ -730,9 +731,25 @@ spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now) if (spdk_likely(!thread->in_interrupt)) { rc = thread_poll(thread, max_msgs, now); + if (spdk_unlikely(thread->in_interrupt)) { + /* The thread transitioned to interrupt mode during the above poll. + * Poll it one more time in case that during the transition time + * there is msg received without notification. + */ + rc = thread_poll(thread, max_msgs, now); + } } else { /* Non-block wait on thread's fd_group */ rc = spdk_fd_group_wait(thread->fgrp, 0); + if (spdk_unlikely(!thread->in_interrupt)) { + /* The thread transitioned to poll mode in a msg during the above processing. + * Clear msg_fd since thread messages will be polled directly in poll mode. + */ + rc = read(thread->msg_fd, ¬ify, sizeof(notify)); + if (rc < 0 && errno != EAGAIN) { + SPDK_ERRLOG("failed to acknowledge msg queue: %s.\n", spdk_strerror(errno)); + } + } } @@ -889,6 +906,10 @@ thread_send_msg_notification(const struct spdk_thread *target_thread) return 0; } + /* When each spdk_thread can switch between poll and interrupt mode dynamically, + * after sending thread msg, it is necessary to check whether target thread runs in + * interrupt mode and then decide whether do event notification. + */ if (spdk_unlikely(target_thread->in_interrupt)) { rc = write(target_thread->msg_fd, ¬ify, sizeof(notify)); if (rc < 0) { @@ -1334,6 +1355,29 @@ spdk_for_each_thread(spdk_msg_fn fn, void *ctx, spdk_msg_fn cpl) assert(rc == 0); } +void +spdk_thread_set_interrupt_mode(bool enable_interrupt) +{ + struct spdk_thread *thread = _get_thread(); + + assert(thread); + assert(spdk_interrupt_mode_is_enabled()); + + if (thread->in_interrupt == enable_interrupt) { + return; + } + + /* Currently, only spdk_thread without pollers can set interrupt mode. + * TODO: remove it after adding interrupt mode switch into poller. + */ + assert(TAILQ_EMPTY(&thread->timed_pollers)); + assert(TAILQ_EMPTY(&thread->active_pollers)); + assert(TAILQ_EMPTY(&thread->paused_pollers)); + + thread->in_interrupt = enable_interrupt; + return; +} + void spdk_io_device_register(void *io_device, spdk_io_channel_create_cb create_cb, spdk_io_channel_destroy_cb destroy_cb, uint32_t ctx_size,