LCOV - code coverage report
Current view: top level - spdk/lib/event - reactor.c (source / functions) Hit Total Coverage
Test: Combined Lines: 608 713 85.3 %
Date: 2024-07-12 12:30:19 Functions: 55 58 94.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 322 467 69.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2016 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/likely.h"
       8                 :            : 
       9                 :            : #include "spdk_internal/event.h"
      10                 :            : #include "spdk_internal/usdt.h"
      11                 :            : 
      12                 :            : #include "spdk/log.h"
      13                 :            : #include "spdk/thread.h"
      14                 :            : #include "spdk/env.h"
      15                 :            : #include "spdk/util.h"
      16                 :            : #include "spdk/scheduler.h"
      17                 :            : #include "spdk/string.h"
      18                 :            : #include "spdk/fd_group.h"
      19                 :            : 
      20                 :            : #ifdef __linux__
      21                 :            : #include <sys/prctl.h>
      22                 :            : #include <sys/eventfd.h>
      23                 :            : #endif
      24                 :            : 
      25                 :            : #ifdef __FreeBSD__
      26                 :            : #include <pthread_np.h>
      27                 :            : #endif
      28                 :            : 
      29                 :            : #define SPDK_EVENT_BATCH_SIZE           8
      30                 :            : 
      31                 :            : static struct spdk_reactor *g_reactors;
      32                 :            : static uint32_t g_reactor_count;
      33                 :            : static struct spdk_cpuset g_reactor_core_mask;
      34                 :            : static enum spdk_reactor_state  g_reactor_state = SPDK_REACTOR_STATE_UNINITIALIZED;
      35                 :            : 
      36                 :            : static bool g_framework_context_switch_monitor_enabled = true;
      37                 :            : 
      38                 :            : static struct spdk_mempool *g_spdk_event_mempool = NULL;
      39                 :            : 
      40                 :            : TAILQ_HEAD(, spdk_scheduler) g_scheduler_list
      41                 :            :         = TAILQ_HEAD_INITIALIZER(g_scheduler_list);
      42                 :            : 
      43                 :            : static struct spdk_scheduler *g_scheduler = NULL;
      44                 :            : static struct spdk_reactor *g_scheduling_reactor;
      45                 :            : bool g_scheduling_in_progress = false;
      46                 :            : static uint64_t g_scheduler_period = 0;
      47                 :            : static uint32_t g_scheduler_core_number;
      48                 :            : static struct spdk_scheduler_core_info *g_core_infos = NULL;
      49                 :            : 
      50                 :            : TAILQ_HEAD(, spdk_governor) g_governor_list
      51                 :            :         = TAILQ_HEAD_INITIALIZER(g_governor_list);
      52                 :            : 
      53                 :            : static struct spdk_governor *g_governor = NULL;
      54                 :            : 
      55                 :            : static int reactor_interrupt_init(struct spdk_reactor *reactor);
      56                 :            : static void reactor_interrupt_fini(struct spdk_reactor *reactor);
      57                 :            : 
      58                 :            : static pthread_mutex_t g_stopping_reactors_mtx = PTHREAD_MUTEX_INITIALIZER;
      59                 :            : static bool g_stopping_reactors = false;
      60                 :            : 
      61                 :            : static struct spdk_scheduler *
      62                 :       8115 : _scheduler_find(const char *name)
      63                 :            : {
      64                 :            :         struct spdk_scheduler *tmp;
      65                 :            : 
      66         [ +  + ]:      15020 :         TAILQ_FOREACH(tmp, &g_scheduler_list, link) {
      67   [ +  +  -  +  :       7752 :                 if (strcmp(name, tmp->name) == 0) {
                   +  + ]
      68                 :        847 :                         return tmp;
      69                 :            :                 }
      70                 :            :         }
      71                 :            : 
      72                 :       7268 :         return NULL;
      73                 :            : }
      74                 :            : 
      75                 :            : int
      76                 :       1681 : spdk_scheduler_set(const char *name)
      77                 :            : {
      78                 :            :         struct spdk_scheduler *scheduler;
      79                 :       1681 :         int rc = 0;
      80                 :            : 
      81                 :            :         /* NULL scheduler was specifically requested */
      82         [ +  + ]:       1681 :         if (name == NULL) {
      83         [ +  - ]:        834 :                 if (g_scheduler) {
      84                 :        834 :                         g_scheduler->deinit();
      85                 :            :                 }
      86                 :        834 :                 g_scheduler = NULL;
      87                 :        834 :                 return 0;
      88                 :            :         }
      89                 :            : 
      90                 :        847 :         scheduler = _scheduler_find(name);
      91         [ -  + ]:        847 :         if (scheduler == NULL) {
      92                 :          0 :                 SPDK_ERRLOG("Requested scheduler is missing\n");
      93                 :          0 :                 return -EINVAL;
      94                 :            :         }
      95                 :            : 
      96         [ +  + ]:        847 :         if (g_scheduler == scheduler) {
      97                 :          9 :                 return 0;
      98                 :            :         }
      99                 :            : 
     100                 :        838 :         rc = scheduler->init();
     101         [ +  - ]:        838 :         if (rc == 0) {
     102         [ -  + ]:        838 :                 if (g_scheduler) {
     103                 :          0 :                         g_scheduler->deinit();
     104                 :            :                 }
     105                 :        838 :                 g_scheduler = scheduler;
     106                 :            :         }
     107                 :            : 
     108                 :        838 :         return rc;
     109                 :            : }
     110                 :            : 
     111                 :            : struct spdk_scheduler *
     112                 :       1250 : spdk_scheduler_get(void)
     113                 :            : {
     114                 :       1250 :         return g_scheduler;
     115                 :            : }
     116                 :            : 
     117                 :            : uint64_t
     118                 :        171 : spdk_scheduler_get_period(void)
     119                 :            : {
     120                 :            :         /* Convert from ticks to microseconds */
     121         [ -  + ]:        171 :         return (g_scheduler_period * SPDK_SEC_TO_USEC / spdk_get_ticks_hz());
     122                 :            : }
     123                 :            : 
     124                 :            : void
     125                 :       1708 : spdk_scheduler_set_period(uint64_t period)
     126                 :            : {
     127                 :            :         /* Convert microseconds to ticks */
     128                 :       1708 :         g_scheduler_period = period * spdk_get_ticks_hz() / SPDK_SEC_TO_USEC;
     129                 :       1708 : }
     130                 :            : 
     131                 :            : void
     132                 :       7268 : spdk_scheduler_register(struct spdk_scheduler *scheduler)
     133                 :            : {
     134         [ -  + ]:       7268 :         if (_scheduler_find(scheduler->name)) {
     135                 :          0 :                 SPDK_ERRLOG("scheduler named '%s' already registered.\n", scheduler->name);
     136                 :          0 :                 assert(false);
     137                 :            :                 return;
     138                 :            :         }
     139                 :            : 
     140                 :       7268 :         TAILQ_INSERT_TAIL(&g_scheduler_list, scheduler, link);
     141                 :            : }
     142                 :            : 
     143                 :            : uint32_t
     144                 :          0 : spdk_scheduler_get_scheduling_lcore(void)
     145                 :            : {
     146                 :          0 :         return g_scheduling_reactor->lcore;
     147                 :            : }
     148                 :            : 
     149                 :            : static void
     150                 :       3873 : reactor_construct(struct spdk_reactor *reactor, uint32_t lcore)
     151                 :            : {
     152                 :       3873 :         reactor->lcore = lcore;
     153                 :       3873 :         reactor->flags.is_valid = true;
     154                 :            : 
     155                 :       3873 :         TAILQ_INIT(&reactor->threads);
     156                 :       3873 :         reactor->thread_count = 0;
     157                 :       3873 :         spdk_cpuset_zero(&reactor->notify_cpuset);
     158                 :            : 
     159                 :       3873 :         reactor->events = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 65536, SPDK_ENV_SOCKET_ID_ANY);
     160         [ -  + ]:       3873 :         if (reactor->events == NULL) {
     161                 :          0 :                 SPDK_ERRLOG("Failed to allocate events ring\n");
     162                 :          0 :                 assert(false);
     163                 :            :         }
     164                 :            : 
     165                 :            :         /* Always initialize interrupt facilities for reactor */
     166         [ -  + ]:       3873 :         if (reactor_interrupt_init(reactor) != 0) {
     167                 :            :                 /* Reactor interrupt facilities are necessary if seting app to interrupt mode. */
     168         [ #  # ]:          0 :                 if (spdk_interrupt_mode_is_enabled()) {
     169                 :          0 :                         SPDK_ERRLOG("Failed to prepare intr facilities\n");
     170                 :          0 :                         assert(false);
     171                 :            :                 }
     172                 :          0 :                 return;
     173                 :            :         }
     174                 :            : 
     175                 :            :         /* If application runs with full interrupt ability,
     176                 :            :          * all reactors are going to run in interrupt mode.
     177                 :            :          */
     178         [ +  + ]:       3873 :         if (spdk_interrupt_mode_is_enabled()) {
     179                 :            :                 uint32_t i;
     180                 :            : 
     181         [ +  + ]:        200 :                 SPDK_ENV_FOREACH_CORE(i) {
     182                 :        151 :                         spdk_cpuset_set_cpu(&reactor->notify_cpuset, i, true);
     183                 :            :                 }
     184                 :         49 :                 reactor->in_interrupt = true;
     185                 :            :         }
     186                 :            : }
     187                 :            : 
     188                 :            : struct spdk_reactor *
     189                 :   74132501 : spdk_reactor_get(uint32_t lcore)
     190                 :            : {
     191                 :            :         struct spdk_reactor *reactor;
     192                 :            : 
     193         [ -  + ]:   74132501 :         if (g_reactors == NULL) {
     194                 :          0 :                 SPDK_WARNLOG("Called spdk_reactor_get() while the g_reactors array was NULL!\n");
     195                 :          0 :                 return NULL;
     196                 :            :         }
     197                 :            : 
     198         [ -  + ]:   74132501 :         if (lcore >= g_reactor_count) {
     199                 :          0 :                 return NULL;
     200                 :            :         }
     201                 :            : 
     202                 :   74132501 :         reactor = &g_reactors[lcore];
     203                 :            : 
     204         [ -  + ]:   74132501 :         if (reactor->flags.is_valid == false) {
     205                 :          0 :                 return NULL;
     206                 :            :         }
     207                 :            : 
     208                 :   74132501 :         return reactor;
     209                 :            : }
     210                 :            : 
     211                 :            : static int reactor_thread_op(struct spdk_thread *thread, enum spdk_thread_op op);
     212                 :            : static bool reactor_thread_op_supported(enum spdk_thread_op op);
     213                 :            : 
     214                 :            : int
     215                 :       2720 : spdk_reactors_init(size_t msg_mempool_size)
     216                 :            : {
     217                 :            :         struct spdk_reactor *reactor;
     218                 :            :         int rc;
     219                 :            :         uint32_t i, current_core;
     220                 :       1245 :         char mempool_name[32];
     221                 :            : 
     222         [ -  + ]:       2720 :         snprintf(mempool_name, sizeof(mempool_name), "evtpool_%d", getpid());
     223                 :       2720 :         g_spdk_event_mempool = spdk_mempool_create(mempool_name,
     224                 :            :                                262144 - 1, /* Power of 2 minus 1 is optimal for memory consumption */
     225                 :            :                                sizeof(struct spdk_event),
     226                 :            :                                SPDK_MEMPOOL_DEFAULT_CACHE_SIZE,
     227                 :            :                                SPDK_ENV_SOCKET_ID_ANY);
     228                 :            : 
     229         [ -  + ]:       2720 :         if (g_spdk_event_mempool == NULL) {
     230                 :          0 :                 SPDK_ERRLOG("spdk_event_mempool creation failed\n");
     231                 :          0 :                 return -1;
     232                 :            :         }
     233                 :            : 
     234                 :            :         /* struct spdk_reactor must be aligned on 64 byte boundary */
     235                 :       2720 :         g_reactor_count = spdk_env_get_last_core() + 1;
     236         [ -  + ]:       2720 :         rc = posix_memalign((void **)&g_reactors, 64,
     237                 :            :                             g_reactor_count * sizeof(struct spdk_reactor));
     238         [ -  + ]:       2720 :         if (rc != 0) {
     239                 :          0 :                 SPDK_ERRLOG("Could not allocate array size=%u for g_reactors\n",
     240                 :            :                             g_reactor_count);
     241                 :          0 :                 spdk_mempool_free(g_spdk_event_mempool);
     242                 :          0 :                 return -1;
     243                 :            :         }
     244                 :            : 
     245                 :       2720 :         g_core_infos = calloc(g_reactor_count, sizeof(*g_core_infos));
     246         [ -  + ]:       2720 :         if (g_core_infos == NULL) {
     247                 :          0 :                 SPDK_ERRLOG("Could not allocate memory for g_core_infos\n");
     248                 :          0 :                 spdk_mempool_free(g_spdk_event_mempool);
     249                 :          0 :                 free(g_reactors);
     250                 :          0 :                 return -ENOMEM;
     251                 :            :         }
     252                 :            : 
     253         [ -  + ]:       2720 :         memset(g_reactors, 0, (g_reactor_count) * sizeof(struct spdk_reactor));
     254                 :            : 
     255                 :       2720 :         rc = spdk_thread_lib_init_ext(reactor_thread_op, reactor_thread_op_supported,
     256                 :            :                                       sizeof(struct spdk_lw_thread), msg_mempool_size);
     257         [ -  + ]:       2720 :         if (rc != 0) {
     258                 :          0 :                 SPDK_ERRLOG("Initialize spdk thread lib failed\n");
     259                 :          0 :                 spdk_mempool_free(g_spdk_event_mempool);
     260                 :          0 :                 free(g_reactors);
     261                 :          0 :                 free(g_core_infos);
     262                 :          0 :                 return rc;
     263                 :            :         }
     264                 :            : 
     265         [ +  + ]:       6589 :         SPDK_ENV_FOREACH_CORE(i) {
     266                 :       3869 :                 reactor_construct(&g_reactors[i], i);
     267                 :            :         }
     268                 :            : 
     269                 :       2720 :         current_core = spdk_env_get_current_core();
     270                 :       2720 :         reactor = spdk_reactor_get(current_core);
     271         [ -  + ]:       2720 :         assert(reactor != NULL);
     272                 :       2720 :         g_scheduling_reactor = reactor;
     273                 :            : 
     274                 :       2720 :         g_reactor_state = SPDK_REACTOR_STATE_INITIALIZED;
     275                 :            : 
     276                 :       2720 :         return 0;
     277                 :            : }
     278                 :            : 
     279                 :            : void
     280                 :       2775 : spdk_reactors_fini(void)
     281                 :            : {
     282                 :            :         uint32_t i;
     283                 :            :         struct spdk_reactor *reactor;
     284                 :            : 
     285         [ +  + ]:       2775 :         if (g_reactor_state == SPDK_REACTOR_STATE_UNINITIALIZED) {
     286                 :         55 :                 return;
     287                 :            :         }
     288                 :            : 
     289                 :       2720 :         spdk_thread_lib_fini();
     290                 :            : 
     291         [ +  + ]:       6589 :         SPDK_ENV_FOREACH_CORE(i) {
     292                 :       3869 :                 reactor = spdk_reactor_get(i);
     293         [ -  + ]:       3869 :                 assert(reactor != NULL);
     294         [ -  + ]:       3869 :                 assert(reactor->thread_count == 0);
     295         [ +  - ]:       3869 :                 if (reactor->events != NULL) {
     296                 :       3869 :                         spdk_ring_free(reactor->events);
     297                 :            :                 }
     298                 :            : 
     299                 :       3869 :                 reactor_interrupt_fini(reactor);
     300                 :            : 
     301         [ +  - ]:       3869 :                 if (g_core_infos != NULL) {
     302                 :       3869 :                         free(g_core_infos[i].thread_infos);
     303                 :            :                 }
     304                 :            :         }
     305                 :            : 
     306                 :       2720 :         spdk_mempool_free(g_spdk_event_mempool);
     307                 :            : 
     308                 :       2720 :         free(g_reactors);
     309                 :       2720 :         g_reactors = NULL;
     310                 :       2720 :         free(g_core_infos);
     311                 :       2720 :         g_core_infos = NULL;
     312                 :            : }
     313                 :            : 
     314                 :            : static void _reactor_set_interrupt_mode(void *arg1, void *arg2);
     315                 :            : 
     316                 :            : static void
     317                 :        720 : _reactor_set_notify_cpuset(void *arg1, void *arg2)
     318                 :            : {
     319                 :        720 :         struct spdk_reactor *target = arg1;
     320                 :        720 :         struct spdk_reactor *reactor = spdk_reactor_get(spdk_env_get_current_core());
     321                 :            : 
     322         [ -  + ]:        720 :         assert(reactor != NULL);
     323         [ -  + ]:        720 :         spdk_cpuset_set_cpu(&reactor->notify_cpuset, target->lcore, target->new_in_interrupt);
     324                 :        720 : }
     325                 :            : 
     326                 :            : static void
     327                 :      27528 : _event_call(uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2)
     328                 :            : {
     329                 :            :         struct spdk_event *ev;
     330                 :            : 
     331                 :      27528 :         ev = spdk_event_allocate(lcore, fn, arg1, arg2);
     332         [ -  + ]:      27528 :         assert(ev);
     333                 :      27528 :         spdk_event_call(ev);
     334                 :      27528 : }
     335                 :            : 
     336                 :            : static void
     337                 :        167 : _reactor_set_notify_cpuset_cpl(void *arg1, void *arg2)
     338                 :            : {
     339                 :        167 :         struct spdk_reactor *target = arg1;
     340                 :            : 
     341   [ +  +  +  + ]:        167 :         if (target->new_in_interrupt == false) {
     342                 :         58 :                 target->set_interrupt_mode_in_progress = false;
     343                 :         58 :                 spdk_thread_send_msg(spdk_thread_get_app_thread(), target->set_interrupt_mode_cb_fn,
     344                 :            :                                      target->set_interrupt_mode_cb_arg);
     345                 :            :         } else {
     346                 :        109 :                 _event_call(target->lcore, _reactor_set_interrupt_mode, target, NULL);
     347                 :            :         }
     348                 :        167 : }
     349                 :            : 
     350                 :            : static void
     351                 :         40 : _reactor_set_thread_interrupt_mode(void *ctx)
     352                 :            : {
     353                 :         40 :         struct spdk_reactor *reactor = ctx;
     354                 :            : 
     355         [ -  + ]:         40 :         spdk_thread_set_interrupt_mode(reactor->in_interrupt);
     356                 :         40 : }
     357                 :            : 
     358                 :            : static void
     359                 :        167 : _reactor_set_interrupt_mode(void *arg1, void *arg2)
     360                 :            : {
     361                 :        167 :         struct spdk_reactor *target = arg1;
     362                 :            :         struct spdk_thread *thread;
     363                 :            :         struct spdk_fd_group *grp;
     364                 :            :         struct spdk_lw_thread *lw_thread, *tmp;
     365                 :            : 
     366         [ -  + ]:        167 :         assert(target == spdk_reactor_get(spdk_env_get_current_core()));
     367         [ -  + ]:        167 :         assert(target != NULL);
     368   [ -  +  -  +  :        167 :         assert(target->in_interrupt != target->new_in_interrupt);
                   -  + ]
     369   [ -  +  -  +  :        167 :         SPDK_DEBUGLOG(reactor, "Do reactor set on core %u from %s to state %s\n",
          -  -  -  -  -  
                -  -  - ]
     370                 :            :                       target->lcore, target->in_interrupt ? "intr" : "poll", target->new_in_interrupt ? "intr" : "poll");
     371                 :            : 
     372         [ -  + ]:        167 :         target->in_interrupt = target->new_in_interrupt;
     373                 :            : 
     374         [ +  + ]:        167 :         if (spdk_interrupt_mode_is_enabled()) {
     375                 :            :                 /* Align spdk_thread with reactor to interrupt mode or poll mode */
     376         [ +  + ]:         50 :                 TAILQ_FOREACH_SAFE(lw_thread, &target->threads, link, tmp) {
     377                 :         10 :                         thread = spdk_thread_get_from_ctx(lw_thread);
     378   [ +  +  +  + ]:         10 :                         if (target->in_interrupt) {
     379                 :          5 :                                 grp = spdk_thread_get_interrupt_fd_group(thread);
     380                 :          5 :                                 spdk_fd_group_nest(target->fgrp, grp);
     381                 :            :                         } else {
     382                 :          5 :                                 grp = spdk_thread_get_interrupt_fd_group(thread);
     383                 :          5 :                                 spdk_fd_group_unnest(target->fgrp, grp);
     384                 :            :                         }
     385                 :            : 
     386                 :         10 :                         spdk_thread_send_msg(thread, _reactor_set_thread_interrupt_mode, target);
     387                 :            :                 }
     388                 :            :         }
     389                 :            : 
     390   [ +  +  +  + ]:        167 :         if (target->new_in_interrupt == false) {
     391                 :            :                 /* Reactor is no longer in interrupt mode. Refresh the tsc_last to accurately
     392                 :            :                  * track reactor stats. */
     393                 :         58 :                 target->tsc_last = spdk_get_ticks();
     394                 :         58 :                 spdk_for_each_reactor(_reactor_set_notify_cpuset, target, NULL, _reactor_set_notify_cpuset_cpl);
     395                 :            :         } else {
     396                 :        109 :                 uint64_t notify = 1;
     397                 :        109 :                 int rc = 0;
     398                 :            : 
     399                 :            :                 /* Always trigger spdk_event and resched event in case of race condition */
     400                 :        109 :                 rc = write(target->events_fd, &notify, sizeof(notify));
     401         [ -  + ]:        109 :                 if (rc < 0) {
     402                 :          0 :                         SPDK_ERRLOG("failed to notify event queue: %s.\n", spdk_strerror(errno));
     403                 :            :                 }
     404                 :        109 :                 rc = write(target->resched_fd, &notify, sizeof(notify));
     405         [ -  + ]:        109 :                 if (rc < 0) {
     406                 :          0 :                         SPDK_ERRLOG("failed to notify reschedule: %s.\n", spdk_strerror(errno));
     407                 :            :                 }
     408                 :            : 
     409                 :        109 :                 target->set_interrupt_mode_in_progress = false;
     410                 :        109 :                 spdk_thread_send_msg(spdk_thread_get_app_thread(), target->set_interrupt_mode_cb_fn,
     411                 :            :                                      target->set_interrupt_mode_cb_arg);
     412                 :            :         }
     413                 :        167 : }
     414                 :            : 
     415                 :            : int
     416                 :        168 : spdk_reactor_set_interrupt_mode(uint32_t lcore, bool new_in_interrupt,
     417                 :            :                                 spdk_reactor_set_interrupt_mode_cb cb_fn, void *cb_arg)
     418                 :            : {
     419                 :            :         struct spdk_reactor *target;
     420                 :            : 
     421                 :        168 :         target = spdk_reactor_get(lcore);
     422         [ -  + ]:        168 :         if (target == NULL) {
     423                 :          0 :                 return -EINVAL;
     424                 :            :         }
     425                 :            : 
     426                 :            :         /* Eventfd has to be supported in order to use interrupt functionality. */
     427         [ -  + ]:        168 :         if (target->fgrp == NULL) {
     428                 :          0 :                 return -ENOTSUP;
     429                 :            :         }
     430                 :            : 
     431         [ -  + ]:        168 :         if (!spdk_thread_is_app_thread(NULL)) {
     432                 :          0 :                 SPDK_ERRLOG("It is only permitted within spdk application thread.\n");
     433                 :          0 :                 return -EPERM;
     434                 :            :         }
     435                 :            : 
     436   [ -  +  -  + ]:        168 :         if (target->in_interrupt == new_in_interrupt) {
     437                 :          0 :                 cb_fn(cb_arg);
     438                 :          0 :                 return 0;
     439                 :            :         }
     440                 :            : 
     441   [ -  +  -  + ]:        168 :         if (target->set_interrupt_mode_in_progress) {
     442                 :          0 :                 SPDK_NOTICELOG("Reactor(%u) is already in progress to set interrupt mode\n", lcore);
     443                 :          0 :                 return -EBUSY;
     444                 :            :         }
     445                 :        168 :         target->set_interrupt_mode_in_progress = true;
     446                 :            : 
     447                 :        168 :         target->new_in_interrupt = new_in_interrupt;
     448                 :        168 :         target->set_interrupt_mode_cb_fn = cb_fn;
     449                 :        168 :         target->set_interrupt_mode_cb_arg = cb_arg;
     450                 :            : 
     451   [ -  +  -  + ]:        168 :         SPDK_DEBUGLOG(reactor, "Starting reactor event from %d to %d\n",
     452                 :            :                       spdk_env_get_current_core(), lcore);
     453                 :            : 
     454         [ +  + ]:        168 :         if (new_in_interrupt == false) {
     455                 :            :                 /* For potential race cases, when setting the reactor to poll mode,
     456                 :            :                  * first change the mode of the reactor and then clear the corresponding
     457                 :            :                  * bit of the notify_cpuset of each reactor.
     458                 :            :                  */
     459                 :         58 :                 _event_call(lcore, _reactor_set_interrupt_mode, target, NULL);
     460                 :            :         } else {
     461                 :            :                 /* For race cases, when setting the reactor to interrupt mode, first set the
     462                 :            :                  * corresponding bit of the notify_cpuset of each reactor and then change the mode.
     463                 :            :                  */
     464                 :        110 :                 spdk_for_each_reactor(_reactor_set_notify_cpuset, target, NULL, _reactor_set_notify_cpuset_cpl);
     465                 :            :         }
     466                 :            : 
     467                 :        168 :         return 0;
     468                 :            : }
     469                 :            : 
     470                 :            : struct spdk_event *
     471                 :   24700219 : spdk_event_allocate(uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2)
     472                 :            : {
     473                 :   24700219 :         struct spdk_event *event = NULL;
     474                 :   24700219 :         struct spdk_reactor *reactor = spdk_reactor_get(lcore);
     475                 :            : 
     476         [ -  + ]:   24700219 :         if (!reactor) {
     477                 :          0 :                 assert(false);
     478                 :            :                 return NULL;
     479                 :            :         }
     480                 :            : 
     481                 :   24700219 :         event = spdk_mempool_get(g_spdk_event_mempool);
     482         [ -  + ]:   24700219 :         if (event == NULL) {
     483                 :          0 :                 assert(false);
     484                 :            :                 return NULL;
     485                 :            :         }
     486                 :            : 
     487                 :   24700219 :         event->lcore = lcore;
     488                 :   24700219 :         event->fn = fn;
     489                 :   24700219 :         event->arg1 = arg1;
     490                 :   24700219 :         event->arg2 = arg2;
     491                 :            : 
     492                 :   24700219 :         return event;
     493                 :            : }
     494                 :            : 
     495                 :            : void
     496                 :   24700219 : spdk_event_call(struct spdk_event *event)
     497                 :            : {
     498                 :            :         int rc;
     499                 :            :         struct spdk_reactor *reactor;
     500                 :   24700219 :         struct spdk_reactor *local_reactor = NULL;
     501                 :   24700219 :         uint32_t current_core = spdk_env_get_current_core();
     502                 :            : 
     503                 :   24700219 :         reactor = spdk_reactor_get(event->lcore);
     504                 :            : 
     505         [ -  + ]:   24700219 :         assert(reactor != NULL);
     506         [ -  + ]:   24700219 :         assert(reactor->events != NULL);
     507                 :            : 
     508                 :   24700219 :         rc = spdk_ring_enqueue(reactor->events, (void **)&event, 1, NULL);
     509         [ -  + ]:   24700219 :         if (rc != 1) {
     510                 :          0 :                 assert(false);
     511                 :            :         }
     512                 :            : 
     513         [ +  - ]:   24700219 :         if (current_core != SPDK_ENV_LCORE_ID_ANY) {
     514                 :   24700219 :                 local_reactor = spdk_reactor_get(current_core);
     515                 :            :         }
     516                 :            : 
     517                 :            :         /* If spdk_event_call isn't called on a reactor, always send a notification.
     518                 :            :          * If it is called on a reactor, send a notification if the destination reactor
     519                 :            :          * is indicated in interrupt mode state.
     520                 :            :          */
     521         [ +  - ]:   24700219 :         if (spdk_unlikely(local_reactor == NULL) ||
     522         [ +  + ]:   24700219 :             spdk_unlikely(spdk_cpuset_get_cpu(&local_reactor->notify_cpuset, event->lcore))) {
     523                 :      71634 :                 uint64_t notify = 1;
     524                 :            : 
     525                 :      71634 :                 rc = write(reactor->events_fd, &notify, sizeof(notify));
     526         [ -  + ]:      71634 :                 if (rc < 0) {
     527                 :          0 :                         SPDK_ERRLOG("failed to notify event queue: %s.\n", spdk_strerror(errno));
     528                 :            :                 }
     529                 :            :         }
     530                 :   24700219 : }
     531                 :            : 
     532                 :            : static inline int
     533                 : 9555854147 : event_queue_run_batch(void *arg)
     534                 :            : {
     535                 : 9555854147 :         struct spdk_reactor *reactor = arg;
     536                 :            :         size_t count, i;
     537                 : 4954007604 :         void *events[SPDK_EVENT_BATCH_SIZE];
     538                 :            :         struct spdk_thread *thread;
     539                 :            :         struct spdk_lw_thread *lw_thread;
     540                 :            : 
     541                 :            : #ifdef DEBUG
     542                 :            :         /*
     543                 :            :          * spdk_ring_dequeue() fills events and returns how many entries it wrote,
     544                 :            :          * so we will never actually read uninitialized data from events, but just to be sure
     545                 :            :          * (and to silence a static analyzer false positive), initialize the array to NULL pointers.
     546                 :            :          */
     547                 : 9555854147 :         memset(events, 0, sizeof(events));
     548                 :            : #endif
     549                 :            : 
     550                 :            :         /* Operate event notification if this reactor currently runs in interrupt state */
     551   [ +  +  +  + ]: 9555854147 :         if (spdk_unlikely(reactor->in_interrupt)) {
     552                 :      71486 :                 uint64_t notify = 1;
     553                 :            :                 int rc;
     554                 :            : 
     555                 :            :                 /* There may be race between event_acknowledge and another producer's event_notify,
     556                 :            :                  * so event_acknowledge should be applied ahead. And then check for self's event_notify.
     557                 :            :                  * This can avoid event notification missing.
     558                 :            :                  */
     559                 :      71486 :                 rc = read(reactor->events_fd, &notify, sizeof(notify));
     560         [ -  + ]:      71486 :                 if (rc < 0) {
     561                 :          0 :                         SPDK_ERRLOG("failed to acknowledge event queue: %s.\n", spdk_strerror(errno));
     562                 :          0 :                         return -errno;
     563                 :            :                 }
     564                 :            : 
     565                 :      71486 :                 count = spdk_ring_dequeue(reactor->events, events, SPDK_EVENT_BATCH_SIZE);
     566                 :            : 
     567         [ -  + ]:      71486 :                 if (spdk_ring_count(reactor->events) != 0) {
     568                 :            :                         /* Trigger new notification if there are still events in event-queue waiting for processing. */
     569                 :          0 :                         rc = write(reactor->events_fd, &notify, sizeof(notify));
     570         [ #  # ]:          0 :                         if (rc < 0) {
     571                 :          0 :                                 SPDK_ERRLOG("failed to notify event queue: %s.\n", spdk_strerror(errno));
     572                 :          0 :                                 return -errno;
     573                 :            :                         }
     574                 :            :                 }
     575                 :            :         } else {
     576                 : 9555782562 :                 count = spdk_ring_dequeue(reactor->events, events, SPDK_EVENT_BATCH_SIZE);
     577                 :            :         }
     578                 :            : 
     579         [ +  + ]: 9555854147 :         if (count == 0) {
     580                 : 9541850901 :                 return 0;
     581                 :            :         }
     582                 :            : 
     583                 :            :         /* Execute the events. There are still some remaining events
     584                 :            :          * that must occur on an SPDK thread. To accommodate those, try to
     585                 :            :          * run them on the first thread in the list, if it exists. */
     586                 :   14003540 :         lw_thread = TAILQ_FIRST(&reactor->threads);
     587         [ +  + ]:   14003540 :         if (lw_thread) {
     588                 :   10255597 :                 thread = spdk_thread_get_from_ctx(lw_thread);
     589                 :            :         } else {
     590                 :    3747943 :                 thread = NULL;
     591                 :            :         }
     592                 :            : 
     593         [ +  + ]:   38703736 :         for (i = 0; i < count; i++) {
     594                 :   24700200 :                 struct spdk_event *event = events[i];
     595                 :            : 
     596         [ -  + ]:   24700200 :                 assert(event != NULL);
     597                 :   24700200 :                 spdk_set_thread(thread);
     598                 :            : 
     599                 :    2296519 :                 SPDK_DTRACE_PROBE3(event_exec, event->fn,
     600                 :            :                                    event->arg1, event->arg2);
     601                 :   24700200 :                 event->fn(event->arg1, event->arg2);
     602                 :   24700200 :                 spdk_set_thread(NULL);
     603                 :            :         }
     604                 :            : 
     605                 :   14003540 :         spdk_mempool_put_bulk(g_spdk_event_mempool, events, count);
     606                 :            : 
     607                 :   14003540 :         return (int)count;
     608                 :            : }
     609                 :            : 
     610                 :            : /* 1s */
     611                 :            : #define CONTEXT_SWITCH_MONITOR_PERIOD 1000000
     612                 :            : 
     613                 :            : static int
     614                 :      28870 : get_rusage(struct spdk_reactor *reactor)
     615                 :            : {
     616                 :      11947 :         struct rusage           rusage;
     617                 :            : 
     618         [ -  + ]:      28870 :         if (getrusage(RUSAGE_THREAD, &rusage) != 0) {
     619                 :          0 :                 return -1;
     620                 :            :         }
     621                 :            : 
     622   [ +  +  +  + ]:      28870 :         if (rusage.ru_nvcsw != reactor->rusage.ru_nvcsw || rusage.ru_nivcsw != reactor->rusage.ru_nivcsw) {
     623   [ -  +  -  + ]:      27616 :                 SPDK_INFOLOG(reactor,
     624                 :            :                              "Reactor %d: %ld voluntary context switches and %ld involuntary context switches in the last second.\n",
     625                 :            :                              reactor->lcore, rusage.ru_nvcsw - reactor->rusage.ru_nvcsw,
     626                 :            :                              rusage.ru_nivcsw - reactor->rusage.ru_nivcsw);
     627                 :            :         }
     628                 :      28870 :         reactor->rusage = rusage;
     629                 :            : 
     630                 :      28870 :         return -1;
     631                 :            : }
     632                 :            : 
     633                 :            : void
     634                 :          0 : spdk_framework_enable_context_switch_monitor(bool enable)
     635                 :            : {
     636                 :            :         /* This global is being read by multiple threads, so this isn't
     637                 :            :          * strictly thread safe. However, we're toggling between true and
     638                 :            :          * false here, and if a thread sees the value update later than it
     639                 :            :          * should, it's no big deal. */
     640                 :          0 :         g_framework_context_switch_monitor_enabled = enable;
     641                 :          0 : }
     642                 :            : 
     643                 :            : bool
     644                 :          0 : spdk_framework_context_switch_monitor_enabled(void)
     645                 :            : {
     646         [ #  # ]:          0 :         return g_framework_context_switch_monitor_enabled;
     647                 :            : }
     648                 :            : 
     649                 :            : static void
     650                 :       3800 : _set_thread_name(const char *thread_name)
     651                 :            : {
     652                 :            : #if defined(__linux__)
     653                 :       3800 :         prctl(PR_SET_NAME, thread_name, 0, 0, 0);
     654                 :            : #elif defined(__FreeBSD__)
     655                 :            :         pthread_set_name_np(pthread_self(), thread_name);
     656                 :            : #else
     657                 :            :         pthread_setname_np(pthread_self(), thread_name);
     658                 :            : #endif
     659                 :       3800 : }
     660                 :            : 
     661                 :            : static void
     662                 :       1158 : _init_thread_stats(struct spdk_reactor *reactor, struct spdk_lw_thread *lw_thread)
     663                 :            : {
     664                 :       1158 :         struct spdk_thread *thread = spdk_thread_get_from_ctx(lw_thread);
     665                 :            :         struct spdk_thread_stats prev_total_stats;
     666                 :            : 
     667                 :            :         /* Read total_stats before updating it to calculate stats during the last scheduling period. */
     668                 :       1158 :         prev_total_stats = lw_thread->total_stats;
     669                 :            : 
     670                 :       1158 :         spdk_set_thread(thread);
     671                 :       1158 :         spdk_thread_get_stats(&lw_thread->total_stats);
     672                 :       1158 :         spdk_set_thread(NULL);
     673                 :            : 
     674                 :       1158 :         lw_thread->current_stats.busy_tsc = lw_thread->total_stats.busy_tsc - prev_total_stats.busy_tsc;
     675                 :       1158 :         lw_thread->current_stats.idle_tsc = lw_thread->total_stats.idle_tsc - prev_total_stats.idle_tsc;
     676                 :       1158 : }
     677                 :            : 
     678                 :            : static void
     679                 :         82 : _threads_reschedule_thread(struct spdk_scheduler_thread_info *thread_info)
     680                 :            : {
     681                 :            :         struct spdk_lw_thread *lw_thread;
     682                 :            :         struct spdk_thread *thread;
     683                 :            : 
     684                 :         82 :         thread = spdk_thread_get_by_id(thread_info->thread_id);
     685         [ +  + ]:         82 :         if (thread == NULL) {
     686                 :            :                 /* Thread no longer exists. */
     687                 :          8 :                 return;
     688                 :            :         }
     689                 :         74 :         lw_thread = spdk_thread_get_ctx(thread);
     690         [ -  + ]:         74 :         assert(lw_thread != NULL);
     691                 :            : 
     692                 :         74 :         lw_thread->lcore = thread_info->lcore;
     693                 :         74 :         lw_thread->resched = true;
     694                 :            : }
     695                 :            : 
     696                 :            : static void
     697                 :        181 : _threads_reschedule(struct spdk_scheduler_core_info *cores_info)
     698                 :            : {
     699                 :            :         struct spdk_scheduler_core_info *core;
     700                 :            :         struct spdk_scheduler_thread_info *thread_info;
     701                 :            :         uint32_t i, j;
     702                 :            : 
     703         [ +  + ]:       1211 :         SPDK_ENV_FOREACH_CORE(i) {
     704                 :       1030 :                 core = &cores_info[i];
     705         [ +  + ]:       2185 :                 for (j = 0; j < core->threads_count; j++) {
     706                 :       1155 :                         thread_info = &core->thread_infos[j];
     707         [ +  + ]:       1155 :                         if (thread_info->lcore != i) {
     708                 :         82 :                                 _threads_reschedule_thread(thread_info);
     709                 :            :                         }
     710                 :            :                 }
     711                 :       1030 :                 core->threads_count = 0;
     712                 :       1030 :                 free(core->thread_infos);
     713                 :       1030 :                 core->thread_infos = NULL;
     714                 :            :         }
     715                 :        181 : }
     716                 :            : 
     717                 :            : static void
     718                 :        181 : _reactors_scheduler_fini(void)
     719                 :            : {
     720                 :            :         /* Reschedule based on the balancing output */
     721                 :        181 :         _threads_reschedule(g_core_infos);
     722                 :            : 
     723                 :        181 :         g_scheduling_in_progress = false;
     724                 :        181 : }
     725                 :            : 
     726                 :            : static void
     727                 :        309 : _reactors_scheduler_update_core_mode(void *ctx)
     728                 :            : {
     729                 :            :         struct spdk_reactor *reactor;
     730                 :            :         uint32_t i;
     731                 :        309 :         int rc = 0;
     732                 :            : 
     733         [ +  + ]:       1213 :         for (i = g_scheduler_core_number; i < SPDK_ENV_LCORE_ID_ANY; i = spdk_env_get_next_core(i)) {
     734                 :       1032 :                 reactor = spdk_reactor_get(i);
     735         [ -  + ]:       1032 :                 assert(reactor != NULL);
     736   [ +  +  -  +  :       1032 :                 if (reactor->in_interrupt != g_core_infos[i].interrupt_mode) {
                   +  + ]
     737                 :            :                         /* Switch next found reactor to new state */
     738         [ -  + ]:        128 :                         rc = spdk_reactor_set_interrupt_mode(i, g_core_infos[i].interrupt_mode,
     739                 :            :                                                              _reactors_scheduler_update_core_mode, NULL);
     740         [ +  - ]:        128 :                         if (rc == 0) {
     741                 :            :                                 /* Set core to start with after callback completes */
     742                 :        128 :                                 g_scheduler_core_number = spdk_env_get_next_core(i);
     743                 :        128 :                                 return;
     744                 :            :                         }
     745                 :            :                 }
     746                 :            :         }
     747                 :        181 :         _reactors_scheduler_fini();
     748                 :            : }
     749                 :            : 
     750                 :            : static void
     751                 :          1 : _reactors_scheduler_cancel(void *arg1, void *arg2)
     752                 :            : {
     753                 :            :         struct spdk_scheduler_core_info *core;
     754                 :            :         uint32_t i;
     755                 :            : 
     756         [ +  + ]:          5 :         SPDK_ENV_FOREACH_CORE(i) {
     757                 :          4 :                 core = &g_core_infos[i];
     758                 :          4 :                 core->threads_count = 0;
     759                 :          4 :                 free(core->thread_infos);
     760                 :          4 :                 core->thread_infos = NULL;
     761                 :            :         }
     762                 :            : 
     763                 :          1 :         g_scheduling_in_progress = false;
     764                 :          1 : }
     765                 :            : 
     766                 :            : static void
     767                 :        183 : _reactors_scheduler_balance(void *arg1, void *arg2)
     768                 :            : {
     769                 :        183 :         struct spdk_scheduler *scheduler = spdk_scheduler_get();
     770                 :            : 
     771   [ +  -  +  + ]:        183 :         if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING || scheduler == NULL) {
     772                 :          1 :                 _reactors_scheduler_cancel(NULL, NULL);
     773                 :          1 :                 return;
     774                 :            :         }
     775                 :            : 
     776                 :        182 :         scheduler->balance(g_core_infos, g_reactor_count);
     777                 :            : 
     778                 :        182 :         g_scheduler_core_number = spdk_env_get_first_core();
     779                 :        182 :         _reactors_scheduler_update_core_mode(NULL);
     780                 :            : }
     781                 :            : 
     782                 :            : /* Phase 1 of thread scheduling is to gather metrics on the existing threads */
     783                 :            : static void
     784                 :       1038 : _reactors_scheduler_gather_metrics(void *arg1, void *arg2)
     785                 :            : {
     786                 :            :         struct spdk_scheduler_core_info *core_info;
     787                 :            :         struct spdk_lw_thread *lw_thread;
     788                 :            :         struct spdk_thread *thread;
     789                 :            :         struct spdk_reactor *reactor;
     790                 :            :         uint32_t next_core;
     791                 :       1038 :         uint32_t i = 0;
     792                 :            : 
     793                 :       1038 :         reactor = spdk_reactor_get(spdk_env_get_current_core());
     794         [ -  + ]:       1038 :         assert(reactor != NULL);
     795                 :       1038 :         core_info = &g_core_infos[reactor->lcore];
     796                 :       1038 :         core_info->lcore = reactor->lcore;
     797                 :       1038 :         core_info->current_idle_tsc = reactor->idle_tsc - core_info->total_idle_tsc;
     798                 :       1038 :         core_info->total_idle_tsc = reactor->idle_tsc;
     799                 :       1038 :         core_info->current_busy_tsc = reactor->busy_tsc - core_info->total_busy_tsc;
     800                 :       1038 :         core_info->total_busy_tsc = reactor->busy_tsc;
     801         [ -  + ]:       1038 :         core_info->interrupt_mode = reactor->in_interrupt;
     802                 :       1038 :         core_info->threads_count = 0;
     803                 :            : 
     804   [ -  +  -  + ]:       1038 :         SPDK_DEBUGLOG(reactor, "Gathering metrics on %u\n", reactor->lcore);
     805                 :            : 
     806         [ +  + ]:       1038 :         if (reactor->thread_count > 0) {
     807                 :        311 :                 core_info->thread_infos = calloc(reactor->thread_count, sizeof(*core_info->thread_infos));
     808         [ -  + ]:        311 :                 if (core_info->thread_infos == NULL) {
     809                 :          0 :                         SPDK_ERRLOG("Failed to allocate memory when gathering metrics on %u\n", reactor->lcore);
     810                 :            : 
     811                 :            :                         /* Cancel this round of schedule work */
     812                 :          0 :                         _event_call(g_scheduling_reactor->lcore, _reactors_scheduler_cancel, NULL, NULL);
     813                 :          0 :                         return;
     814                 :            :                 }
     815                 :            : 
     816         [ +  + ]:       1469 :                 TAILQ_FOREACH(lw_thread, &reactor->threads, link) {
     817                 :       1158 :                         _init_thread_stats(reactor, lw_thread);
     818                 :            : 
     819                 :       1158 :                         core_info->thread_infos[i].lcore = lw_thread->lcore;
     820                 :       1158 :                         thread = spdk_thread_get_from_ctx(lw_thread);
     821         [ -  + ]:       1158 :                         assert(thread != NULL);
     822                 :       1158 :                         core_info->thread_infos[i].thread_id = spdk_thread_get_id(thread);
     823                 :       1158 :                         core_info->thread_infos[i].total_stats = lw_thread->total_stats;
     824                 :       1158 :                         core_info->thread_infos[i].current_stats = lw_thread->current_stats;
     825                 :       1158 :                         core_info->threads_count++;
     826         [ -  + ]:       1158 :                         assert(core_info->threads_count <= reactor->thread_count);
     827                 :       1158 :                         i++;
     828                 :            :                 }
     829                 :            :         }
     830                 :            : 
     831                 :       1038 :         next_core = spdk_env_get_next_core(reactor->lcore);
     832         [ +  + ]:       1038 :         if (next_core == UINT32_MAX) {
     833                 :        183 :                 next_core = spdk_env_get_first_core();
     834                 :            :         }
     835                 :            : 
     836                 :            :         /* If we've looped back around to the scheduler thread, move to the next phase */
     837         [ +  + ]:       1038 :         if (next_core == g_scheduling_reactor->lcore) {
     838                 :            :                 /* Phase 2 of scheduling is rebalancing - deciding which threads to move where */
     839                 :        183 :                 _event_call(next_core, _reactors_scheduler_balance, NULL, NULL);
     840                 :        183 :                 return;
     841                 :            :         }
     842                 :            : 
     843                 :        855 :         _event_call(next_core, _reactors_scheduler_gather_metrics, NULL, NULL);
     844                 :            : }
     845                 :            : 
     846                 :            : static int _reactor_schedule_thread(struct spdk_thread *thread);
     847                 :            : static uint64_t g_rusage_period;
     848                 :            : 
     849                 :            : static void
     850                 :       6971 : _reactor_remove_lw_thread(struct spdk_reactor *reactor, struct spdk_lw_thread *lw_thread)
     851                 :            : {
     852                 :       6971 :         struct spdk_thread      *thread = spdk_thread_get_from_ctx(lw_thread);
     853                 :            :         struct spdk_fd_group    *grp;
     854                 :            : 
     855         [ +  + ]:       6971 :         TAILQ_REMOVE(&reactor->threads, lw_thread, link);
     856         [ -  + ]:       6971 :         assert(reactor->thread_count > 0);
     857                 :       6971 :         reactor->thread_count--;
     858                 :            : 
     859                 :            :         /* Operate thread intr if running with full interrupt ability */
     860         [ +  + ]:       6971 :         if (spdk_interrupt_mode_is_enabled()) {
     861   [ +  +  +  - ]:         30 :                 if (reactor->in_interrupt) {
     862                 :         30 :                         grp = spdk_thread_get_interrupt_fd_group(thread);
     863                 :         30 :                         spdk_fd_group_unnest(reactor->fgrp, grp);
     864                 :            :                 }
     865                 :            :         }
     866                 :       6971 : }
     867                 :            : 
     868                 :            : static bool
     869                 :10836984817 : reactor_post_process_lw_thread(struct spdk_reactor *reactor, struct spdk_lw_thread *lw_thread)
     870                 :            : {
     871                 :10836984817 :         struct spdk_thread *thread = spdk_thread_get_from_ctx(lw_thread);
     872                 :            : 
     873   [ +  +  +  + ]:10836984817 :         if (spdk_unlikely(spdk_thread_is_exited(thread) &&
     874                 :            :                           spdk_thread_is_idle(thread))) {
     875                 :       3309 :                 _reactor_remove_lw_thread(reactor, lw_thread);
     876                 :       3309 :                 spdk_thread_destroy(thread);
     877                 :       3309 :                 return true;
     878                 :            :         }
     879                 :            : 
     880   [ +  +  +  +  :10836981813 :         if (spdk_unlikely(lw_thread->resched && !spdk_thread_is_bound(thread))) {
                   +  + ]
     881                 :         77 :                 lw_thread->resched = false;
     882                 :         77 :                 _reactor_remove_lw_thread(reactor, lw_thread);
     883                 :         77 :                 _reactor_schedule_thread(thread);
     884                 :         77 :                 return true;
     885                 :            :         }
     886                 :            : 
     887                 :10836981740 :         return false;
     888                 :            : }
     889                 :            : 
     890                 :            : static void
     891                 :    5406456 : reactor_interrupt_run(struct spdk_reactor *reactor)
     892                 :            : {
     893                 :    5406456 :         int block_timeout = -1; /* _EPOLL_WAIT_FOREVER */
     894                 :            : 
     895                 :    5406456 :         spdk_fd_group_wait(reactor->fgrp, block_timeout);
     896                 :    5406456 : }
     897                 :            : 
     898                 :            : static void
     899                 : 9555782274 : _reactor_run(struct spdk_reactor *reactor)
     900                 :            : {
     901                 :            :         struct spdk_thread      *thread;
     902                 :            :         struct spdk_lw_thread   *lw_thread, *tmp;
     903                 :            :         uint64_t                now;
     904                 :            :         int                     rc;
     905                 :            : 
     906                 : 9555782274 :         event_queue_run_batch(reactor);
     907                 :            : 
     908                 :            :         /* If no threads are present on the reactor,
     909                 :            :          * tsc_last gets outdated. Update it to track
     910                 :            :          * thread execution time correctly. */
     911         [ +  + ]: 9555782274 :         if (spdk_unlikely(TAILQ_EMPTY(&reactor->threads))) {
     912                 : 1940505286 :                 now = spdk_get_ticks();
     913                 : 1940505286 :                 reactor->idle_tsc += now - reactor->tsc_last;
     914                 : 1940505286 :                 reactor->tsc_last = now;
     915                 : 1940505286 :                 return;
     916                 :            :         }
     917                 :            : 
     918         [ +  + ]:18452260788 :         TAILQ_FOREACH_SAFE(lw_thread, &reactor->threads, link, tmp) {
     919                 :10836984800 :                 thread = spdk_thread_get_from_ctx(lw_thread);
     920                 :10836984800 :                 rc = spdk_thread_poll(thread, 0, reactor->tsc_last);
     921                 :            : 
     922                 :10836984800 :                 now = spdk_thread_get_last_tsc(thread);
     923         [ +  + ]:10836984800 :                 if (rc == 0) {
     924                 :10757033596 :                         reactor->idle_tsc += now - reactor->tsc_last;
     925         [ +  - ]:   79951434 :                 } else if (rc > 0) {
     926                 :   79951434 :                         reactor->busy_tsc += now - reactor->tsc_last;
     927                 :            :                 }
     928                 :10836984800 :                 reactor->tsc_last = now;
     929                 :            : 
     930                 :10836984800 :                 reactor_post_process_lw_thread(reactor, lw_thread);
     931                 :            :         }
     932                 :            : }
     933                 :            : 
     934                 :            : static int
     935                 :       3800 : reactor_run(void *arg)
     936                 :            : {
     937                 :       3800 :         struct spdk_reactor     *reactor = arg;
     938                 :            :         struct spdk_thread      *thread;
     939                 :            :         struct spdk_lw_thread   *lw_thread, *tmp;
     940                 :       1556 :         char                    thread_name[32];
     941                 :       3800 :         uint64_t                last_sched = 0;
     942                 :            : 
     943                 :       3800 :         SPDK_NOTICELOG("Reactor started on core %u\n", reactor->lcore);
     944                 :            : 
     945                 :            :         /* Rename the POSIX thread because the reactor is tied to the POSIX
     946                 :            :          * thread in the SPDK event library.
     947                 :            :          */
     948                 :       3800 :         snprintf(thread_name, sizeof(thread_name), "reactor_%u", reactor->lcore);
     949                 :       3800 :         _set_thread_name(thread_name);
     950                 :            : 
     951                 :       3800 :         reactor->tsc_last = spdk_get_ticks();
     952                 :            : 
     953                 :            :         while (1) {
     954                 :            :                 /* Execute interrupt process fn if this reactor currently runs in interrupt state */
     955   [ +  +  +  + ]: 9561188630 :                 if (spdk_unlikely(reactor->in_interrupt)) {
     956                 :    5406440 :                         reactor_interrupt_run(reactor);
     957                 :            :                 } else {
     958                 : 9555782138 :                         _reactor_run(reactor);
     959                 :            :                 }
     960                 :            : 
     961   [ +  +  +  - ]: 9561188630 :                 if (g_framework_context_switch_monitor_enabled) {
     962         [ +  + ]: 9561188630 :                         if ((reactor->last_rusage + g_rusage_period) < reactor->tsc_last) {
     963                 :      28870 :                                 get_rusage(reactor);
     964                 :      28870 :                                 reactor->last_rusage = reactor->tsc_last;
     965                 :            :                         }
     966                 :            :                 }
     967                 :            : 
     968   [ +  +  +  +  : 9561188630 :                 if (spdk_unlikely(g_scheduler_period > 0 &&
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     969                 :            :                                   (reactor->tsc_last - last_sched) > g_scheduler_period &&
     970                 :            :                                   reactor == g_scheduling_reactor &&
     971                 :            :                                   !g_scheduling_in_progress)) {
     972                 :        159 :                         last_sched = reactor->tsc_last;
     973                 :        159 :                         g_scheduling_in_progress = true;
     974                 :        159 :                         _reactors_scheduler_gather_metrics(NULL, NULL);
     975                 :            :                 }
     976                 :            : 
     977         [ +  + ]: 9561188630 :                 if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) {
     978                 :       3800 :                         break;
     979                 :            :                 }
     980                 :            :         }
     981                 :            : 
     982         [ +  + ]:       7385 :         TAILQ_FOREACH(lw_thread, &reactor->threads, link) {
     983                 :       3585 :                 thread = spdk_thread_get_from_ctx(lw_thread);
     984                 :            :                 /* All threads should have already had spdk_thread_exit() called on them, except
     985                 :            :                  * for the app thread.
     986                 :            :                  */
     987         [ +  + ]:       3585 :                 if (spdk_thread_is_running(thread)) {
     988         [ -  + ]:       2683 :                         if (!spdk_thread_is_app_thread(thread)) {
     989                 :          0 :                                 SPDK_ERRLOG("spdk_thread_exit() was not called on thread '%s'\n",
     990                 :            :                                             spdk_thread_get_name(thread));
     991                 :          0 :                                 SPDK_ERRLOG("This will result in a non-zero exit code in a future release.\n");
     992                 :            :                         }
     993                 :       2683 :                         spdk_set_thread(thread);
     994                 :       2683 :                         spdk_thread_exit(thread);
     995                 :            :                 }
     996                 :            :         }
     997                 :            : 
     998         [ +  + ]:       9487 :         while (!TAILQ_EMPTY(&reactor->threads)) {
     999         [ +  + ]:      11955 :                 TAILQ_FOREACH_SAFE(lw_thread, &reactor->threads, link, tmp) {
    1000                 :       6268 :                         thread = spdk_thread_get_from_ctx(lw_thread);
    1001                 :       6268 :                         spdk_set_thread(thread);
    1002         [ +  + ]:       6268 :                         if (spdk_thread_is_exited(thread)) {
    1003                 :       3585 :                                 _reactor_remove_lw_thread(reactor, lw_thread);
    1004                 :       3585 :                                 spdk_thread_destroy(thread);
    1005                 :            :                         } else {
    1006   [ +  +  +  + ]:       2683 :                                 if (spdk_unlikely(reactor->in_interrupt)) {
    1007                 :         16 :                                         reactor_interrupt_run(reactor);
    1008                 :            :                                 } else {
    1009                 :       2667 :                                         spdk_thread_poll(thread, 0, 0);
    1010                 :            :                                 }
    1011                 :            :                         }
    1012                 :            :                 }
    1013                 :            :         }
    1014                 :            : 
    1015                 :       3800 :         return 0;
    1016                 :            : }
    1017                 :            : 
    1018                 :            : int
    1019                 :         10 : spdk_app_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
    1020                 :            : {
    1021                 :            :         int ret;
    1022                 :            :         const struct spdk_cpuset *validmask;
    1023                 :            : 
    1024                 :         10 :         ret = spdk_cpuset_parse(cpumask, mask);
    1025         [ -  + ]:         10 :         if (ret < 0) {
    1026                 :          0 :                 return ret;
    1027                 :            :         }
    1028                 :            : 
    1029                 :         10 :         validmask = spdk_app_get_core_mask();
    1030                 :         10 :         spdk_cpuset_and(cpumask, validmask);
    1031                 :            : 
    1032                 :         10 :         return 0;
    1033                 :            : }
    1034                 :            : 
    1035                 :            : const struct spdk_cpuset *
    1036                 :        239 : spdk_app_get_core_mask(void)
    1037                 :            : {
    1038                 :        239 :         return &g_reactor_core_mask;
    1039                 :            : }
    1040                 :            : 
    1041                 :            : void
    1042                 :       2683 : spdk_reactors_start(void)
    1043                 :            : {
    1044                 :            :         struct spdk_reactor *reactor;
    1045                 :            :         uint32_t i, current_core;
    1046                 :            :         int rc;
    1047                 :            : 
    1048                 :       2683 :         g_rusage_period = (CONTEXT_SWITCH_MONITOR_PERIOD * spdk_get_ticks_hz()) / SPDK_SEC_TO_USEC;
    1049                 :       2683 :         g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
    1050                 :            :         /* Reinitialize to false, in case the app framework is restarting in the same process. */
    1051                 :       2683 :         g_stopping_reactors = false;
    1052                 :            : 
    1053                 :       2683 :         current_core = spdk_env_get_current_core();
    1054         [ +  + ]:       6447 :         SPDK_ENV_FOREACH_CORE(i) {
    1055         [ +  + ]:       3764 :                 if (i != current_core) {
    1056                 :       1081 :                         reactor = spdk_reactor_get(i);
    1057         [ -  + ]:       1081 :                         if (reactor == NULL) {
    1058                 :          0 :                                 continue;
    1059                 :            :                         }
    1060                 :            : 
    1061                 :       1081 :                         rc = spdk_env_thread_launch_pinned(reactor->lcore, reactor_run, reactor);
    1062         [ -  + ]:       1081 :                         if (rc < 0) {
    1063                 :          0 :                                 SPDK_ERRLOG("Unable to start reactor thread on core %u\n", reactor->lcore);
    1064                 :          0 :                                 assert(false);
    1065                 :            :                                 return;
    1066                 :            :                         }
    1067                 :            :                 }
    1068                 :       3764 :                 spdk_cpuset_set_cpu(&g_reactor_core_mask, i, true);
    1069                 :            :         }
    1070                 :            : 
    1071                 :            :         /* Start the main reactor */
    1072                 :       2683 :         reactor = spdk_reactor_get(current_core);
    1073         [ -  + ]:       2683 :         assert(reactor != NULL);
    1074                 :       2683 :         reactor_run(reactor);
    1075                 :            : 
    1076                 :       2683 :         spdk_env_thread_wait_all();
    1077                 :            : 
    1078                 :       2683 :         g_reactor_state = SPDK_REACTOR_STATE_SHUTDOWN;
    1079                 :            : }
    1080                 :            : 
    1081                 :            : static void
    1082                 :       2683 : _reactors_stop(void *arg1, void *arg2)
    1083                 :            : {
    1084                 :            :         uint32_t i;
    1085                 :            :         int rc;
    1086                 :            :         struct spdk_reactor *reactor;
    1087                 :            :         struct spdk_reactor *local_reactor;
    1088                 :       2683 :         uint64_t notify = 1;
    1089                 :            : 
    1090                 :       2683 :         g_reactor_state = SPDK_REACTOR_STATE_EXITING;
    1091                 :       2683 :         local_reactor = spdk_reactor_get(spdk_env_get_current_core());
    1092                 :            : 
    1093         [ +  + ]:       6447 :         SPDK_ENV_FOREACH_CORE(i) {
    1094                 :            :                 /* If spdk_event_call isn't called  on a reactor, always send a notification.
    1095                 :            :                  * If it is called on a reactor, send a notification if the destination reactor
    1096                 :            :                  * is indicated in interrupt mode state.
    1097                 :            :                  */
    1098   [ +  -  +  + ]:       3764 :                 if (local_reactor == NULL || spdk_cpuset_get_cpu(&local_reactor->notify_cpuset, i)) {
    1099                 :        100 :                         reactor = spdk_reactor_get(i);
    1100         [ -  + ]:        100 :                         assert(reactor != NULL);
    1101                 :        100 :                         rc = write(reactor->events_fd, &notify, sizeof(notify));
    1102         [ -  + ]:        100 :                         if (rc < 0) {
    1103                 :          0 :                                 SPDK_ERRLOG("failed to notify event queue for reactor(%u): %s.\n", i, spdk_strerror(errno));
    1104                 :          0 :                                 continue;
    1105                 :            :                         }
    1106                 :            :                 }
    1107                 :            :         }
    1108                 :       2683 : }
    1109                 :            : 
    1110                 :            : static void
    1111                 :       3764 : nop(void *arg1, void *arg2)
    1112                 :            : {
    1113                 :       3764 : }
    1114                 :            : 
    1115                 :            : void
    1116                 :       2683 : spdk_reactors_stop(void *arg1)
    1117                 :            : {
    1118                 :       2683 :         spdk_for_each_reactor(nop, NULL, NULL, _reactors_stop);
    1119                 :       2683 : }
    1120                 :            : 
    1121                 :            : static pthread_mutex_t g_scheduler_mtx = PTHREAD_MUTEX_INITIALIZER;
    1122                 :            : static uint32_t g_next_core = UINT32_MAX;
    1123                 :            : 
    1124                 :            : static void
    1125                 :       6979 : _schedule_thread(void *arg1, void *arg2)
    1126                 :            : {
    1127                 :       6979 :         struct spdk_lw_thread *lw_thread = arg1;
    1128                 :            :         struct spdk_thread *thread;
    1129                 :            :         struct spdk_reactor *reactor;
    1130                 :            :         uint32_t current_core;
    1131                 :            :         struct spdk_fd_group *grp;
    1132                 :            : 
    1133                 :       6979 :         current_core = spdk_env_get_current_core();
    1134                 :       6979 :         reactor = spdk_reactor_get(current_core);
    1135         [ -  + ]:       6979 :         assert(reactor != NULL);
    1136                 :            : 
    1137                 :            :         /* Update total_stats to reflect state of thread
    1138                 :            :         * at the end of the move. */
    1139                 :       6979 :         thread = spdk_thread_get_from_ctx(lw_thread);
    1140                 :       6979 :         spdk_set_thread(thread);
    1141                 :       6979 :         spdk_thread_get_stats(&lw_thread->total_stats);
    1142                 :       6979 :         spdk_set_thread(NULL);
    1143                 :            : 
    1144                 :       6979 :         lw_thread->lcore = current_core;
    1145                 :            : 
    1146                 :       6979 :         TAILQ_INSERT_TAIL(&reactor->threads, lw_thread, link);
    1147                 :       6979 :         reactor->thread_count++;
    1148                 :            : 
    1149                 :            :         /* Operate thread intr if running with full interrupt ability */
    1150         [ +  + ]:       6979 :         if (spdk_interrupt_mode_is_enabled()) {
    1151                 :            :                 int rc;
    1152                 :            : 
    1153   [ +  +  +  - ]:         30 :                 if (reactor->in_interrupt) {
    1154                 :         30 :                         grp = spdk_thread_get_interrupt_fd_group(thread);
    1155                 :         30 :                         rc = spdk_fd_group_nest(reactor->fgrp, grp);
    1156         [ -  + ]:         30 :                         if (rc < 0) {
    1157                 :          0 :                                 SPDK_ERRLOG("Failed to schedule spdk_thread: %s.\n", spdk_strerror(-rc));
    1158                 :            :                         }
    1159                 :            :                 }
    1160                 :            : 
    1161                 :            :                 /* Align spdk_thread with reactor to interrupt mode or poll mode */
    1162                 :         30 :                 spdk_thread_send_msg(thread, _reactor_set_thread_interrupt_mode, reactor);
    1163                 :            :         }
    1164                 :       6979 : }
    1165                 :            : 
    1166                 :            : static int
    1167                 :       6980 : _reactor_schedule_thread(struct spdk_thread *thread)
    1168                 :            : {
    1169                 :            :         uint32_t core;
    1170                 :            :         struct spdk_lw_thread *lw_thread;
    1171                 :       6980 :         struct spdk_event *evt = NULL;
    1172                 :            :         struct spdk_cpuset *cpumask;
    1173                 :            :         uint32_t i;
    1174                 :       6980 :         struct spdk_reactor *local_reactor = NULL;
    1175                 :       6980 :         uint32_t current_lcore = spdk_env_get_current_core();
    1176                 :       3023 :         struct spdk_cpuset polling_cpumask;
    1177                 :       3023 :         struct spdk_cpuset valid_cpumask;
    1178                 :            : 
    1179                 :       6980 :         cpumask = spdk_thread_get_cpumask(thread);
    1180                 :            : 
    1181                 :       6980 :         lw_thread = spdk_thread_get_ctx(thread);
    1182         [ -  + ]:       6980 :         assert(lw_thread != NULL);
    1183                 :       6980 :         core = lw_thread->lcore;
    1184         [ -  + ]:       6980 :         memset(lw_thread, 0, sizeof(*lw_thread));
    1185                 :            : 
    1186         [ +  - ]:       6980 :         if (current_lcore != SPDK_ENV_LCORE_ID_ANY) {
    1187                 :       6980 :                 local_reactor = spdk_reactor_get(current_lcore);
    1188         [ -  + ]:       6980 :                 assert(local_reactor);
    1189                 :            :         }
    1190                 :            : 
    1191                 :            :         /* When interrupt ability of spdk_thread is not enabled and the current
    1192                 :            :          * reactor runs on DPDK thread, skip reactors which are in interrupt mode.
    1193                 :            :          */
    1194   [ +  +  +  - ]:       6980 :         if (!spdk_interrupt_mode_is_enabled() && local_reactor != NULL) {
    1195                 :            :                 /* Get the cpumask of all reactors in polling */
    1196                 :       6950 :                 spdk_cpuset_zero(&polling_cpumask);
    1197         [ +  + ]:      19661 :                 SPDK_ENV_FOREACH_CORE(i) {
    1198                 :      12711 :                         spdk_cpuset_set_cpu(&polling_cpumask, i, true);
    1199                 :            :                 }
    1200                 :       6950 :                 spdk_cpuset_xor(&polling_cpumask, &local_reactor->notify_cpuset);
    1201                 :            : 
    1202         [ +  + ]:       6950 :                 if (core == SPDK_ENV_LCORE_ID_ANY) {
    1203                 :            :                         /* Get the cpumask of all valid reactors which are suggested and also in polling */
    1204                 :       6887 :                         spdk_cpuset_copy(&valid_cpumask, &polling_cpumask);
    1205                 :       6887 :                         spdk_cpuset_and(&valid_cpumask, spdk_thread_get_cpumask(thread));
    1206                 :            : 
    1207                 :            :                         /* If there are any valid reactors, spdk_thread should be scheduled
    1208                 :            :                          * into one of the valid reactors.
    1209                 :            :                          * If there is no valid reactors, spdk_thread should be scheduled
    1210                 :            :                          * into one of the polling reactors.
    1211                 :            :                          */
    1212         [ +  + ]:       6887 :                         if (spdk_cpuset_count(&valid_cpumask) != 0) {
    1213                 :       6756 :                                 cpumask = &valid_cpumask;
    1214                 :            :                         } else {
    1215                 :        131 :                                 cpumask = &polling_cpumask;
    1216                 :            :                         }
    1217         [ -  + ]:         63 :                 } else if (!spdk_cpuset_get_cpu(&polling_cpumask, core)) {
    1218                 :            :                         /* If specified reactor is not in polling, spdk_thread should be scheduled
    1219                 :            :                          * into one of the polling reactors.
    1220                 :            :                          */
    1221                 :          0 :                         core = SPDK_ENV_LCORE_ID_ANY;
    1222                 :          0 :                         cpumask = &polling_cpumask;
    1223                 :            :                 }
    1224                 :            :         }
    1225                 :            : 
    1226         [ -  + ]:       6980 :         pthread_mutex_lock(&g_scheduler_mtx);
    1227         [ +  + ]:       6980 :         if (core == SPDK_ENV_LCORE_ID_ANY) {
    1228         [ +  - ]:       8280 :                 for (i = 0; i < spdk_env_get_core_count(); i++) {
    1229         [ +  + ]:       8280 :                         if (g_next_core >= g_reactor_count) {
    1230                 :       5699 :                                 g_next_core = spdk_env_get_first_core();
    1231                 :            :                         }
    1232                 :       8280 :                         core = g_next_core;
    1233                 :       8280 :                         g_next_core = spdk_env_get_next_core(g_next_core);
    1234                 :            : 
    1235         [ +  + ]:       8280 :                         if (spdk_cpuset_get_cpu(cpumask, core)) {
    1236                 :       6917 :                                 break;
    1237                 :            :                         }
    1238                 :            :                 }
    1239                 :            :         }
    1240                 :            : 
    1241                 :       6980 :         evt = spdk_event_allocate(core, _schedule_thread, lw_thread, NULL);
    1242                 :            : 
    1243         [ -  + ]:       6980 :         pthread_mutex_unlock(&g_scheduler_mtx);
    1244                 :            : 
    1245         [ -  + ]:       6980 :         assert(evt != NULL);
    1246         [ -  + ]:       6980 :         if (evt == NULL) {
    1247                 :          0 :                 SPDK_ERRLOG("Unable to schedule thread on requested core mask.\n");
    1248                 :          0 :                 return -1;
    1249                 :            :         }
    1250                 :            : 
    1251                 :       6980 :         lw_thread->tsc_start = spdk_get_ticks();
    1252                 :            : 
    1253                 :       6980 :         spdk_event_call(evt);
    1254                 :            : 
    1255                 :       6980 :         return 0;
    1256                 :            : }
    1257                 :            : 
    1258                 :            : static void
    1259                 :         38 : _reactor_request_thread_reschedule(struct spdk_thread *thread)
    1260                 :            : {
    1261                 :            :         struct spdk_lw_thread *lw_thread;
    1262                 :            :         struct spdk_reactor *reactor;
    1263                 :            :         uint32_t current_core;
    1264                 :            : 
    1265         [ -  + ]:         38 :         assert(thread == spdk_get_thread());
    1266                 :            : 
    1267                 :         38 :         lw_thread = spdk_thread_get_ctx(thread);
    1268                 :            : 
    1269         [ -  + ]:         38 :         assert(lw_thread != NULL);
    1270                 :         38 :         lw_thread->resched = true;
    1271                 :         38 :         lw_thread->lcore = SPDK_ENV_LCORE_ID_ANY;
    1272                 :            : 
    1273                 :         38 :         current_core = spdk_env_get_current_core();
    1274                 :         38 :         reactor = spdk_reactor_get(current_core);
    1275         [ -  + ]:         38 :         assert(reactor != NULL);
    1276                 :            : 
    1277                 :            :         /* Send a notification if the destination reactor is indicated in intr mode state */
    1278         [ +  + ]:         38 :         if (spdk_unlikely(spdk_cpuset_get_cpu(&reactor->notify_cpuset, reactor->lcore))) {
    1279                 :         30 :                 uint64_t notify = 1;
    1280                 :            : 
    1281         [ -  + ]:         30 :                 if (write(reactor->resched_fd, &notify, sizeof(notify)) < 0) {
    1282                 :          0 :                         SPDK_ERRLOG("failed to notify reschedule: %s.\n", spdk_strerror(errno));
    1283                 :            :                 }
    1284                 :            :         }
    1285                 :         38 : }
    1286                 :            : 
    1287                 :            : static int
    1288                 :       6941 : reactor_thread_op(struct spdk_thread *thread, enum spdk_thread_op op)
    1289                 :            : {
    1290                 :            :         struct spdk_lw_thread *lw_thread;
    1291                 :            : 
    1292      [ +  +  - ]:       6941 :         switch (op) {
    1293                 :       6903 :         case SPDK_THREAD_OP_NEW:
    1294                 :       6903 :                 lw_thread = spdk_thread_get_ctx(thread);
    1295                 :       6903 :                 lw_thread->lcore = SPDK_ENV_LCORE_ID_ANY;
    1296                 :       6903 :                 return _reactor_schedule_thread(thread);
    1297                 :         38 :         case SPDK_THREAD_OP_RESCHED:
    1298                 :         38 :                 _reactor_request_thread_reschedule(thread);
    1299                 :         38 :                 return 0;
    1300                 :          0 :         default:
    1301                 :          0 :                 return -ENOTSUP;
    1302                 :            :         }
    1303                 :            : }
    1304                 :            : 
    1305                 :            : static bool
    1306                 :       6921 : reactor_thread_op_supported(enum spdk_thread_op op)
    1307                 :            : {
    1308         [ +  - ]:       6921 :         switch (op) {
    1309                 :       6921 :         case SPDK_THREAD_OP_NEW:
    1310                 :            :         case SPDK_THREAD_OP_RESCHED:
    1311                 :       6921 :                 return true;
    1312                 :          0 :         default:
    1313                 :          0 :                 return false;
    1314                 :            :         }
    1315                 :            : }
    1316                 :            : 
    1317                 :            : struct call_reactor {
    1318                 :            :         uint32_t cur_core;
    1319                 :            :         spdk_event_fn fn;
    1320                 :            :         void *arg1;
    1321                 :            :         void *arg2;
    1322                 :            : 
    1323                 :            :         uint32_t orig_core;
    1324                 :            :         spdk_event_fn cpl;
    1325                 :            : };
    1326                 :            : 
    1327                 :            : static void
    1328                 :      98428 : on_reactor(void *arg1, void *arg2)
    1329                 :            : {
    1330                 :      98428 :         struct call_reactor *cr = arg1;
    1331                 :            :         struct spdk_event *evt;
    1332                 :            : 
    1333                 :      98428 :         cr->fn(cr->arg1, cr->arg2);
    1334                 :            : 
    1335                 :      98428 :         cr->cur_core = spdk_env_get_next_core(cr->cur_core);
    1336                 :            : 
    1337         [ +  + ]:      98428 :         if (cr->cur_core >= g_reactor_count) {
    1338   [ -  +  -  + ]:      26323 :                 SPDK_DEBUGLOG(reactor, "Completed reactor iteration\n");
    1339                 :            : 
    1340                 :      26323 :                 evt = spdk_event_allocate(cr->orig_core, cr->cpl, cr->arg1, cr->arg2);
    1341                 :      26323 :                 free(cr);
    1342                 :            :         } else {
    1343   [ -  +  -  + ]:      72105 :                 SPDK_DEBUGLOG(reactor, "Continuing reactor iteration to %d\n",
    1344                 :            :                               cr->cur_core);
    1345                 :            : 
    1346                 :      72105 :                 evt = spdk_event_allocate(cr->cur_core, on_reactor, arg1, NULL);
    1347                 :            :         }
    1348         [ -  + ]:      98428 :         assert(evt != NULL);
    1349                 :      98428 :         spdk_event_call(evt);
    1350                 :      98428 : }
    1351                 :            : 
    1352                 :            : void
    1353                 :      26343 : spdk_for_each_reactor(spdk_event_fn fn, void *arg1, void *arg2, spdk_event_fn cpl)
    1354                 :            : {
    1355                 :            :         struct call_reactor *cr;
    1356                 :            : 
    1357                 :            :         /* When the application framework is shutting down, we will send one
    1358                 :            :          * final for_each_reactor operation with completion callback _reactors_stop,
    1359                 :            :          * to flush any existing for_each_reactor operations to avoid any memory
    1360                 :            :          * leaks. We use a mutex here to protect a boolean flag that will ensure
    1361                 :            :          * we don't start any more operations once we've started shutting down.
    1362                 :            :          */
    1363         [ -  + ]:      26343 :         pthread_mutex_lock(&g_stopping_reactors_mtx);
    1364   [ +  +  +  + ]:      26343 :         if (g_stopping_reactors) {
    1365         [ -  + ]:         20 :                 pthread_mutex_unlock(&g_stopping_reactors_mtx);
    1366                 :         20 :                 return;
    1367         [ +  + ]:      26323 :         } else if (cpl == _reactors_stop) {
    1368                 :       2683 :                 g_stopping_reactors = true;
    1369                 :            :         }
    1370         [ -  + ]:      26323 :         pthread_mutex_unlock(&g_stopping_reactors_mtx);
    1371                 :            : 
    1372                 :      26323 :         cr = calloc(1, sizeof(*cr));
    1373         [ -  + ]:      26323 :         if (!cr) {
    1374                 :          0 :                 SPDK_ERRLOG("Unable to perform reactor iteration\n");
    1375                 :          0 :                 cpl(arg1, arg2);
    1376                 :          0 :                 return;
    1377                 :            :         }
    1378                 :            : 
    1379                 :      26323 :         cr->fn = fn;
    1380                 :      26323 :         cr->arg1 = arg1;
    1381                 :      26323 :         cr->arg2 = arg2;
    1382                 :      26323 :         cr->cpl = cpl;
    1383                 :      26323 :         cr->orig_core = spdk_env_get_current_core();
    1384                 :      26323 :         cr->cur_core = spdk_env_get_first_core();
    1385                 :            : 
    1386   [ -  +  -  + ]:      26323 :         SPDK_DEBUGLOG(reactor, "Starting reactor iteration from %d\n", cr->orig_core);
    1387                 :            : 
    1388                 :      26323 :         _event_call(cr->cur_core, on_reactor, cr, NULL);
    1389                 :            : }
    1390                 :            : 
    1391                 :            : #ifdef __linux__
    1392                 :            : static int
    1393                 :        119 : reactor_schedule_thread_event(void *arg)
    1394                 :            : {
    1395                 :        119 :         struct spdk_reactor *reactor = arg;
    1396                 :            :         struct spdk_lw_thread *lw_thread, *tmp;
    1397                 :        119 :         uint32_t count = 0;
    1398                 :        119 :         uint64_t notify = 1;
    1399                 :            : 
    1400   [ -  +  -  + ]:        119 :         assert(reactor->in_interrupt);
    1401                 :            : 
    1402         [ -  + ]:        119 :         if (read(reactor->resched_fd, &notify, sizeof(notify)) < 0) {
    1403                 :          0 :                 SPDK_ERRLOG("failed to acknowledge reschedule: %s.\n", spdk_strerror(errno));
    1404                 :          0 :                 return -errno;
    1405                 :            :         }
    1406                 :            : 
    1407         [ +  + ]:        139 :         TAILQ_FOREACH_SAFE(lw_thread, &reactor->threads, link, tmp) {
    1408                 :         20 :                 count += reactor_post_process_lw_thread(reactor, lw_thread) ? 1 : 0;
    1409                 :            :         }
    1410                 :            : 
    1411                 :        119 :         return count;
    1412                 :            : }
    1413                 :            : 
    1414                 :            : static int
    1415                 :       3873 : reactor_interrupt_init(struct spdk_reactor *reactor)
    1416                 :            : {
    1417                 :            :         int rc;
    1418                 :            : 
    1419                 :       3873 :         rc = spdk_fd_group_create(&reactor->fgrp);
    1420         [ -  + ]:       3873 :         if (rc != 0) {
    1421                 :          0 :                 return rc;
    1422                 :            :         }
    1423                 :            : 
    1424                 :       3873 :         reactor->resched_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    1425         [ -  + ]:       3873 :         if (reactor->resched_fd < 0) {
    1426                 :          0 :                 rc = -EBADF;
    1427                 :          0 :                 goto err;
    1428                 :            :         }
    1429                 :            : 
    1430                 :       3873 :         rc = SPDK_FD_GROUP_ADD(reactor->fgrp, reactor->resched_fd, reactor_schedule_thread_event,
    1431                 :            :                                reactor);
    1432         [ -  + ]:       3873 :         if (rc) {
    1433                 :          0 :                 close(reactor->resched_fd);
    1434                 :          0 :                 goto err;
    1435                 :            :         }
    1436                 :            : 
    1437                 :       3873 :         reactor->events_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    1438         [ -  + ]:       3873 :         if (reactor->events_fd < 0) {
    1439                 :          0 :                 spdk_fd_group_remove(reactor->fgrp, reactor->resched_fd);
    1440                 :          0 :                 close(reactor->resched_fd);
    1441                 :            : 
    1442                 :          0 :                 rc = -EBADF;
    1443                 :          0 :                 goto err;
    1444                 :            :         }
    1445                 :            : 
    1446                 :       3873 :         rc = SPDK_FD_GROUP_ADD(reactor->fgrp, reactor->events_fd,
    1447                 :            :                                event_queue_run_batch, reactor);
    1448         [ -  + ]:       3873 :         if (rc) {
    1449                 :          0 :                 spdk_fd_group_remove(reactor->fgrp, reactor->resched_fd);
    1450                 :          0 :                 close(reactor->resched_fd);
    1451                 :          0 :                 close(reactor->events_fd);
    1452                 :          0 :                 goto err;
    1453                 :            :         }
    1454                 :            : 
    1455                 :       3873 :         return 0;
    1456                 :            : 
    1457                 :          0 : err:
    1458                 :          0 :         spdk_fd_group_destroy(reactor->fgrp);
    1459                 :          0 :         reactor->fgrp = NULL;
    1460                 :          0 :         return rc;
    1461                 :            : }
    1462                 :            : #else
    1463                 :            : static int
    1464                 :            : reactor_interrupt_init(struct spdk_reactor *reactor)
    1465                 :            : {
    1466                 :            :         return -ENOTSUP;
    1467                 :            : }
    1468                 :            : #endif
    1469                 :            : 
    1470                 :            : static void
    1471                 :       3873 : reactor_interrupt_fini(struct spdk_reactor *reactor)
    1472                 :            : {
    1473                 :       3873 :         struct spdk_fd_group *fgrp = reactor->fgrp;
    1474                 :            : 
    1475         [ -  + ]:       3873 :         if (!fgrp) {
    1476                 :          0 :                 return;
    1477                 :            :         }
    1478                 :            : 
    1479                 :       3873 :         spdk_fd_group_remove(fgrp, reactor->events_fd);
    1480                 :       3873 :         spdk_fd_group_remove(fgrp, reactor->resched_fd);
    1481                 :            : 
    1482                 :       3873 :         close(reactor->events_fd);
    1483                 :       3873 :         close(reactor->resched_fd);
    1484                 :            : 
    1485                 :       3873 :         spdk_fd_group_destroy(fgrp);
    1486                 :       3873 :         reactor->fgrp = NULL;
    1487                 :            : }
    1488                 :            : 
    1489                 :            : static struct spdk_governor *
    1490                 :       2241 : _governor_find(const char *name)
    1491                 :            : {
    1492                 :            :         struct spdk_governor *governor, *tmp;
    1493                 :            : 
    1494         [ +  + ]:       2241 :         TAILQ_FOREACH_SAFE(governor, &g_governor_list, link, tmp) {
    1495   [ +  +  -  +  :         26 :                 if (strcmp(name, governor->name) == 0) {
                   +  - ]
    1496                 :         26 :                         return governor;
    1497                 :            :                 }
    1498                 :            :         }
    1499                 :            : 
    1500                 :       2215 :         return NULL;
    1501                 :            : }
    1502                 :            : 
    1503                 :            : int
    1504                 :         52 : spdk_governor_set(const char *name)
    1505                 :            : {
    1506                 :            :         struct spdk_governor *governor;
    1507                 :         52 :         int rc = 0;
    1508                 :            : 
    1509                 :            :         /* NULL governor was specifically requested */
    1510         [ +  + ]:         52 :         if (name == NULL) {
    1511         [ +  + ]:         22 :                 if (g_governor) {
    1512                 :         10 :                         g_governor->deinit();
    1513                 :            :                 }
    1514                 :         22 :                 g_governor = NULL;
    1515                 :         22 :                 return 0;
    1516                 :            :         }
    1517                 :            : 
    1518                 :         30 :         governor = _governor_find(name);
    1519         [ +  + ]:         30 :         if (governor == NULL) {
    1520                 :          4 :                 return -EINVAL;
    1521                 :            :         }
    1522                 :            : 
    1523         [ -  + ]:         26 :         if (g_governor == governor) {
    1524                 :          0 :                 return 0;
    1525                 :            :         }
    1526                 :            : 
    1527                 :         26 :         rc = governor->init();
    1528         [ +  + ]:         26 :         if (rc == 0) {
    1529         [ -  + ]:         14 :                 if (g_governor) {
    1530                 :          0 :                         g_governor->deinit();
    1531                 :            :                 }
    1532                 :         14 :                 g_governor = governor;
    1533                 :            :         }
    1534                 :            : 
    1535                 :         26 :         return rc;
    1536                 :            : }
    1537                 :            : 
    1538                 :            : struct spdk_governor *
    1539                 :        269 : spdk_governor_get(void)
    1540                 :            : {
    1541                 :        269 :         return g_governor;
    1542                 :            : }
    1543                 :            : 
    1544                 :            : void
    1545                 :       2211 : spdk_governor_register(struct spdk_governor *governor)
    1546                 :            : {
    1547         [ -  + ]:       2211 :         if (_governor_find(governor->name)) {
    1548                 :          0 :                 SPDK_ERRLOG("governor named '%s' already registered.\n", governor->name);
    1549                 :          0 :                 assert(false);
    1550                 :            :                 return;
    1551                 :            :         }
    1552                 :            : 
    1553                 :       2211 :         TAILQ_INSERT_TAIL(&g_governor_list, governor, link);
    1554                 :            : }
    1555                 :            : 
    1556                 :       2850 : SPDK_LOG_REGISTER_COMPONENT(reactor)

Generated by: LCOV version 1.14