LCOV - code coverage report
Current view: top level - spdk/examples/thread/thread - thread_ex.c (source / functions) Hit Total Coverage
Test: Combined Lines: 0 260 0.0 %
Date: 2024-07-11 10:44:40 Functions: 0 29 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 162 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2022 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/event.h"
      10                 :            : #include "spdk/init.h"
      11                 :            : #include "spdk/string.h"
      12                 :            : #include "spdk/thread.h"
      13                 :            : #include "spdk/bdev.h"
      14                 :            : #include "spdk/rpc.h"
      15                 :            : #include "spdk/likely.h"
      16                 :            : 
      17                 :            : #include "spdk_internal/event.h"
      18                 :            : #include "spdk_internal/thread.h"
      19                 :            : 
      20                 :            : #define NAME_MAX_LENGTH 256
      21                 :            : #define TIMED_POLLER_PERIOD 1000000
      22                 :            : #define POLLING_TIME 6
      23                 :            : #define MAX_POLLER_TYPE_STR_LEN 100
      24                 :            : 
      25                 :            : #define POLLER_TYPE_ACTIVE "active"
      26                 :            : #define POLLER_TYPE_TIMED "timed"
      27                 :            : 
      28                 :            : struct lw_thread {
      29                 :            :         TAILQ_ENTRY(lw_thread) link;
      30                 :            :         bool resched;
      31                 :            : };
      32                 :            : 
      33                 :            : struct reactor {
      34                 :            :         uint32_t core;
      35                 :            : 
      36                 :            :         struct spdk_ring        *threads;
      37                 :            :         TAILQ_ENTRY(reactor)    link;
      38                 :            : };
      39                 :            : 
      40                 :            : struct poller_ctx {
      41                 :            :         char *poller_type;
      42                 :            :         uint64_t *run_count;
      43                 :            : };
      44                 :            : 
      45                 :            : static struct reactor g_main_reactor;
      46                 :            : static struct spdk_thread *g_init_thread = NULL;
      47                 :            : static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
      48                 :            : static uint64_t g_time_start;
      49                 :            : static uint64_t g_counting_poller_counter;
      50                 :            : static uint64_t g_printing_poller_counter;
      51                 :            : static uint64_t g_for_each_thread_poller_counter;
      52                 :            : static uint64_t g_for_each_channel_poller_counter;
      53                 :            : static uint64_t g_thread_poll_cnt;
      54                 :            : static uint64_t g_io_channel_cnt;
      55                 :            : static struct spdk_poller *g_active_poller = NULL, *g_timed_poller = NULL;
      56                 :            : static struct spdk_poller *g_timed_for_each_thread = NULL, *g_timed_for_each_channel = NULL;
      57                 :            : 
      58                 :            : static int schedule_spdk_thread(struct spdk_thread *thread);
      59                 :            : 
      60                 :            : static void
      61                 :          0 : usage(char *program_name)
      62                 :            : {
      63         [ #  # ]:          0 :         printf("%s options", program_name);
      64                 :          0 :         printf("\n");
      65         [ #  # ]:          0 :         printf("\t[-h show this usage message]\n");
      66                 :          0 : }
      67                 :            : 
      68                 :            : static int
      69                 :          0 : parse_args(int argc, char **argv, struct spdk_env_opts *opts)
      70                 :            : {
      71                 :            :         int op;
      72                 :            : 
      73   [ #  #  #  #  :          0 :         while ((op = getopt(argc, argv, "h")) != -1) {
                   #  # ]
      74         [ #  # ]:          0 :                 switch (op) {
      75                 :          0 :                 case 'h':
      76                 :          0 :                         usage(argv[0]);
      77                 :          0 :                         exit(EXIT_SUCCESS);
      78                 :          0 :                 default:
      79                 :          0 :                         usage(argv[0]);
      80                 :          0 :                         return 1;
      81                 :            :                 }
      82                 :            :         }
      83                 :            : 
      84                 :          0 :         return 0;
      85                 :            : }
      86                 :            : 
      87                 :            : static void
      88                 :          0 : reactor_run(void)
      89                 :            : {
      90                 :          0 :         struct reactor *reactor = &g_main_reactor;
      91                 :          0 :         struct lw_thread *lw_thread;
      92                 :          0 :         struct spdk_thread *thread = NULL;
      93                 :            : 
      94                 :            :         /* Run all the SPDK threads in this reactor by FIFO. */
      95         [ #  # ]:          0 :         if (spdk_ring_dequeue(reactor->threads, (void **)&lw_thread, 1)) {
      96                 :          0 :                 thread = spdk_thread_get_from_ctx(lw_thread);
      97         [ #  # ]:          0 :                 assert(thread != NULL);
      98                 :            : 
      99                 :          0 :                 spdk_thread_poll(thread, 0, 0);
     100                 :            : 
     101                 :            :                 /* spdk_unlikely() is a branch prediction macro. Here it means the
     102                 :            :                  * thread should not be exited and idle, but it is still possible. */
     103   [ #  #  #  # ]:          0 :                 if (spdk_unlikely(spdk_thread_is_exited(thread) &&
     104                 :            :                                   spdk_thread_is_idle(thread))) {
     105                 :          0 :                         spdk_thread_destroy(thread);
     106                 :            :                 } else {
     107                 :          0 :                         spdk_ring_enqueue(reactor->threads, (void **)&lw_thread, 1, NULL);
     108                 :            :                 }
     109                 :            :         }
     110                 :          0 : }
     111                 :            : 
     112                 :            : static void
     113                 :          0 : reactor_run_fini(void)
     114                 :            : {
     115                 :          0 :         struct reactor *reactor = &g_main_reactor;
     116                 :          0 :         struct lw_thread *lw_thread;
     117                 :          0 :         struct spdk_thread *thread = NULL;
     118                 :            : 
     119                 :            :         /* Free all the lightweight threads. */
     120         [ #  # ]:          0 :         while (spdk_ring_dequeue(reactor->threads, (void **)&lw_thread, 1)) {
     121                 :          0 :                 thread = spdk_thread_get_from_ctx(lw_thread);
     122         [ #  # ]:          0 :                 assert(thread != NULL);
     123                 :          0 :                 spdk_set_thread(thread);
     124                 :            : 
     125         [ #  # ]:          0 :                 if (spdk_thread_is_exited(thread)) {
     126                 :          0 :                         spdk_thread_destroy(thread);
     127                 :            :                 } else {
     128                 :            :                         /* This thread is not exited yet, and may need to communicate
     129                 :            :                          * with other threads to be exited. So mark it as exiting,
     130                 :            :                          * and check again after traversing other threads. */
     131                 :          0 :                         spdk_thread_exit(thread);
     132                 :          0 :                         spdk_thread_poll(thread, 0, 0);
     133                 :          0 :                         spdk_ring_enqueue(reactor->threads, (void **)&lw_thread, 1, NULL);
     134                 :            :                 }
     135                 :            :         }
     136                 :          0 : }
     137                 :            : 
     138                 :            : static int
     139                 :          0 : schedule_spdk_thread(struct spdk_thread *thread)
     140                 :            : {
     141                 :            :         struct reactor *reactor;
     142                 :          0 :         struct lw_thread *lw_thread;
     143                 :            : 
     144                 :          0 :         lw_thread = spdk_thread_get_ctx(thread);
     145         [ #  # ]:          0 :         assert(lw_thread != NULL);
     146         [ #  # ]:          0 :         memset(lw_thread, 0, sizeof(*lw_thread));
     147                 :            : 
     148                 :            :         /* Assign lightweight threads to reactor(core). Here we use a mutex.
     149                 :            :          * The way the actual SPDK event framework solves this is by using
     150                 :            :          * internal rings for messages between reactors. */
     151         [ #  # ]:          0 :         pthread_mutex_lock(&g_mutex);
     152                 :          0 :         reactor = &g_main_reactor;
     153                 :            : 
     154                 :          0 :         spdk_ring_enqueue(reactor->threads, (void **)&lw_thread, 1, NULL);
     155         [ #  # ]:          0 :         pthread_mutex_unlock(&g_mutex);
     156                 :            : 
     157                 :          0 :         return 0;
     158                 :            : }
     159                 :            : 
     160                 :            : static int
     161                 :          0 : reactor_thread_op(struct spdk_thread *thread, enum spdk_thread_op op)
     162                 :            : {
     163         [ #  # ]:          0 :         switch (op) {
     164                 :          0 :         case SPDK_THREAD_OP_NEW:
     165                 :          0 :                 return schedule_spdk_thread(thread);
     166                 :          0 :         default:
     167                 :          0 :                 return -ENOTSUP;
     168                 :            :         }
     169                 :            : }
     170                 :            : 
     171                 :            : static bool
     172                 :          0 : reactor_thread_op_supported(enum spdk_thread_op op)
     173                 :            : {
     174         [ #  # ]:          0 :         switch (op) {
     175                 :          0 :         case SPDK_THREAD_OP_NEW:
     176                 :          0 :                 return true;
     177                 :          0 :         default:
     178                 :          0 :                 return false;
     179                 :            :         }
     180                 :            : }
     181                 :            : 
     182                 :            : static int
     183                 :          0 : init_reactor(void)
     184                 :            : {
     185                 :            :         int rc;
     186                 :          0 :         char thread_name[32];
     187                 :          0 :         struct spdk_cpuset cpumask;
     188                 :          0 :         uint32_t main_core = spdk_env_get_current_core();
     189                 :            : 
     190         [ #  # ]:          0 :         printf("Initializing thread library.\n");
     191                 :            : 
     192                 :            :         /* Whenever SPDK creates a new lightweight thread it will call
     193                 :            :          * schedule_spdk_thread() asking for the application to begin
     194                 :            :          * polling it via spdk_thread_poll(). Each lightweight thread in
     195                 :            :          * SPDK optionally allocates extra memory to be used by the application
     196                 :            :          * framework. The size of the extra memory allocated is the third parameter. */
     197                 :          0 :         spdk_thread_lib_init_ext(reactor_thread_op, reactor_thread_op_supported,
     198                 :            :                                  sizeof(struct lw_thread), SPDK_DEFAULT_MSG_MEMPOOL_SIZE);
     199                 :            : 
     200                 :          0 :         g_main_reactor.core = main_core;
     201                 :            : 
     202                 :          0 :         g_main_reactor.threads = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 1024, SPDK_ENV_SOCKET_ID_ANY);
     203         [ #  # ]:          0 :         if (!g_main_reactor.threads) {
     204   [ #  #  #  # ]:          0 :                 fprintf(stderr, "ERROR: Failed to alloc thread ring!\n");
     205                 :          0 :                 rc = -ENOMEM;
     206                 :          0 :                 goto err_exit;
     207                 :            :         }
     208                 :            : 
     209                 :            :         /* Spawn an spdk_thread thread on the current core to manage this application. */
     210                 :          0 :         spdk_cpuset_zero(&cpumask);
     211                 :          0 :         spdk_cpuset_set_cpu(&cpumask, main_core, true);
     212         [ #  # ]:          0 :         snprintf(thread_name, sizeof(thread_name), "example_main_thread");
     213                 :          0 :         g_init_thread = spdk_thread_create(thread_name, &cpumask);
     214         [ #  # ]:          0 :         if (!g_init_thread) {
     215   [ #  #  #  # ]:          0 :                 fprintf(stderr, "ERROR: Failed to create SPDK thread!\n");
     216                 :          0 :                 return -1;
     217                 :            :         }
     218                 :            : 
     219   [ #  #  #  # ]:          0 :         fprintf(stdout, "SPDK threads initialized successfully.\n");
     220                 :          0 :         return 0;
     221                 :            : 
     222                 :          0 : err_exit:
     223                 :          0 :         return rc;
     224                 :            : }
     225                 :            : 
     226                 :            : static void
     227                 :          0 : destroy_threads(void)
     228                 :            : {
     229                 :          0 :         struct reactor *reactor = &g_main_reactor;
     230                 :            : 
     231                 :          0 :         spdk_ring_free(reactor->threads);
     232                 :            : 
     233         [ #  # ]:          0 :         pthread_mutex_destroy(&g_mutex);
     234                 :          0 :         spdk_thread_lib_fini();
     235         [ #  # ]:          0 :         printf("Threads destroyed successfully\n");
     236                 :          0 : }
     237                 :            : 
     238                 :            : static void
     239                 :          0 : thread_fn(void *ctx)
     240                 :            : {
     241                 :          0 :         struct spdk_thread *thread = ctx;
     242                 :            : 
     243         [ #  # ]:          0 :         printf("Hello from new SPDK thread! Thread name: %s\n", spdk_thread_get_name(thread));
     244                 :          0 : }
     245                 :            : 
     246                 :            : static struct spdk_thread *
     247                 :          0 : register_thread(char *thread_num)
     248                 :            : {
     249                 :          0 :         struct spdk_thread *thread = NULL;
     250                 :          0 :         char thread_name[16] = "example_thread";
     251                 :          0 :         struct spdk_cpuset tmp_cpumask = {};
     252                 :            : 
     253   [ #  #  #  # ]:          0 :         strncat(thread_name, thread_num, 1);
     254                 :            : 
     255         [ #  # ]:          0 :         printf("Initializing new SPDK thread: %s\n", thread_name);
     256                 :            : 
     257                 :          0 :         spdk_cpuset_zero(&tmp_cpumask);
     258                 :          0 :         spdk_cpuset_set_cpu(&tmp_cpumask, spdk_env_get_first_core(), true);
     259                 :            : 
     260                 :          0 :         thread = spdk_thread_create(thread_name, &tmp_cpumask);
     261         [ #  # ]:          0 :         assert(thread != NULL);
     262                 :            : 
     263                 :          0 :         spdk_thread_send_msg(thread, thread_fn, thread);
     264                 :            : 
     265                 :          0 :         return thread;
     266                 :            : }
     267                 :            : 
     268                 :            : static int
     269                 :          0 : create_cb(void *io_device, void *ctx_buf)
     270                 :            : {
     271                 :          0 :         int *ch_count = io_device;
     272                 :            : 
     273                 :          0 :         (*ch_count)++;
     274                 :            : 
     275         [ #  # ]:          0 :         printf("Hello from IO device register callback!\n");
     276                 :            : 
     277                 :          0 :         return 0;
     278                 :            : }
     279                 :            : 
     280                 :            : static void
     281                 :          0 : destroy_cb(void *io_device, void *ctx_buf)
     282                 :            : {
     283                 :          0 :         int *ch_count = io_device;
     284                 :            : 
     285                 :          0 :         (*ch_count)--;
     286                 :            : 
     287         [ #  # ]:          0 :         printf("Hello from IO device destroy callback!\n");
     288                 :          0 : }
     289                 :            : 
     290                 :            : static void
     291                 :          0 : app_thread_register_io_device(void *arg)
     292                 :            : {
     293                 :          0 :         struct spdk_io_channel *ch0 = NULL;
     294                 :            : 
     295         [ #  # ]:          0 :         printf("Registering a new IO device.\n");
     296                 :          0 :         spdk_io_device_register(&g_io_channel_cnt, create_cb, destroy_cb,
     297                 :            :                                 sizeof(int), NULL);
     298                 :            : 
     299                 :            :         /* Get a reference pointer to IO channel. */
     300                 :          0 :         ch0 = spdk_get_io_channel(&g_io_channel_cnt);
     301         [ #  # ]:          0 :         assert(ch0 != NULL);
     302                 :            :         /* Put (away) the reference pointer. */
     303                 :          0 :         spdk_put_io_channel(ch0);
     304                 :          0 : }
     305                 :            : 
     306                 :            : static void
     307                 :          0 : unregister_cb(void *io_device)
     308                 :            : {
     309                 :            :         int *ch_count __attribute__((unused));
     310                 :            : 
     311                 :          0 :         ch_count = io_device;
     312         [ #  # ]:          0 :         assert(*ch_count == 0);
     313                 :            : 
     314         [ #  # ]:          0 :         printf("Hello from IO device unregister callback!\n");
     315                 :          0 : }
     316                 :            : 
     317                 :            : static void
     318                 :          0 : app_thread_unregister_io_device(void *arg)
     319                 :            : {
     320         [ #  # ]:          0 :         printf("Unregistering IO device...\n");
     321                 :            : 
     322                 :          0 :         spdk_io_device_unregister(&g_io_channel_cnt, unregister_cb);
     323                 :          0 : }
     324                 :            : 
     325                 :            : static int
     326                 :          0 : poller_count(void *arg)
     327                 :            : {
     328                 :          0 :         struct poller_ctx *ctx = arg;
     329                 :            :         uint64_t time_diff;
     330                 :            : 
     331         [ #  # ]:          0 :         time_diff = (spdk_get_ticks() - g_time_start) / spdk_get_ticks_hz();
     332                 :            : 
     333                 :          0 :         (*ctx->run_count)++;
     334                 :            : 
     335                 :            :         /* After POLLING_TIME seconds pass, let the poller unregister itself. */
     336         [ #  # ]:          0 :         if (time_diff >= POLLING_TIME) {
     337                 :          0 :                 spdk_poller_unregister(&g_active_poller);
     338                 :            :         }
     339                 :            : 
     340                 :          0 :         return 0;
     341                 :            : }
     342                 :            : 
     343                 :            : static void
     344                 :          0 : thread1_counting_poller(void *arg)
     345                 :            : {
     346                 :          0 :         struct poller_ctx *ctx = arg;
     347                 :            : 
     348         [ #  # ]:          0 :         printf("Registering new active poller...\n");
     349                 :            :         /* Register an ACTIVE poller for this SPDK thread.
     350                 :            :          * Active poller runs continuously, in other words:
     351                 :            :          * it's execution period is set to 0. */
     352                 :          0 :         g_active_poller = SPDK_POLLER_REGISTER(poller_count, ctx, 0);
     353         [ #  # ]:          0 :         assert(g_active_poller != NULL);
     354                 :          0 : }
     355                 :            : 
     356                 :            : static int
     357                 :          0 : poller_print_msg(void *arg)
     358                 :            : {
     359                 :          0 :         struct poller_ctx *ctx = arg;
     360                 :            :         uint64_t time_diff;
     361                 :            : 
     362         [ #  # ]:          0 :         time_diff = (spdk_get_ticks() - g_time_start) / spdk_get_ticks_hz();
     363                 :          0 :         (*ctx->run_count)++;
     364                 :            : 
     365         [ #  # ]:          0 :         printf("Hello from %s poller! Time elapsed: %ld, Current run count: %ld\n", ctx->poller_type,
     366                 :          0 :                time_diff, *ctx->run_count);
     367                 :            : 
     368                 :            :         /* After POLLING_TIME seconds pass, let the poller unregister itself. */
     369         [ #  # ]:          0 :         if (time_diff >= POLLING_TIME) {
     370                 :          0 :                 spdk_poller_unregister(&g_timed_poller);
     371                 :            :         }
     372                 :            : 
     373                 :          0 :         return 0;
     374                 :            : }
     375                 :            : 
     376                 :            : static void
     377                 :          0 : thread2_printing_poller(void *arg)
     378                 :            : {
     379                 :          0 :         struct poller_ctx *ctx = arg;
     380                 :            : 
     381         [ #  # ]:          0 :         printf("Registering new timed poller...\n");
     382                 :            :         /* Timed pollers run every set time period defined in microseconds.
     383                 :            :          * This one is set to execute every "TIMED_POLLER_PERIOD". */
     384                 :          0 :         g_timed_poller = SPDK_POLLER_REGISTER(poller_print_msg, ctx, TIMED_POLLER_PERIOD);
     385         [ #  # ]:          0 :         assert(g_timed_poller != NULL);
     386                 :          0 : }
     387                 :            : 
     388                 :            : static void
     389                 :          0 : thread_msg_fn(void *arg)
     390                 :            : {
     391                 :          0 :         uint64_t *thread_poll_cnt = arg;
     392                 :          0 :         struct spdk_thread *thread = spdk_get_thread();
     393                 :            : 
     394                 :          0 :         (*thread_poll_cnt)++;
     395                 :            : 
     396         [ #  # ]:          0 :         printf("Message received by thread: %s, current thread poll count: %ld\n",
     397                 :            :                spdk_thread_get_name(thread), *thread_poll_cnt);
     398                 :          0 : }
     399                 :            : 
     400                 :            : static void
     401                 :          0 : thread_msg_cpl_fn(void *arg)
     402                 :            : {
     403         [ #  # ]:          0 :         printf("Finished iterating over SPDK threads!\n");
     404                 :          0 : }
     405                 :            : 
     406                 :            : static int
     407                 :          0 : poller_for_each_thread(void *arg)
     408                 :            : {
     409                 :          0 :         struct poller_ctx *ctx = arg;
     410                 :            :         uint64_t time_diff;
     411                 :            : 
     412         [ #  # ]:          0 :         time_diff = (spdk_get_ticks() - g_time_start) / spdk_get_ticks_hz();
     413                 :          0 :         (*ctx->run_count)++;
     414                 :            : 
     415         [ #  # ]:          0 :         printf("Calling all threads from %s poller! Time elapsed: %ld, Current run count: %ld\n",
     416                 :          0 :                ctx->poller_type, time_diff, *ctx->run_count);
     417                 :            : 
     418                 :            :         /* Send a message to each thread. */
     419                 :          0 :         spdk_for_each_thread(thread_msg_fn, &g_thread_poll_cnt, thread_msg_cpl_fn);
     420                 :            : 
     421                 :            :         /* After POLLING_TIME seconds pass, let the poller unregister itself. */
     422         [ #  # ]:          0 :         if (time_diff >= POLLING_TIME) {
     423                 :          0 :                 spdk_poller_unregister(&g_timed_for_each_thread);
     424                 :            :         }
     425                 :            : 
     426                 :          0 :         return 0;
     427                 :            : }
     428                 :            : 
     429                 :            : static void
     430                 :          0 : thread2_for_each_thread_poller(void *arg)
     431                 :            : {
     432                 :          0 :         struct poller_ctx *ctx = arg;
     433                 :            : 
     434         [ #  # ]:          0 :         printf("Registering new timed poller...\n");
     435                 :            :         /* Register a poller to send a message to all available threads via
     436                 :            :          * spdk_for_each_thread(). */
     437                 :          0 :         g_timed_for_each_thread = SPDK_POLLER_REGISTER(poller_for_each_thread, ctx, TIMED_POLLER_PERIOD);
     438         [ #  # ]:          0 :         assert(g_timed_for_each_thread != NULL);
     439                 :          0 : }
     440                 :            : 
     441                 :            : static void
     442                 :          0 : io_device_send_msg_fn(struct spdk_io_channel_iter *i)
     443                 :            : {
     444                 :          0 :         struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
     445                 :          0 :         struct spdk_thread *thread = spdk_io_channel_get_thread(ch);
     446                 :            : 
     447         [ #  # ]:          0 :         printf("Iterating over IO channels. Currently on thread: %s and IO device: %s\n",
     448                 :            :                spdk_thread_get_name(thread), spdk_io_channel_get_io_device_name(ch));
     449                 :          0 :         spdk_for_each_channel_continue(i, 0);
     450                 :          0 : }
     451                 :            : 
     452                 :            : static void
     453                 :          0 : io_device_msg_cpl_fn(struct spdk_io_channel_iter *i, int status)
     454                 :            : {
     455         [ #  # ]:          0 :         printf("Completed iterating over IO channels with status: %d.\n", status);
     456                 :          0 : }
     457                 :            : 
     458                 :            : static int
     459                 :          0 : poller_for_each_channel(void *arg)
     460                 :            : {
     461                 :          0 :         struct poller_ctx *ctx = arg;
     462                 :            :         uint64_t time_diff;
     463                 :            : 
     464         [ #  # ]:          0 :         time_diff = (spdk_get_ticks() - g_time_start) / spdk_get_ticks_hz();
     465                 :          0 :         (*ctx->run_count)++;
     466                 :            : 
     467         [ #  # ]:          0 :         printf("Calling all IO channels from %s poller! Time elapsed: %ld, Current run count: %ld\n",
     468                 :          0 :                ctx->poller_type, time_diff, *ctx->run_count);
     469                 :            : 
     470                 :            :         /* Send a message to all io devices. */
     471                 :          0 :         spdk_for_each_channel(&g_io_channel_cnt, io_device_send_msg_fn, NULL, io_device_msg_cpl_fn);
     472                 :            : 
     473                 :            :         /* After POLLING_TIME seconds pass, let the poller unregister itself. */
     474         [ #  # ]:          0 :         if (time_diff >= POLLING_TIME) {
     475                 :          0 :                 spdk_poller_unregister(&g_timed_for_each_channel);
     476                 :            :         }
     477                 :            : 
     478                 :          0 :         return 0;
     479                 :            : }
     480                 :            : 
     481                 :            : static void
     482                 :          0 : thread2_for_each_channel_poller(void *arg)
     483                 :            : {
     484                 :          0 :         struct poller_ctx *ctx = arg;
     485                 :            : 
     486         [ #  # ]:          0 :         printf("Registering new timed poller...\n");
     487                 :            :         /* Register a poller to send a message to all available IO channels via
     488                 :            :          * spdk_for_each_channel(). */
     489                 :          0 :         g_timed_for_each_channel = SPDK_POLLER_REGISTER(poller_for_each_channel, ctx, TIMED_POLLER_PERIOD);
     490         [ #  # ]:          0 :         assert(g_timed_for_each_channel != NULL);
     491                 :          0 : }
     492                 :            : 
     493                 :            : int
     494                 :          0 : main(int argc, char **argv)
     495                 :            : {
     496                 :            :         int rc;
     497                 :          0 :         struct spdk_env_opts opts;
     498                 :            :         struct spdk_thread *example_thread1, *example_thread2;
     499                 :          0 :         uint64_t time_diff = 0;
     500                 :          0 :         struct poller_ctx ctx_counting, ctx_printing, ctx_for_each_thread, ctx_for_each_channel;
     501                 :            : 
     502                 :          0 :         spdk_env_opts_init(&opts);
     503                 :          0 :         opts.name = "thread-example";
     504                 :          0 :         opts.core_mask = "0x1";
     505                 :            : 
     506                 :          0 :         rc = parse_args(argc, argv, &opts);
     507         [ #  # ]:          0 :         if (rc != 0) {
     508   [ #  #  #  # ]:          0 :                 fprintf(stderr, "ERROR: Unable to parse program args! Code: %d\n", rc);
     509                 :          0 :                 return rc;
     510                 :            :         }
     511                 :            : 
     512         [ #  # ]:          0 :         if (spdk_env_init(&opts) < 0) {
     513   [ #  #  #  # ]:          0 :                 fprintf(stderr, "ERROR: Unable to initialize SPDK env!\n");
     514                 :          0 :                 return -EINVAL;
     515                 :            :         }
     516                 :            : 
     517                 :            :         /* Initialize a reactor and an SPDK thread to manage the application. */
     518                 :          0 :         rc = init_reactor();
     519         [ #  # ]:          0 :         if (rc != 0) {
     520   [ #  #  #  # ]:          0 :                 fprintf(stderr, "ERROR: Unable to initialize reactor! Code: %d\n", rc);
     521                 :          0 :                 return rc;
     522                 :            :         }
     523                 :            : 
     524                 :            :         /* Get a time reference to print elapsed time in poller functions. */
     525                 :          0 :         g_time_start = spdk_get_ticks();
     526                 :            : 
     527                 :            :         /* Register a mock IO device on app_thread (main application thread). */
     528                 :          0 :         spdk_thread_send_msg(spdk_thread_get_app_thread(), app_thread_register_io_device, NULL);
     529                 :            : 
     530                 :            :         /* Register two new SPDK threads. */
     531                 :          0 :         example_thread1 = register_thread("1");
     532                 :          0 :         example_thread2 = register_thread("2");
     533                 :            : 
     534                 :            :         /* Signal the first thread to register and execute an ACTIVE poller, which will run as often as possible. */
     535                 :          0 :         ctx_counting.poller_type = POLLER_TYPE_ACTIVE;
     536                 :          0 :         ctx_counting.run_count = &g_counting_poller_counter;
     537                 :          0 :         spdk_thread_send_msg(example_thread1, thread1_counting_poller, &ctx_counting);
     538                 :            : 
     539                 :            :         /* Signal the second thread to register and execute TIMED pollers, which will run periodically. */
     540                 :          0 :         ctx_printing.poller_type = POLLER_TYPE_TIMED;
     541                 :          0 :         ctx_printing.run_count = &g_printing_poller_counter;
     542                 :          0 :         spdk_thread_send_msg(example_thread2, thread2_printing_poller, &ctx_printing);
     543                 :            : 
     544                 :          0 :         ctx_for_each_thread.poller_type = POLLER_TYPE_TIMED;
     545                 :          0 :         ctx_for_each_thread.run_count = &g_for_each_thread_poller_counter;
     546                 :          0 :         spdk_thread_send_msg(example_thread2, thread2_for_each_thread_poller, &ctx_for_each_thread);
     547                 :            : 
     548                 :          0 :         ctx_for_each_channel.poller_type = POLLER_TYPE_TIMED;
     549                 :          0 :         ctx_for_each_channel.run_count = &g_for_each_channel_poller_counter;
     550                 :          0 :         spdk_thread_send_msg(example_thread2, thread2_for_each_channel_poller, &ctx_for_each_channel);
     551                 :            : 
     552                 :            :         /* Poll SPDK threads and IO devices for POLLING_TIME + 1 seconds - to avoid a race
     553                 :            :          * between all the pollers and IO device unregistering, let below while loop
     554                 :            :          * poll for one second longer than all the pollers.  */
     555         [ #  # ]:          0 :         while (time_diff < POLLING_TIME + 1) {
     556         [ #  # ]:          0 :                 time_diff = (spdk_get_ticks() - g_time_start) / spdk_get_ticks_hz();
     557                 :          0 :                 reactor_run();
     558                 :            :         }
     559                 :            : 
     560         [ #  # ]:          0 :         printf("ACTIVE (counting) poller ran %lu times.\n", g_counting_poller_counter);
     561         [ #  # ]:          0 :         printf("TIMED (printing) poller ran %lu times.\n", g_printing_poller_counter);
     562         [ #  # ]:          0 :         printf("TIMED (for each thread) poller ran %lu times.\n", g_for_each_thread_poller_counter);
     563         [ #  # ]:          0 :         printf("TIMED (for each channel) poller ran %lu times.\n", g_for_each_channel_poller_counter);
     564                 :            : 
     565                 :            :         /* Unregister the mock IO device. */
     566                 :          0 :         spdk_thread_send_msg(spdk_thread_get_app_thread(), app_thread_unregister_io_device, NULL);
     567                 :            : 
     568                 :            :         /* Disable the reactor and free all SPDK threads. */
     569                 :          0 :         reactor_run_fini();
     570                 :          0 :         destroy_threads();
     571                 :            : 
     572                 :            :         /* Stop SPDK environment. */
     573                 :          0 :         spdk_env_fini();
     574                 :            : 
     575                 :          0 :         return 0;
     576                 :            : }

Generated by: LCOV version 1.14