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 == false) { 115 TAILQ_REMOVE(&g_subsystems, subsystem, tailq); 116 TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq); 117 } else { 118 if (depends_on_sorted == true) { 119 TAILQ_REMOVE(&g_subsystems, subsystem, tailq); 120 TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq); 121 } 122 } 123 } 124 } 125 126 TAILQ_FOREACH_SAFE(subsystem, &subsystems_list, tailq, subsystem_tmp) { 127 TAILQ_REMOVE(&subsystems_list, subsystem, tailq); 128 TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq); 129 } 130 } 131 132 void 133 spdk_subsystem_init_next(int rc) 134 { 135 assert(spdk_get_thread() == spdk_thread_get_app_thread()); 136 137 /* The initialization is interrupted by the spdk_subsystem_fini, so just return */ 138 if (g_subsystems_init_interrupted) { 139 return; 140 } 141 142 if (rc) { 143 SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name); 144 g_subsystem_start_fn(rc, g_subsystem_start_arg); 145 return; 146 } 147 148 if (!g_next_subsystem) { 149 g_next_subsystem = TAILQ_FIRST(&g_subsystems); 150 } else { 151 g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq); 152 } 153 154 if (!g_next_subsystem) { 155 g_subsystems_initialized = true; 156 g_subsystem_start_fn(0, g_subsystem_start_arg); 157 return; 158 } 159 160 if (g_next_subsystem->init) { 161 g_next_subsystem->init(); 162 } else { 163 spdk_subsystem_init_next(0); 164 } 165 } 166 167 void 168 spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg) 169 { 170 struct spdk_subsystem_depend *dep; 171 172 assert(spdk_get_thread() == spdk_thread_get_app_thread()); 173 174 g_subsystem_start_fn = cb_fn; 175 g_subsystem_start_arg = cb_arg; 176 177 /* Verify that all dependency name and depends_on subsystems are registered */ 178 TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) { 179 if (!subsystem_find(dep->name)) { 180 SPDK_ERRLOG("subsystem %s is missing\n", dep->name); 181 g_subsystem_start_fn(-1, g_subsystem_start_arg); 182 return; 183 } 184 if (!subsystem_find(dep->depends_on)) { 185 SPDK_ERRLOG("subsystem %s dependency %s is missing\n", 186 dep->name, dep->depends_on); 187 g_subsystem_start_fn(-1, g_subsystem_start_arg); 188 return; 189 } 190 } 191 192 subsystem_sort(); 193 194 spdk_subsystem_init_next(0); 195 } 196 197 static void 198 subsystem_fini_next(void *arg1) 199 { 200 assert(g_fini_thread == spdk_get_thread()); 201 202 if (!g_next_subsystem) { 203 /* If the initialized flag is false, then we've failed to initialize 204 * the very first subsystem and no de-init is needed 205 */ 206 if (g_subsystems_initialized) { 207 g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list); 208 } 209 } else { 210 if (g_subsystems_initialized || g_subsystems_init_interrupted) { 211 g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq); 212 } else { 213 g_subsystems_init_interrupted = true; 214 } 215 } 216 217 while (g_next_subsystem) { 218 if (g_next_subsystem->fini) { 219 g_next_subsystem->fini(); 220 return; 221 } 222 g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq); 223 } 224 225 g_subsystem_stop_fn(g_subsystem_stop_arg); 226 return; 227 } 228 229 void 230 spdk_subsystem_fini_next(void) 231 { 232 if (g_fini_thread != spdk_get_thread()) { 233 spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL); 234 } else { 235 subsystem_fini_next(NULL); 236 } 237 } 238 239 void 240 spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg) 241 { 242 g_subsystem_stop_fn = cb_fn; 243 g_subsystem_stop_arg = cb_arg; 244 245 g_fini_thread = spdk_get_thread(); 246 247 spdk_subsystem_fini_next(); 248 } 249 250 void 251 subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem) 252 { 253 if (subsystem && subsystem->write_config_json) { 254 subsystem->write_config_json(w); 255 } else { 256 spdk_json_write_null(w); 257 } 258 } 259