LCOV - code coverage report
Current view: top level - lib/init - subsystem.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 59 103 57.3 %
Date: 2024-07-15 06:45:20 Functions: 7 15 46.7 %

          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             : 
       8             : #include "spdk/init.h"
       9             : #include "spdk/log.h"
      10             : #include "spdk/queue.h"
      11             : #include "spdk/thread.h"
      12             : 
      13             : #include "spdk_internal/init.h"
      14             : #include "spdk/env.h"
      15             : 
      16             : #include "spdk/json.h"
      17             : 
      18             : #include "subsystem.h"
      19             : 
      20             : TAILQ_HEAD(spdk_subsystem_list, spdk_subsystem);
      21             : struct spdk_subsystem_list g_subsystems = TAILQ_HEAD_INITIALIZER(g_subsystems);
      22             : 
      23             : TAILQ_HEAD(spdk_subsystem_depend_list, spdk_subsystem_depend);
      24             : struct spdk_subsystem_depend_list g_subsystems_deps = TAILQ_HEAD_INITIALIZER(g_subsystems_deps);
      25             : static struct spdk_subsystem *g_next_subsystem;
      26             : static bool g_subsystems_initialized = false;
      27             : static bool g_subsystems_init_interrupted = false;
      28             : static spdk_subsystem_init_fn g_subsystem_start_fn = NULL;
      29             : static void *g_subsystem_start_arg = NULL;
      30             : static spdk_msg_fn g_subsystem_stop_fn = NULL;
      31             : static void *g_subsystem_stop_arg = NULL;
      32             : static struct spdk_thread *g_fini_thread = NULL;
      33             : 
      34             : void
      35          14 : spdk_add_subsystem(struct spdk_subsystem *subsystem)
      36             : {
      37          14 :         TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
      38          14 : }
      39             : 
      40             : void
      41          13 : spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
      42             : {
      43          13 :         TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq);
      44          13 : }
      45             : 
      46             : static struct spdk_subsystem *
      47          49 : _subsystem_find(struct spdk_subsystem_list *list, const char *name)
      48             : {
      49             :         struct spdk_subsystem *iter;
      50             : 
      51         142 :         TAILQ_FOREACH(iter, list, tailq) {
      52         127 :                 if (strcmp(name, iter->name) == 0) {
      53          34 :                         return iter;
      54             :                 }
      55             :         }
      56             : 
      57          15 :         return NULL;
      58             : }
      59             : 
      60             : struct spdk_subsystem *
      61          25 : subsystem_find(const char *name)
      62             : {
      63          25 :         return _subsystem_find(&g_subsystems, name);
      64             : }
      65             : 
      66             : struct spdk_subsystem *
      67           0 : subsystem_get_first(void)
      68             : {
      69           0 :         return TAILQ_FIRST(&g_subsystems);
      70             : }
      71             : 
      72             : struct spdk_subsystem *
      73           0 : subsystem_get_next(struct spdk_subsystem *cur_subsystem)
      74             : {
      75           0 :         return TAILQ_NEXT(cur_subsystem, tailq);
      76             : }
      77             : 
      78             : 
      79             : struct spdk_subsystem_depend *
      80           0 : subsystem_get_first_depend(void)
      81             : {
      82           0 :         return TAILQ_FIRST(&g_subsystems_deps);
      83             : }
      84             : 
      85             : struct spdk_subsystem_depend *
      86           0 : subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
      87             : {
      88           0 :         return TAILQ_NEXT(cur_depend, tailq);
      89             : }
      90             : 
      91             : static void
      92           2 : subsystem_sort(void)
      93             : {
      94             :         bool has_dependency, all_dependencies_met;
      95             :         struct spdk_subsystem *subsystem, *subsystem_tmp;
      96             :         struct spdk_subsystem_depend *subsystem_dep;
      97           2 :         struct spdk_subsystem_list sorted_list;
      98             : 
      99           2 :         TAILQ_INIT(&sorted_list);
     100             :         /* We will move subsystems from the original g_subsystems TAILQ to the temporary
     101             :          * sorted_list one at a time. We can only move a subsystem if it either (a) has no
     102             :          * dependencies, or (b) all of its dependencies have already been moved to the
     103             :          * sorted_list.
     104             :          *
     105             :          * Once all of the subsystems have been moved to the temporary list, we will move
     106             :          * the list as-is back to the original g_subsystems TAILQ - they will now be sorted
     107             :          * in the order which they must be initialized.
     108             :          */
     109           9 :         while (!TAILQ_EMPTY(&g_subsystems)) {
     110          32 :                 TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
     111          25 :                         has_dependency = false;
     112          25 :                         all_dependencies_met = true;
     113         125 :                         TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
     114         113 :                                 if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
     115          24 :                                         has_dependency = true;
     116          24 :                                         if (!_subsystem_find(&sorted_list, subsystem_dep->depends_on)) {
     117             :                                                 /* We found a dependency that isn't in the sorted_list yet.
     118             :                                                  * Clear the flag and break from the inner loop, we know
     119             :                                                  * we can't move this subsystem to the sorted_list yet.
     120             :                                                  */
     121          13 :                                                 all_dependencies_met = false;
     122          13 :                                                 break;
     123             :                                         }
     124             :                                 }
     125             :                         }
     126             : 
     127          25 :                         if (!has_dependency || all_dependencies_met) {
     128          12 :                                 TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
     129          12 :                                 TAILQ_INSERT_TAIL(&sorted_list, subsystem, tailq);
     130             :                         }
     131             :                 }
     132             :         }
     133             : 
     134           2 :         TAILQ_SWAP(&sorted_list, &g_subsystems, spdk_subsystem, tailq);
     135           2 : }
     136             : 
     137             : void
     138          14 : spdk_subsystem_init_next(int rc)
     139             : {
     140          14 :         assert(spdk_thread_is_app_thread(NULL));
     141             : 
     142             :         /* The initialization is interrupted by the spdk_subsystem_fini, so just return */
     143          14 :         if (g_subsystems_init_interrupted) {
     144           0 :                 return;
     145             :         }
     146             : 
     147          14 :         if (rc) {
     148           0 :                 SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name);
     149           0 :                 g_subsystem_start_fn(rc, g_subsystem_start_arg);
     150           0 :                 return;
     151             :         }
     152             : 
     153          14 :         if (!g_next_subsystem) {
     154           2 :                 g_next_subsystem = TAILQ_FIRST(&g_subsystems);
     155             :         } else {
     156          12 :                 g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
     157             :         }
     158             : 
     159          14 :         if (!g_next_subsystem) {
     160           2 :                 g_subsystems_initialized = true;
     161           2 :                 g_subsystem_start_fn(0, g_subsystem_start_arg);
     162           2 :                 return;
     163             :         }
     164             : 
     165          12 :         if (g_next_subsystem->init) {
     166           0 :                 g_next_subsystem->init();
     167             :         } else {
     168          12 :                 spdk_subsystem_init_next(0);
     169             :         }
     170             : }
     171             : 
     172             : void
     173           4 : spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
     174             : {
     175             :         struct spdk_subsystem_depend *dep;
     176             : 
     177           4 :         assert(spdk_thread_is_app_thread(NULL));
     178             : 
     179           4 :         g_subsystem_start_fn = cb_fn;
     180           4 :         g_subsystem_start_arg = cb_arg;
     181             : 
     182             :         /* Verify that all dependency name and depends_on subsystems are registered */
     183          15 :         TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
     184          13 :                 if (!subsystem_find(dep->name)) {
     185           1 :                         SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
     186           1 :                         g_subsystem_start_fn(-1, g_subsystem_start_arg);
     187           1 :                         return;
     188             :                 }
     189          12 :                 if (!subsystem_find(dep->depends_on)) {
     190           1 :                         SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
     191             :                                     dep->name, dep->depends_on);
     192           1 :                         g_subsystem_start_fn(-1, g_subsystem_start_arg);
     193           1 :                         return;
     194             :                 }
     195             :         }
     196             : 
     197           2 :         subsystem_sort();
     198             : 
     199           2 :         spdk_subsystem_init_next(0);
     200             : }
     201             : 
     202             : static void
     203           0 : subsystem_fini_next(void *arg1)
     204             : {
     205           0 :         assert(g_fini_thread == spdk_get_thread());
     206             : 
     207           0 :         if (!g_next_subsystem) {
     208             :                 /* If the initialized flag is false, then we've failed to initialize
     209             :                  * the very first subsystem and no de-init is needed
     210             :                  */
     211           0 :                 if (g_subsystems_initialized) {
     212           0 :                         g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
     213             :                 }
     214             :         } else {
     215           0 :                 if (g_subsystems_initialized || g_subsystems_init_interrupted) {
     216           0 :                         g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
     217             :                 } else {
     218           0 :                         g_subsystems_init_interrupted = true;
     219             :                 }
     220             :         }
     221             : 
     222           0 :         while (g_next_subsystem) {
     223           0 :                 if (g_next_subsystem->fini) {
     224           0 :                         g_next_subsystem->fini();
     225           0 :                         return;
     226             :                 }
     227           0 :                 g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
     228             :         }
     229             : 
     230           0 :         g_subsystem_stop_fn(g_subsystem_stop_arg);
     231           0 :         return;
     232             : }
     233             : 
     234             : void
     235           0 : spdk_subsystem_fini_next(void)
     236             : {
     237           0 :         if (g_fini_thread != spdk_get_thread()) {
     238           0 :                 spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
     239             :         } else {
     240           0 :                 subsystem_fini_next(NULL);
     241             :         }
     242           0 : }
     243             : 
     244             : void
     245           0 : spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
     246             : {
     247           0 :         g_subsystem_stop_fn = cb_fn;
     248           0 :         g_subsystem_stop_arg = cb_arg;
     249             : 
     250           0 :         g_fini_thread = spdk_get_thread();
     251             : 
     252           0 :         spdk_subsystem_fini_next();
     253           0 : }
     254             : 
     255             : void
     256           0 : subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
     257             : {
     258           0 :         if (subsystem && subsystem->write_config_json) {
     259           0 :                 subsystem->write_config_json(w);
     260             :         } else {
     261           0 :                 spdk_json_write_null(w);
     262             :         }
     263           0 : }

Generated by: LCOV version 1.15