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 spdk_add_subsystem(struct spdk_subsystem *subsystem) 36 { 37 TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq); 38 } 39 40 void 41 spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend) 42 { 43 TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq); 44 } 45 46 static struct spdk_subsystem * 47 _subsystem_find(struct spdk_subsystem_list *list, const char *name) 48 { 49 struct spdk_subsystem *iter; 50 51 TAILQ_FOREACH(iter, list, tailq) { 52 if (strcmp(name, iter->name) == 0) { 53 return iter; 54 } 55 } 56 57 return NULL; 58 } 59 60 struct spdk_subsystem * 61 subsystem_find(const char *name) 62 { 63 return _subsystem_find(&g_subsystems, name); 64 } 65 66 struct spdk_subsystem * 67 subsystem_get_first(void) 68 { 69 return TAILQ_FIRST(&g_subsystems); 70 } 71 72 struct spdk_subsystem * 73 subsystem_get_next(struct spdk_subsystem *cur_subsystem) 74 { 75 return TAILQ_NEXT(cur_subsystem, tailq); 76 } 77 78 79 struct spdk_subsystem_depend * 80 subsystem_get_first_depend(void) 81 { 82 return TAILQ_FIRST(&g_subsystems_deps); 83 } 84 85 struct spdk_subsystem_depend * 86 subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend) 87 { 88 return TAILQ_NEXT(cur_depend, tailq); 89 } 90 91 static void 92 subsystem_sort(void) 93 { 94 bool depends_on, depends_on_sorted; 95 struct spdk_subsystem *subsystem, *subsystem_tmp; 96 struct spdk_subsystem_depend *subsystem_dep; 97 98 struct spdk_subsystem_list subsystems_list = TAILQ_HEAD_INITIALIZER(subsystems_list); 99 100 while (!TAILQ_EMPTY(&g_subsystems)) { 101 TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) { 102 depends_on = false; 103 TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) { 104 if (strcmp(subsystem->name, subsystem_dep->name) == 0) { 105 depends_on = true; 106 depends_on_sorted = !!_subsystem_find(&subsystems_list, subsystem_dep->depends_on); 107 if (depends_on_sorted) { 108 continue; 109 } 110 break; 111 } 112 } 113 114 if (!depends_on || depends_on_sorted) { 115 TAILQ_REMOVE(&g_subsystems, subsystem, tailq); 116 TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq); 117 } 118 } 119 } 120 121 TAILQ_FOREACH_SAFE(subsystem, &subsystems_list, tailq, subsystem_tmp) { 122 TAILQ_REMOVE(&subsystems_list, subsystem, tailq); 123 TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq); 124 } 125 } 126 127 void 128 spdk_subsystem_init_next(int rc) 129 { 130 assert(spdk_get_thread() == spdk_thread_get_app_thread()); 131 132 /* The initialization is interrupted by the spdk_subsystem_fini, so just return */ 133 if (g_subsystems_init_interrupted) { 134 return; 135 } 136 137 if (rc) { 138 SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name); 139 g_subsystem_start_fn(rc, g_subsystem_start_arg); 140 return; 141 } 142 143 if (!g_next_subsystem) { 144 g_next_subsystem = TAILQ_FIRST(&g_subsystems); 145 } else { 146 g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq); 147 } 148 149 if (!g_next_subsystem) { 150 g_subsystems_initialized = true; 151 g_subsystem_start_fn(0, g_subsystem_start_arg); 152 return; 153 } 154 155 if (g_next_subsystem->init) { 156 g_next_subsystem->init(); 157 } else { 158 spdk_subsystem_init_next(0); 159 } 160 } 161 162 void 163 spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg) 164 { 165 struct spdk_subsystem_depend *dep; 166 167 assert(spdk_get_thread() == spdk_thread_get_app_thread()); 168 169 g_subsystem_start_fn = cb_fn; 170 g_subsystem_start_arg = cb_arg; 171 172 /* Verify that all dependency name and depends_on subsystems are registered */ 173 TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) { 174 if (!subsystem_find(dep->name)) { 175 SPDK_ERRLOG("subsystem %s is missing\n", dep->name); 176 g_subsystem_start_fn(-1, g_subsystem_start_arg); 177 return; 178 } 179 if (!subsystem_find(dep->depends_on)) { 180 SPDK_ERRLOG("subsystem %s dependency %s is missing\n", 181 dep->name, dep->depends_on); 182 g_subsystem_start_fn(-1, g_subsystem_start_arg); 183 return; 184 } 185 } 186 187 subsystem_sort(); 188 189 spdk_subsystem_init_next(0); 190 } 191 192 static void 193 subsystem_fini_next(void *arg1) 194 { 195 assert(g_fini_thread == spdk_get_thread()); 196 197 if (!g_next_subsystem) { 198 /* If the initialized flag is false, then we've failed to initialize 199 * the very first subsystem and no de-init is needed 200 */ 201 if (g_subsystems_initialized) { 202 g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list); 203 } 204 } else { 205 if (g_subsystems_initialized || g_subsystems_init_interrupted) { 206 g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq); 207 } else { 208 g_subsystems_init_interrupted = true; 209 } 210 } 211 212 while (g_next_subsystem) { 213 if (g_next_subsystem->fini) { 214 g_next_subsystem->fini(); 215 return; 216 } 217 g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq); 218 } 219 220 g_subsystem_stop_fn(g_subsystem_stop_arg); 221 return; 222 } 223 224 void 225 spdk_subsystem_fini_next(void) 226 { 227 if (g_fini_thread != spdk_get_thread()) { 228 spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL); 229 } else { 230 subsystem_fini_next(NULL); 231 } 232 } 233 234 void 235 spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg) 236 { 237 g_subsystem_stop_fn = cb_fn; 238 g_subsystem_stop_arg = cb_arg; 239 240 g_fini_thread = spdk_get_thread(); 241 242 spdk_subsystem_fini_next(); 243 } 244 245 void 246 subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem) 247 { 248 if (subsystem && subsystem->write_config_json) { 249 subsystem->write_config_json(w); 250 } else { 251 spdk_json_write_null(w); 252 } 253 } 254