LCOV - code coverage report
Current view: top level - lib/init - subsystem.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 68 121 56.2 %
Date: 2024-12-14 20:55:10 Functions: 7 16 43.8 %

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

Generated by: LCOV version 1.15